name: AI Triage Automation on: issues: types: - labeled workflow_dispatch: inputs: issue_url: description: "GitHub Issue URL to process" required: true type: string template_name: description: "Coder template to use for workspace" required: true default: "coder" type: string template_preset: description: "Template preset to use" required: false default: "" type: string prefix: description: "Prefix for workspace name" required: false default: "traiage" type: string permissions: contents: read jobs: traiage: name: Triage GitHub Issue with Claude Code runs-on: ubuntu-latest if: github.event.label.name == 'traiage' || github.event_name == 'workflow_dispatch' timeout-minutes: 30 env: CODER_URL: ${{ secrets.TRAIAGE_CODER_URL }} CODER_SESSION_TOKEN: ${{ secrets.TRAIAGE_CODER_SESSION_TOKEN }} permissions: contents: read issues: write steps: # This is only required for testing locally using nektos/act, so leaving commented out. # An alternative is to use a larger or custom image. # - name: Install Github CLI # id: install-gh # run: | # (type -p wget >/dev/null || (sudo apt update && sudo apt install wget -y)) \ # && sudo mkdir -p -m 755 /etc/apt/keyrings \ # && out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \ # && cat $out | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \ # && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ # && sudo mkdir -p -m 755 /etc/apt/sources.list.d \ # && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ # && sudo apt update \ # && sudo apt install gh -y - name: Determine Inputs id: determine-inputs if: always() env: GITHUB_ACTOR: ${{ github.actor }} GITHUB_EVENT_ISSUE_HTML_URL: ${{ github.event.issue.html_url }} GITHUB_EVENT_NAME: ${{ github.event_name }} GITHUB_EVENT_USER_ID: ${{ github.event.sender.id }} GITHUB_EVENT_USER_LOGIN: ${{ github.event.sender.login }} INPUTS_ISSUE_URL: ${{ inputs.issue_url }} INPUTS_TEMPLATE_NAME: ${{ inputs.template_name || 'coder' }} INPUTS_TEMPLATE_PRESET: ${{ inputs.template_preset || ''}} INPUTS_PREFIX: ${{ inputs.prefix || 'traiage' }} GH_TOKEN: ${{ github.token }} run: | echo "Using template name: ${INPUTS_TEMPLATE_NAME}" echo "template_name=${INPUTS_TEMPLATE_NAME}" >> "${GITHUB_OUTPUT}" echo "Using template preset: ${INPUTS_TEMPLATE_PRESET}" echo "template_preset=${INPUTS_TEMPLATE_PRESET}" >> "${GITHUB_OUTPUT}" echo "Using prefix: ${INPUTS_PREFIX}" echo "prefix=${INPUTS_PREFIX}" >> "${GITHUB_OUTPUT}" # For workflow_dispatch, use the actor who triggered it # For issues events, use the issue author. 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}" echo "Using issue URL: ${INPUTS_ISSUE_URL}" echo "issue_url=${INPUTS_ISSUE_URL}" >> "${GITHUB_OUTPUT}" exit 0 elif [[ "${GITHUB_EVENT_NAME}" == "issues" ]]; then GITHUB_USER_ID=${GITHUB_EVENT_USER_ID} echo "Using issue author: ${GITHUB_EVENT_USER_LOGIN} (ID: ${GITHUB_USER_ID})" echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}" echo "github_username=${GITHUB_EVENT_USER_LOGIN}" >> "${GITHUB_OUTPUT}" echo "Using issue URL: ${GITHUB_EVENT_ISSUE_HTML_URL}" echo "issue_url=${GITHUB_EVENT_ISSUE_HTML_URL}" >> "${GITHUB_OUTPUT}" exit 0 else echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}" exit 1 fi - name: Verify push access env: GITHUB_REPOSITORY: ${{ github.repository }} GH_TOKEN: ${{ github.token }} GITHUB_USERNAME: ${{ steps.determine-inputs.outputs.github_username }} GITHUB_USER_ID: ${{ steps.determine-inputs.outputs.github_user_id }} run: | # Query the actor’s permission on this repo can_push="$(gh api "/repos/${GITHUB_REPOSITORY}/collaborators/${GITHUB_USERNAME}/permission" --jq '.user.permissions.push')" if [[ "${can_push}" != "true" ]]; then echo "::error title=Access Denied::${GITHUB_USERNAME} does not have push access to ${GITHUB_REPOSITORY}" exit 1 fi - name: Extract context key and description from issue id: extract-context env: ISSUE_URL: ${{ steps.determine-inputs.outputs.issue_url }} GH_TOKEN: ${{ github.token }} run: | issue_number="$(gh issue view "${ISSUE_URL}" --json number --jq '.number')" context_key="gh-${issue_number}" TASK_PROMPT=$(cat <> "${GITHUB_OUTPUT}" { echo "TASK_PROMPT<> "${GITHUB_OUTPUT}" - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 path: ./.github/actions/create-task-action persist-credentials: false ref: main repository: coder/create-task-action - name: Create Coder Task id: create_task uses: ./.github/actions/create-task-action with: coder-url: ${{ secrets.TRAIAGE_CODER_URL }} coder-token: ${{ secrets.TRAIAGE_CODER_SESSION_TOKEN }} coder-organization: "default" coder-template-name: coder coder-template-preset: ${{ steps.determine-inputs.outputs.template_preset }} coder-task-name-prefix: gh-coder coder-task-prompt: ${{ steps.extract-context.outputs.task_prompt }} github-user-id: ${{ steps.determine-inputs.outputs.github_user_id }} github-token: ${{ github.token }} github-issue-url: ${{ steps.determine-inputs.outputs.issue_url }} comment-on-issue: ${{ startsWith(steps.determine-inputs.outputs.issue_url, format('{0}/{1}', github.server_url, github.repository)) }} - name: Write outputs env: TASK_CREATED: ${{ steps.create_task.outputs.task-created }} TASK_NAME: ${{ steps.create_task.outputs.task-name }} TASK_URL: ${{ steps.create_task.outputs.task-url }} run: | { echo "**Task created:** ${TASK_CREATED}" echo "**Task name:** ${TASK_NAME}" echo "**Task URL**: ${TASK_URL}" } >> "${GITHUB_STEP_SUMMARY}"