@@ -22,121 +22,140 @@ jobs:
2222 if : github.event_name == 'issues'
2323 runs-on : ubuntu-latest
2424 steps :
25- - name : Analyze issue and apply labels
25+ - name : Get available labels
26+ id : get-labels
2627 uses : actions/github-script@v7
2728 with :
2829 script : |
29- // Function to determine labels based on content
30- function determineLabels(title, body) {
31- const content = (title + ' ' + body).toLowerCase();
32- const labels = [];
33-
34- // Check if it matches bug report patterns
35- if (content.includes('bug report') ||
36- content.includes('buggy behavior') ||
37- content.includes('error') ||
38- content.includes('broken') ||
39- content.includes('not working') ||
40- content.includes('fails to') ||
41- content.includes('crash') ||
42- content.includes('problem')) {
43- labels.push('i: bug');
44- }
30+ const labels = await github.rest.issues.listLabelsForRepo({
31+ owner: context.repo.owner,
32+ repo: context.repo.repo,
33+ per_page: 100
34+ });
35+ const labelNames = labels.data.map(label => label.name);
36+ return labelNames.join(', ');
37+
38+ - name : Set environment variables
39+ env :
40+ ISSUE_TITLE : ${{ github.event.issue.title }}
41+ ISSUE_BODY : ${{ github.event.issue.body }}
42+ LABELS_RESULT : ${{ steps.get-labels.outputs.result }}
43+ run : |
44+ {
45+ echo "AVAILABLE_LABELS=${LABELS_RESULT}"
46+ echo "ISSUE_TITLE=${ISSUE_TITLE}"
47+ echo "ISSUE_BODY<<EOF"
48+ echo "${ISSUE_BODY}"
49+ echo "EOF"
50+ } >> "$GITHUB_ENV"
51+
52+ - name : Analyze issue with AI
53+ id : ai-triage
54+ uses : actions/ai-inference@v1
55+ with :
56+ prompt : |
57+ ## Role
4558
46- // Check if it matches feature request patterns
47- if (content.includes('feature request') ||
48- content.includes('enhancement') ||
49- content.includes('suggestion') ||
50- content.includes('would like') ||
51- content.includes('could you') ||
52- content.includes('add support for') ||
53- content.includes('it would be nice')) {
54- labels.push('i: enhancement');
55- }
59+ You are an issue triage assistant. Analyze the current GitHub
60+ issue and identify the most appropriate existing labels. Use the
61+ available tools to gather information; do not ask for information
62+ to be provided.
5663
57- // Check if it matches support request patterns
58- if (content.includes('support request') ||
59- content.includes('how to') ||
60- content.includes('question') ||
61- content.includes('help needed') ||
62- (content.includes('how do') &&
63- content.includes('?'))) {
64- labels.push('i: state:unsupported');
65- }
64+ ## Guidelines
6665
67- return labels;
68- }
66+ - Only use labels that are from the list of available labels.
67+ - You can choose multiple labels to apply.
68+ - When generating shell commands, you **MUST NOT** use command
69+ substitution with `$(...)`, `<(...)`, or `>(...)`. This is a
70+ security measure to prevent unintended command execution.
71+
72+ ## Input Data
73+
74+ **Available Labels** (comma-separated):
75+ ```
76+ ${{ env.AVAILABLE_LABELS }}
77+ ```
78+
79+ **Issue Title**:
80+ ```
81+ ${{ env.ISSUE_TITLE }}
82+ ```
83+
84+ **Issue Body**:
85+ ```
86+ ${{ env.ISSUE_BODY }}
87+ ```
88+
89+ **Output File Path**:
90+ ```
91+ ${{ env.GITHUB_ENV }}
92+ ```
6993
70- const issue = context.payload.issue;
71- const issueBody = issue.body || '';
72- const issueTitle = issue.title || '';
94+ ## Steps
7395
74- const labels = determineLabels(issueTitle, issueBody);
96+ 1. Review the issue title, issue body, and available labels
97+ provided above.
98+
99+ 2. Based on the issue title and issue body, classify the issue
100+ and choose all appropriate labels from the list of available
101+ labels.
102+
103+ 3. Output the selected labels as a comma-separated list to the
104+ file at the path specified in "Output File Path" using the
105+ following format:
106+ ```
107+ SELECTED_LABELS=label1,label2,label3
108+ ```
109+
110+ - name : Apply labels
111+ uses : actions/github-script@v7
112+ with :
113+ script : |
114+ const selectedLabels = process.env.SELECTED_LABELS;
115+ if (!selectedLabels || selectedLabels.trim() === '') {
116+ console.log('No labels selected by AI');
117+ return;
118+ }
119+
120+ const labels = selectedLabels.split(',')
121+ .map(l => l.trim())
122+ .filter(l => l.length > 0);
75123
76- // Apply labels if any were determined
77124 if (labels.length > 0) {
78125 console.log(`Applying labels: ${labels.join(', ')}`);
79126 await github.rest.issues.addLabels({
80127 owner: context.repo.owner,
81128 repo: context.repo.repo,
82- issue_number: issue.number,
129+ issue_number: context. issue.number,
83130 labels: labels
84131 });
85132 } else {
86- console.log(
87- 'No appropriate labels determined for this issue'
88- );
133+ console.log('No valid labels to apply');
89134 }
90135
91136 triage-unlabeled-issues :
92137 name : Triage Unlabeled Issues
93138 if : github.event_name == 'workflow_dispatch'
94139 runs-on : ubuntu-latest
95140 steps :
96- - name : Find and label unlabeled issues
141+ - name : Get available labels
142+ id : get-labels
97143 uses : actions/github-script@v7
98144 with :
99145 script : |
100- // Function to determine labels based on content
101- function determineLabels(title, body) {
102- const content = (title + ' ' + body).toLowerCase();
103- const labels = [];
104-
105- // Check if it matches bug report patterns
106- if (content.includes('bug report') ||
107- content.includes('buggy behavior') ||
108- content.includes('error') ||
109- content.includes('broken') ||
110- content.includes('not working') ||
111- content.includes('fails to') ||
112- content.includes('crash') ||
113- content.includes('problem')) {
114- labels.push('i: bug');
115- }
116-
117- // Check if it matches feature request patterns
118- if (content.includes('feature request') ||
119- content.includes('enhancement') ||
120- content.includes('suggestion') ||
121- content.includes('would like') ||
122- content.includes('could you') ||
123- content.includes('add support for') ||
124- content.includes('it would be nice')) {
125- labels.push('i: enhancement');
126- }
127-
128- // Check if it matches support request patterns
129- if (content.includes('support request') ||
130- content.includes('how to') ||
131- content.includes('question') ||
132- content.includes('help needed') ||
133- (content.includes('how do') &&
134- content.includes('?'))) {
135- labels.push('i: state:unsupported');
136- }
137-
138- return labels;
139- }
146+ const labels = await github.rest.issues.listLabelsForRepo({
147+ owner: context.repo.owner,
148+ repo: context.repo.repo,
149+ per_page: 100
150+ });
151+ const labelNames = labels.data.map(label => label.name);
152+ return labelNames.join(', ');
153+
154+ - name : Find and triage unlabeled issues
155+ uses : actions/github-script@v7
156+ with :
157+ script : |
158+ const availableLabels = ${{ steps.get-labels.outputs.result }};
140159
141160 // Get all open issues
142161 const issues = await github.paginate(
@@ -160,41 +179,21 @@ jobs:
160179 `Found ${unlabeledIssues.length} unlabeled issues`
161180 );
162181
163- // Process each unlabeled issue
164- for (const issue of unlabeledIssues) {
165- const issueBody = issue.body || '';
166- const issueTitle = issue.title || '';
167-
168- const labels = determineLabels(issueTitle, issueBody);
169-
170- // Apply labels if any were determined
171- if (labels.length > 0) {
172- const labelList = labels.join(', ');
173- console.log(
174- `Issue #${issue.number}: Applying labels: ${labelList}`
175- );
176- try {
177- await github.rest.issues.addLabels({
178- owner: context.repo.owner,
179- repo: context.repo.repo,
180- issue_number: issue.number,
181- labels: labels
182- });
183- } catch (error) {
184- console.error(
185- `Failed to label issue #${issue.number}: ` +
186- `${error.message}`
187- );
188- }
189- } else {
190- console.log(
191- `Issue #${issue.number}: ` +
192- `No appropriate labels determined`
193- );
194- }
195-
196- // Add a small delay to avoid rate limiting
197- await new Promise(resolve => setTimeout(resolve, 100));
182+ if (unlabeledIssues.length === 0) {
183+ console.log('No unlabeled issues to process');
184+ return;
198185 }
199186
200- console.log('Finished processing unlabeled issues');
187+ // For manual dispatch, we'll log that AI triage is not yet
188+ // implemented for batch processing
189+ console.log(
190+ 'Note: Batch AI triage for unlabeled issues requires ' +
191+ 'manual triggering of individual issue workflows or ' +
192+ 'implementing batch AI processing in the future.'
193+ );
194+
195+ for (const issue of unlabeledIssues) {
196+ console.log(
197+ `Issue #${issue.number}: "${issue.title}" needs triage`
198+ );
199+ }
0 commit comments