11---
2- name : Issue Triage
2+ name : Issue and PR Triage
33
44' on ' :
55 workflow_call :
66 inputs :
77 issue_number :
8- description : ' Issue number to triage (leave empty to process all)'
8+ description : ' Issue/PR number to triage (leave empty to process all)'
99 required : false
1010 type : string
1111
1212permissions :
1313 issues : write
14+ pull-requests : write
1415 contents : read
1516 models : read
1617
1718jobs :
18- triage-new-issue :
19- name : Triage New Issue
20- if : github.event_name == 'issues'
19+ triage-new-item :
20+ name : Triage New Issue or PR
21+ if : github.event_name == 'issues' || github.event_name == 'pull_request'
2122 runs-on : ubuntu-latest
2223 steps :
2324 - name : Get available labels
@@ -35,27 +36,29 @@ jobs:
3536
3637 - name : Set environment variables
3738 env :
38- ISSUE_TITLE : ${{ github.event.issue.title }}
39- ISSUE_BODY : ${{ github.event.issue.body }}
39+ ITEM_TITLE : ${{ github.event_name == 'pull_request' && github.event.pull_request.title || github.event.issue.title }}
40+ ITEM_BODY : ${{ github.event_name == 'pull_request' && github.event.pull_request.body || github.event.issue.body }}
41+ ITEM_TYPE : ${{ github.event_name == 'pull_request' && 'pull request' || 'issue' }}
4042 LABELS_RESULT : ${{ steps.get-labels.outputs.result }}
4143 run : |
4244 {
4345 echo "AVAILABLE_LABELS=${LABELS_RESULT}"
44- echo "ISSUE_TITLE=${ISSUE_TITLE}"
45- echo "ISSUE_BODY<<EOF"
46- echo "${ISSUE_BODY}"
46+ echo "ITEM_TITLE=${ITEM_TITLE}"
47+ echo "ITEM_TYPE=${ITEM_TYPE}"
48+ echo "ITEM_BODY<<EOF"
49+ echo "${ITEM_BODY}"
4750 echo "EOF"
4851 } >> "$GITHUB_ENV"
4952
50- - name : Analyze issue with AI
53+ - name : Analyze with AI
5154 id : ai-triage
5255 uses : actions/ai-inference@v2
5356 with :
5457 prompt : |
5558 ## Role
5659
57- You are an issue triage assistant. Analyze the current GitHub
58- issue and identify the most appropriate existing labels. Use the
60+ You are an issue and pull request triage assistant. Analyze the current GitHub
61+ ${{ env.ITEM_TYPE }} and identify the most appropriate existing labels. Use the
5962 available tools to gather information; do not ask for information
6063 to be provided.
6164
@@ -74,22 +77,22 @@ jobs:
7477 ${{ env.AVAILABLE_LABELS }}
7578 ```
7679
77- **Issue Title**:
80+ **Title**:
7881 ```
79- ${{ env.ISSUE_TITLE }}
82+ ${{ env.ITEM_TITLE }}
8083 ```
8184
82- **Issue Body**:
85+ **Body**:
8386 ```
84- ${{ env.ISSUE_BODY }}
87+ ${{ env.ITEM_BODY }}
8588 ```
8689
8790 ## Steps
8891
89- 1. Review the issue title, issue body, and available labels
92+ 1. Review the title, body, and available labels
9093 provided above.
9194
92- 2. Based on the issue title and issue body, classify the issue
95+ 2. Based on the title and body, classify the ${{ env.ITEM_TYPE }}
9396 and choose all appropriate labels from the list of available
9497 labels.
9598
@@ -128,18 +131,18 @@ jobs:
128131 console.log('No valid labels to apply');
129132 }
130133
131- triage-unlabeled-issues :
132- name : Triage Unlabeled Issues
134+ triage-unlabeled-items :
135+ name : Triage Unlabeled Issues and PRs
133136 if : |
134137 github.event_name == 'workflow_dispatch' &&
135138 inputs.issue_number == ''
136139 runs-on : ubuntu-latest
137140 steps :
138- - name : Find and dispatch triage for unlabeled issues
141+ - name : Find and dispatch triage for unlabeled items
139142 uses : actions/github-script@v8
140143 with :
141144 script : |
142- // Get all open issues
145+ // Get all open issues (includes PRs)
143146 const issues = await github.paginate(
144147 github.rest.issues.listForRepo,
145148 {
@@ -150,27 +153,28 @@ jobs:
150153 }
151154 );
152155
153- console.log(`Found ${issues.length} open issues`);
156+ console.log(`Found ${issues.length} open issues and PRs `);
154157
155- // Filter issues without labels
156- const unlabeledIssues = issues.filter(issue =>
157- !issue.pull_request && issue.labels.length === 0
158+ // Filter items without labels
159+ const unlabeledItems = issues.filter(issue =>
160+ issue.labels.length === 0
158161 );
159162
160163 console.log(
161- `Found ${unlabeledIssues .length} unlabeled issues `
164+ `Found ${unlabeledItems .length} unlabeled items `
162165 );
163166
164- if (unlabeledIssues .length === 0) {
165- console.log('No unlabeled issues to process');
167+ if (unlabeledItems .length === 0) {
168+ console.log('No unlabeled items to process');
166169 return;
167170 }
168171
169- // Dispatch triage workflow for each unlabeled issue
170- for (const issue of unlabeledIssues) {
172+ // Dispatch triage workflow for each unlabeled item
173+ for (const item of unlabeledItems) {
174+ const itemType = item.pull_request ? 'PR' : 'issue';
171175 console.log(
172- `Dispatching triage for issue #${issue .number}: ` +
173- `"${issue .title}"`
176+ `Dispatching triage for ${itemType} #${item .number}: ` +
177+ `"${item .title}"`
174178 );
175179
176180 try {
@@ -180,12 +184,12 @@ jobs:
180184 workflow_id: 'issue-triage.yml',
181185 ref: context.ref || 'main',
182186 inputs: {
183- issue_number: issue .number.toString()
187+ issue_number: item .number.toString()
184188 }
185189 });
186190 } catch (error) {
187191 console.error(
188- `Failed to dispatch triage for issue #${issue .number}: ` +
192+ `Failed to dispatch triage for ${itemType} #${item .number}: ` +
189193 `${error.message}`
190194 );
191195 }
@@ -196,8 +200,8 @@ jobs:
196200
197201 console.log('Finished dispatching triage workflows');
198202
199- triage-single-issue :
200- name : Triage Single Issue
203+ triage-single-item :
204+ name : Triage Single Issue or PR
201205 if : |
202206 github.event_name == 'workflow_dispatch' &&
203207 inputs.issue_number != ''
@@ -216,44 +220,53 @@ jobs:
216220 const labelNames = labels.data.map(label => label.name);
217221 return labelNames.join(', ');
218222
219- - name : Get issue details
220- id : get-issue
223+ - name : Get item details
224+ id : get-item
221225 uses : actions/github-script@v8
222226 with :
223227 script : |
228+ const itemNumber = parseInt('${{ inputs.issue_number }}');
229+
230+ // Try to get as an issue first (works for both issues and PRs)
224231 const issue = await github.rest.issues.get({
225232 owner: context.repo.owner,
226233 repo: context.repo.repo,
227- issue_number: parseInt('${{ inputs.issue_number }}')
234+ issue_number: itemNumber
228235 });
236+
237+ const itemType = issue.data.pull_request ? 'pull request' : 'issue';
238+
229239 return {
230240 title: issue.data.title,
231- body: issue.data.body || ''
241+ body: issue.data.body || '',
242+ type: itemType
232243 };
233244
234245 - name : Set environment variables
235246 env :
236- ISSUE_TITLE : ${{ fromJSON(steps.get-issue.outputs.result).title }}
237- ISSUE_BODY : ${{ fromJSON(steps.get-issue.outputs.result).body }}
247+ ITEM_TITLE : ${{ fromJSON(steps.get-item.outputs.result).title }}
248+ ITEM_BODY : ${{ fromJSON(steps.get-item.outputs.result).body }}
249+ ITEM_TYPE : ${{ fromJSON(steps.get-item.outputs.result).type }}
238250 LABELS_RESULT : ${{ steps.get-labels.outputs.result }}
239251 run : |
240252 {
241253 echo "AVAILABLE_LABELS=${LABELS_RESULT}"
242- echo "ISSUE_TITLE=${ISSUE_TITLE}"
243- echo "ISSUE_BODY<<EOF"
244- echo "${ISSUE_BODY}"
254+ echo "ITEM_TITLE=${ITEM_TITLE}"
255+ echo "ITEM_TYPE=${ITEM_TYPE}"
256+ echo "ITEM_BODY<<EOF"
257+ echo "${ITEM_BODY}"
245258 echo "EOF"
246259 } >> "$GITHUB_ENV"
247260
248- - name : Analyze issue with AI
261+ - name : Analyze with AI
249262 id : ai-triage
250263 uses : actions/ai-inference@v2
251264 with :
252265 prompt : |
253266 ## Role
254267
255- You are an issue triage assistant. Analyze the current GitHub
256- issue and identify the most appropriate existing labels. Use the
268+ You are an issue and pull request triage assistant. Analyze the current GitHub
269+ ${{ env.ITEM_TYPE }} and identify the most appropriate existing labels. Use the
257270 available tools to gather information; do not ask for information
258271 to be provided.
259272
@@ -272,22 +285,22 @@ jobs:
272285 ${{ env.AVAILABLE_LABELS }}
273286 ```
274287
275- **Issue Title**:
288+ **Title**:
276289 ```
277- ${{ env.ISSUE_TITLE }}
290+ ${{ env.ITEM_TITLE }}
278291 ```
279292
280- **Issue Body**:
293+ **Body**:
281294 ```
282- ${{ env.ISSUE_BODY }}
295+ ${{ env.ITEM_BODY }}
283296 ```
284297
285298 ## Steps
286299
287- 1. Review the issue title, issue body, and available labels
300+ 1. Review the title, body, and available labels
288301 provided above.
289302
290- 2. Based on the issue title and issue body, classify the issue
303+ 2. Based on the title and body, classify the ${{ env.ITEM_TYPE }}
291304 and choose all appropriate labels from the list of available
292305 labels.
293306
@@ -302,11 +315,11 @@ jobs:
302315 uses : actions/github-script@v8
303316 env :
304317 AI_RESPONSE : ${{ steps.ai-triage.outputs.response }}
305- ISSUE_NUMBER : ${{ inputs.issue_number }}
318+ ITEM_NUMBER : ${{ inputs.issue_number }}
306319 with :
307320 script : |
308321 const response = process.env.AI_RESPONSE;
309- const issueNumber = parseInt(process.env.ISSUE_NUMBER );
322+ const itemNumber = parseInt(process.env.ITEM_NUMBER );
310323
311324 if (!response || response.trim() === '') {
312325 console.log('No labels selected by AI');
@@ -322,7 +335,7 @@ jobs:
322335 await github.rest.issues.addLabels({
323336 owner: context.repo.owner,
324337 repo: context.repo.repo,
325- issue_number: issueNumber ,
338+ issue_number: itemNumber ,
326339 labels: labels
327340 });
328341 } else {
0 commit comments