11name : AI Triage Automation
22
33on :
4+ issues :
5+ types :
6+ - labeled
47 workflow_dispatch :
58 inputs :
69 issue_url :
3235 traiage :
3336 name : Triage GitHub Issue with Claude Code
3437 runs-on : ubuntu-latest
38+ if : github.event.label.name == 'traiage' || github.event_name == 'workflow_dispatch'
3539 timeout-minutes : 30
3640 env :
3741 CODER_URL : ${{ secrets.TRAIAGE_CODER_URL }}
@@ -43,17 +47,58 @@ jobs:
4347 actions : write
4448
4549 steps :
46- - name : Checkout repository
47- uses : actions/checkout@v4
48- with :
49- persist-credentials : false
50- fetch-depth : 0
50+ - name : Get GitHub user ID
51+ id : github-user-id
52+ if : always()
53+ env :
54+ GITHUB_ACTOR : ${{ github.actor }}
55+ GITHUB_EVENT_NAME : ${{ github.event_name }}
56+ GITHUB_EVENT_USER_ID : ${{ github.event.sender.id }}
57+ GITHUB_EVENT_USER_LOGIN : ${{ github.event.sender.login }}
58+ GH_TOKEN : ${{ github.token }}
59+ run : |
60+ # For workflow_dispatch, use the actor who triggered it
61+ # For issues events, use the issue author
62+ if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
63+ if ! GITHUB_USER_ID=$(gh api "users/${GITHUB_ACTOR}" --jq '.id'); then
64+ echo "::error::Failed to get GitHub user ID for actor ${GITHUB_ACTOR}"
65+ exit 1
66+ fi
67+ echo "Using workflow_dispatch actor: ${GITHUB_ACTOR} (ID: ${GITHUB_USER_ID})"
68+ echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}"
69+ echo "github_username=${GITHUB_ACTOR}" >> "${GITHUB_OUTPUT}"
70+ exit 0
71+ elif [[ "${GITHUB_EVENT_NAME}" == "issues" ]]; then
72+ GITHUB_USER_ID=${GITHUB_EVENT_USER_ID}
73+ echo "Using issue author: ${GITHUB_EVENT_USER_LOGIN} (ID: ${GITHUB_USER_ID})"
74+ echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}"
75+ echo "github_username=${GITHUB_EVENT_USER_LOGIN}" >> "${GITHUB_OUTPUT}"
76+ exit 0
77+ else
78+ echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}"
79+ exit 1
80+ fi
81+
82+ - name : Verify organization membership
83+ env :
84+ GITHUB_ORG : ${{ github.repository_owner }}
85+ GH_TOKEN : ${{ github.token }}
86+ GITHUB_USERNAME : ${{ steps.github-user-id.outputs.github_username }}
87+ GITHUB_USER_ID : ${{ steps.github-user-id.outputs.github_user_id }}
88+ run : |
89+ # Check if the actor is a member of the organization
90+ if ! gh api "orgs/${GITHUB_ORG}/members/${GITHUB_USERNAME}" --silent 2>/dev/null; then
91+ echo "::error title=Access Denied::User ${GITHUB_USERNAME} is not a member of the ${GITHUB_ORG} organization"
92+ echo "::error::You must be a member of the ${GITHUB_ORG} GitHub organization to run this workflow."
93+ exit 1
94+ fi
95+ echo "::notice::User ${GITHUB_USERNAME} verified as member of ${GITHUB_ORG} organization"
5196
5297 - name : Extract context key from issue
5398 id : extract-context
5499 env :
55100 ISSUE_URL : ${{ inputs.issue_url }}
56- GITHUB_TOKEN : ${{ github.token }}
101+ GH_TOKEN : ${{ github.token }}
57102 run : |
58103 issue_number="$(gh issue view "${ISSUE_URL}" --json number --jq '.number')"
59104 context_key="gh-${issue_number}"
@@ -82,25 +127,30 @@ jobs:
82127 id : get-coder-username
83128 env :
84129 CODER_SESSION_TOKEN : ${{ secrets.TRAIAGE_CODER_SESSION_TOKEN }}
85- GITHUB_USER_ID : ${{
86- (github.event_name == 'workflow_dispatch' && github.actor_id)
87- }}
130+ GH_TOKEN : ${{ github.token }}
131+ GITHUB_USER_ID : ${{ steps.github-user-id.outputs.github_user_id }}
88132 run : |
89- [[ -z "${GITHUB_USER_ID}" || "${GITHUB_USER_ID}" == "null" ]] && echo "No GitHub actor ID found" && exit 1
90133 user_json=$(
91134 coder users list --github-user-id="${GITHUB_USER_ID}" --output=json
92135 )
93136 coder_username=$(jq -r 'first | .username' <<< "$user_json")
94137 [[ -z "${coder_username}" || "${coder_username}" == "null" ]] && echo "No Coder user with GitHub user ID ${GITHUB_USER_ID} found" && exit 1
95138 echo "coder_username=${coder_username}" >> "${GITHUB_OUTPUT}"
96139
140+ - name : Checkout repository
141+ uses : actions/checkout@v4
142+ with :
143+ persist-credentials : false
144+ fetch-depth : 0
145+
97146 # TODO(Cian): this is a good use-case for 'recipes'
98147 - name : Create Coder task
99148 id : create-task
100149 env :
101150 CODER_USERNAME : ${{ steps.get-coder-username.outputs.coder_username }}
102151 CONTEXT_KEY : ${{ steps.extract-context.outputs.context_key }}
103- GITHUB_TOKEN : ${{ github.token }}
152+ GH_TOKEN : ${{ github.token }}
153+ GITHUB_REPOSITORY : ${{ github.repository }}
104154 ISSUE_URL : ${{ inputs.issue_url }}
105155 PREFIX : ${{ inputs.prefix }}
106156 RUN_ID : ${{ github.run_id }}
@@ -125,7 +175,11 @@ jobs:
125175 export TASK_NAME="${PREFIX}-${CONTEXT_KEY}-${RUN_ID}"
126176 echo "Creating task: $TASK_NAME"
127177 ./scripts/traiage.sh create
128- coder exp task status "${CODER_USERNAME}/$TASK_NAME" --watch
178+ if [[ "${ISSUE_URL}" == "https://github.com/${GITHUB_REPOSITORY}"* ]]; then
179+ gh issue comment "${ISSUE_URL}" --body "Task created: ${TASK_NAME}" --create-if-none --edit-last
180+ else
181+ echo "Skipping comment on other repo."
182+ fi
129183 echo "TASK_NAME=${CODER_USERNAME}/${TASK_NAME}" >> "${GITHUB_OUTPUT}"
130184 echo "TASK_NAME=${CODER_USERNAME}/${TASK_NAME}" >> "${GITHUB_ENV}"
131185
@@ -134,7 +188,11 @@ jobs:
134188 if : inputs.cleanup
135189 env :
136190 BUCKET_PREFIX : " gs://coder-traiage-outputs/traiage"
191+ CODER_USERNAME : ${{ steps.get-coder-username.outputs.coder_username }}
192+ TASK_NAME : ${{ steps.create-task.outputs.TASK_NAME }}
137193 run : |
194+ echo "Waiting for task to complete..."
195+ coder exp task status "${CODER_USERNAME}/$TASK_NAME" --watch
138196 echo "Creating archive for workspace: $TASK_NAME"
139197 ./scripts/traiage.sh archive
140198 echo "archive_url=${BUCKET_PREFIX%%/}/$TASK_NAME.tar.gz" >> "${GITHUB_OUTPUT}"
@@ -145,8 +203,9 @@ jobs:
145203 env :
146204 ARCHIVE_URL : ${{ steps.create-archive.outputs.archive_url }}
147205 BUCKET_PREFIX : " gs://coder-traiage-outputs/traiage"
206+ CODER_USERNAME : ${{ steps.get-coder-username.outputs.coder_username }}
148207 CONTEXT_KEY : ${{ steps.extract-context.outputs.context_key }}
149- GITHUB_TOKEN : ${{ github.token }}
208+ GH_TOKEN : ${{ github.token }}
150209 GITHUB_REPOSITORY : ${{ github.repository }}
151210 ISSUE_URL : ${{ inputs.issue_url }}
152211 TASK_NAME : ${{ steps.create-task.outputs.TASK_NAME }}
0 commit comments