From 24242507af61b906a58b9f5cc97fe12b65467b22 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 11 Dec 2025 23:12:35 +0000 Subject: [PATCH] Refactor classify-issue-severity workflow to use create-task-action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies the workflow by using the create-task-action pattern instead of the previous claude-code-action with JSON parsing. Key changes: - Uses create-task-action to create a Coder Task for severity classification - Removes complex JSON output parsing and validation steps - Simplifies from 2 jobs to 1 job - Adds workflow_dispatch trigger for manual execution - Task automatically posts comments using GitHub MCP tools The same severity classification logic and prompts are preserved, but now executed through a Coder Task which provides better reliability and follows the established pattern from doc-check.yaml. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .github/workflows/classify-issue-severity.yml | 439 ++++++++---------- 1 file changed, 194 insertions(+), 245 deletions(-) diff --git a/.github/workflows/classify-issue-severity.yml b/.github/workflows/classify-issue-severity.yml index 820021dd6edd0..93f75780d058b 100644 --- a/.github/workflows/classify-issue-severity.yml +++ b/.github/workflows/classify-issue-severity.yml @@ -1,4 +1,4 @@ -# WIP: This workflow assists in evaluating the severity of incoming issues to help +# This workflow assists in evaluating the severity of incoming issues to help # with triaging tickets. It uses AI analysis to classify issues into severity levels # (s0-s4) when the 'triage-check' label is applied. @@ -7,303 +7,252 @@ name: Classify Issue Severity on: issues: types: [labeled] - -permissions: - contents: read - id-token: write # zizmor: ignore[excessive-permissions] - Required by claude-code-action for OIDC auth + workflow_dispatch: + inputs: + issue_url: + description: "Issue URL to classify" + required: true + type: string + template_preset: + description: "Template preset to use" + required: false + default: "" + type: string jobs: - analyze: - name: AI Analysis - if: github.event.label.name == 'triage-check' + classify-severity: + name: AI Severity Classification runs-on: ubuntu-latest - outputs: - result: ${{ steps.extract.outputs.result }} + if: | + (github.event.label.name == 'triage-check' || github.event_name == 'workflow_dispatch') + timeout-minutes: 30 + env: + CODER_URL: ${{ secrets.DOC_CHECK_CODER_URL }} + CODER_SESSION_TOKEN: ${{ secrets.DOC_CHECK_CODER_SESSION_TOKEN }} + permissions: + contents: read + issues: write + actions: write steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Analyze Issue Severity - id: analysis - uses: anthropics/claude-code-action@f0c8eb29807907de7f5412d04afceb5e24817127 # v1.0.23 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - claude_args: | - --json-schema '{"type":"object","properties":{"status":{"type":"string"},"severity":{"type":"string"},"reasoning":{"type":"string"},"next_steps":{"type":"array","items":{"type":"string"}}},"required":["status","reasoning"]}' - prompt: | - You are an expert software engineer triaging customer-reported issues for Coder, a cloud development environment platform. + - name: Determine Issue Context + id: determine-context + env: + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_EVENT_NAME: ${{ github.event_name }} + GITHUB_EVENT_ISSUE_HTML_URL: ${{ github.event.issue.html_url }} + GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} + GITHUB_EVENT_SENDER_ID: ${{ github.event.sender.id }} + GITHUB_EVENT_SENDER_LOGIN: ${{ github.event.sender.login }} + INPUTS_ISSUE_URL: ${{ inputs.issue_url }} + INPUTS_TEMPLATE_PRESET: ${{ inputs.template_preset || '' }} + GH_TOKEN: ${{ github.token }} + run: | + echo "Using template preset: ${INPUTS_TEMPLATE_PRESET}" + echo "template_preset=${INPUTS_TEMPLATE_PRESET}" >> "${GITHUB_OUTPUT}" - Your task is to carefully analyze the issue and classify it into one of the following severity levels. **This requires deep reasoning and thoughtful analysis** - not just keyword matching. + # For workflow_dispatch, use the provided issue URL + if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then + if ! GITHUB_USER_ID=$(gh api "users/${GITHUB_ACTOR}" --jq '.id'); then + echo "::error::Failed to get GitHub user ID for actor ${GITHUB_ACTOR}" + exit 1 + fi + echo "Using workflow_dispatch actor: ${GITHUB_ACTOR} (ID: ${GITHUB_USER_ID})" + echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}" + echo "github_username=${GITHUB_ACTOR}" >> "${GITHUB_OUTPUT}" - ## Issue Details + echo "Using issue URL: ${INPUTS_ISSUE_URL}" + echo "issue_url=${INPUTS_ISSUE_URL}" >> "${GITHUB_OUTPUT}" - Issue Number: ${{ github.event.issue.number }} + # Extract issue number from URL for later use + ISSUE_NUMBER=$(echo "${INPUTS_ISSUE_URL}" | grep -oP '(?<=issues/)\d+') + echo "issue_number=${ISSUE_NUMBER}" >> "${GITHUB_OUTPUT}" - Issue Content: - ``` - Title: ${{ github.event.issue.title }} + elif [[ "${GITHUB_EVENT_NAME}" == "issues" ]]; then + GITHUB_USER_ID=${GITHUB_EVENT_SENDER_ID} + echo "Using label adder: ${GITHUB_EVENT_SENDER_LOGIN} (ID: ${GITHUB_USER_ID})" + echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}" + echo "github_username=${GITHUB_EVENT_SENDER_LOGIN}" >> "${GITHUB_OUTPUT}" - Description: - ${{ github.event.issue.body }} - ``` + echo "Using issue URL: ${GITHUB_EVENT_ISSUE_HTML_URL}" + echo "issue_url=${GITHUB_EVENT_ISSUE_HTML_URL}" >> "${GITHUB_OUTPUT}" + echo "issue_number=${GITHUB_EVENT_ISSUE_NUMBER}" >> "${GITHUB_OUTPUT}" - ## Severity Level Definitions + else + echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}" + exit 1 + fi - - **s0**: Entire product and/or major feature (Tasks, Bridge, Boundaries, etc.) is broken in a way that makes it unusable for majority to all customers + - name: Build Classification Prompt + id: build-prompt + env: + ISSUE_URL: ${{ steps.determine-context.outputs.issue_url }} + ISSUE_NUMBER: ${{ steps.determine-context.outputs.issue_number }} + GH_TOKEN: ${{ github.token }} + run: | + echo "Analyzing issue #${ISSUE_NUMBER}" - - **s1**: Core feature is broken without a workaround for limited number of customers + # Build task prompt - using unquoted heredoc so variables expand + TASK_PROMPT=$(cat < /dev/null 2>&1; then - echo "❌ Result is not valid JSON: $RESULT" - exit 1 - fi + ## 🤖 Automated Severity Classification - { - echo "result<> "$GITHUB_OUTPUT" - - post-comment: - name: Post Classification Comment - needs: analyze - runs-on: ubuntu-latest - if: always() && needs.analyze.result != 'skipped' - permissions: - issues: write - contents: read + **Recommended Severity:** \`S0\` | \`S1\` | \`S2\` | \`S3\` | \`S4\` - steps: - - name: Parse and Validate Analysis - id: parse - env: - RESULT: ${{ needs.analyze.outputs.result }} - run: | - # Parse the JSON output from claude-code-action - echo "Raw result: $RESULT" + **Analysis:** + [2-3 sentences explaining your reasoning - focus on the actual impact, not just symptoms. Explain why you chose this severity level over others.] - # Extract JSON from the result - JSON=$(echo "$RESULT" | jq -r '.') + --- + *This classification was performed by AI analysis. Please review and adjust if needed.* - # Check if parsing succeeded - if ! echo "$JSON" | jq -e . > /dev/null 2>&1; then - echo "Failed to parse JSON" - exit 1 - fi + ### Format 2: Insufficient Information - # Get status - STATUS=$(echo "$JSON" | jq -r '.status // empty') + ## 🤖 Automated Severity Classification - if [ "$STATUS" = "classified" ]; then - # Validate severity is one of the allowed values - SEVERITY=$(echo "$JSON" | jq -r '.severity // empty') - if ! echo "$SEVERITY" | grep -Eq '^s[0-4]$'; then - echo "Invalid severity: $SEVERITY" - exit 1 - fi + **Status:** Unable to classify - insufficient information - REASONING=$(echo "$JSON" | jq -r '.reasoning // empty') - - # Set outputs - { - echo "status=classified" - echo "severity=$SEVERITY" - echo "reasoning<> "$GITHUB_OUTPUT" - - elif [ "$STATUS" = "insufficient_info" ]; then - REASONING=$(echo "$JSON" | jq -r '.reasoning // empty') - NEXT_STEPS=$(echo "$JSON" | jq -r '.next_steps | join("\n- ")' | sed 's/^/- /') - - # Set outputs - { - echo "status=insufficient_info" - echo "reasoning<> "$GITHUB_OUTPUT" - else - echo "Unknown status: $STATUS" - exit 1 - fi + **Reasoning:** + [2-3 sentences explaining what critical information is missing and why it's needed to determine severity.] - - name: Post Classification Comment - if: steps.parse.outputs.status == 'classified' - env: - GH_TOKEN: ${{ github.token }} - SEVERITY: ${{ steps.parse.outputs.severity }} - REASONING: ${{ steps.parse.outputs.reasoning }} - run: | - SEVERITY_UPPER=$(echo "$SEVERITY" | tr '[:lower:]' '[:upper:]') + **Suggested next steps:** + - [Specific information point 1] + - [Specific information point 2] + - [Specific information point 3] - gh issue comment "${{ github.event.issue.number }}" \ - --repo "${{ github.repository }}" \ - --body "## 🤖 Automated Severity Classification + --- + *This classification was performed by AI analysis. Please provide the requested information for proper severity assessment.* - **Recommended Severity:** \`${SEVERITY_UPPER}\` + EOF + ) - **Analysis:** - ${REASONING} + # Output the prompt + { + echo "task_prompt<> "${GITHUB_OUTPUT}" - --- - *This classification was performed by AI analysis. Please review and adjust if needed.*" + - name: Checkout create-task-action + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + with: + fetch-depth: 1 + path: ./.github/actions/create-task-action + persist-credentials: false + ref: main + repository: coder/create-task-action - - name: Post Insufficient Information Comment - if: steps.parse.outputs.status == 'insufficient_info' + - name: Create Coder Task for Severity Classification + id: create_task + uses: ./.github/actions/create-task-action + with: + coder-url: ${{ secrets.DOC_CHECK_CODER_URL }} + coder-token: ${{ secrets.DOC_CHECK_CODER_SESSION_TOKEN }} + coder-organization: "default" + coder-template-name: coder + coder-template-preset: ${{ steps.determine-context.outputs.template_preset }} + coder-task-name-prefix: severity-classification + coder-task-prompt: ${{ steps.build-prompt.outputs.task_prompt }} + github-user-id: ${{ steps.determine-context.outputs.github_user_id }} + github-token: ${{ github.token }} + github-issue-url: ${{ steps.determine-context.outputs.issue_url }} + comment-on-issue: true + + - name: Write outputs env: - GH_TOKEN: ${{ github.token }} - REASONING: ${{ steps.parse.outputs.reasoning }} - NEXT_STEPS: ${{ steps.parse.outputs.next_steps }} + TASK_CREATED: ${{ steps.create_task.outputs.task-created }} + TASK_NAME: ${{ steps.create_task.outputs.task-name }} + TASK_URL: ${{ steps.create_task.outputs.task-url }} + ISSUE_URL: ${{ steps.determine-context.outputs.issue_url }} run: | - gh issue comment "${{ github.event.issue.number }}" \ - --repo "${{ github.repository }}" \ - --body "## 🤖 Automated Severity Classification - - **Status:** Unable to classify - insufficient information - - **Reasoning:** - ${REASONING} - - **Suggested next steps:** - ${NEXT_STEPS} - - --- - *This classification was performed by AI analysis. Please provide the requested information for proper severity assessment.*" + { + echo "## Severity Classification Task" + echo "" + echo "**Issue:** ${ISSUE_URL}" + echo "**Task created:** ${TASK_CREATED}" + echo "**Task name:** ${TASK_NAME}" + echo "**Task URL:** ${TASK_URL}" + echo "" + echo "The Coder task is analyzing the issue and will comment with severity classification." + } >> "${GITHUB_STEP_SUMMARY}"