@@ -2,19 +2,13 @@ name: '📋 Gemini Scheduled Issue Triage'
22
33on :
44 schedule :
5- - cron : ' 0 * * * *' # Runs every hour
5+ - cron : ' 0 * * * *'
66 pull_request :
7- branches :
8- - ' main'
9- - ' release/**/*'
10- paths :
11- - ' .github/workflows/gemini-scheduled-triage.yml'
7+ branches : [main]
8+ paths : ['.github/workflows/gemini-scheduled-triage.yml']
129 push :
13- branches :
14- - ' main'
15- - ' release/**/*'
16- paths :
17- - ' .github/workflows/gemini-scheduled-triage.yml'
10+ branches : [main]
11+ paths : ['.github/workflows/gemini-scheduled-triage.yml']
1812 workflow_dispatch :
1913
2014concurrency :
@@ -40,17 +34,14 @@ jobs:
4034 steps :
4135 - name : ' Get repository labels'
4236 id : ' get_labels'
43- uses : ' actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd ' # ratchet:actions/github-script@v8.0.0
37+ uses : ' actions/github-script@v7 '
4438 with :
45- # NOTE: we intentionally do not use the minted token. The default
46- # GITHUB_TOKEN provided by the action has enough permissions to read
47- # the labels.
4839 script : |-
4940 const labels = [];
5041 for await (const response of github.paginate.iterator(github.rest.issues.listLabelsForRepo, {
5142 owner: context.repo.owner,
5243 repo: context.repo.repo,
53- per_page: 100, // Maximum per page to reduce API calls
44+ per_page: 100,
5445 })) {
5546 labels.push(...response.data);
5647 }
@@ -70,32 +61,26 @@ jobs:
7061 GITHUB_REPOSITORY : ' ${{ github.repository }}'
7162 GITHUB_TOKEN : ' ${{ secrets.GITHUB_TOKEN || github.token }}'
7263 run : |-
73- echo '🔍 Finding unlabeled issues and issues marked for triage...'
7464 ISSUES="$(gh issue list \
7565 --state 'open' \
7666 --search 'no:label label:"status/needs-triage"' \
7767 --json number,title,body \
7868 --limit '100' \
7969 --repo "${GITHUB_REPOSITORY}"
8070 )"
81-
82- echo '📝 Setting output for GitHub Actions...'
8371 echo "issues_to_triage=${ISSUES}" >> "${GITHUB_OUTPUT}"
8472
85- ISSUE_COUNT="$(echo "${ISSUES}" | jq 'length')"
86- echo "✅ Found ${ISSUE_COUNT} issue(s) to triage! 🎯"
87-
8873 - name : ' Run Gemini Issue Analysis'
8974 id : ' gemini_issue_analysis'
9075 if : |-
9176 ${{ steps.find_issues.outputs.issues_to_triage != '[]' }}
92- uses : ' google-github-actions/run-gemini-cli@v0' # ratchet:exclude
77+ uses : ' google-github-actions/run-gemini-cli@v0'
9378 env :
94- GITHUB_TOKEN : ' ' # Do not pass any auth token here since this runs on untrusted inputs
79+ GITHUB_TOKEN : ' '
9580 ISSUES_TO_TRIAGE : ' ${{ steps.find_issues.outputs.issues_to_triage }}'
9681 REPOSITORY : ' ${{ github.repository }}'
9782 AVAILABLE_LABELS : ' ${{ steps.get_labels.outputs.available_labels }}'
98- GEMINI_CLI_TRUST_WORKSPACE : true
83+ GEMINI_CLI_TRUST_WORKSPACE : ' true'
9984 with :
10085 gemini_api_key : ' ${{ secrets.GEMINI_API_KEY }}'
10186 gemini_cli_version : ' ${{ vars.GEMINI_CLI_VERSION }}'
@@ -125,13 +110,10 @@ jobs:
125110
126111 label :
127112 runs-on : ' ubuntu-latest'
128- needs :
129- - ' triage'
113+ needs : [triage]
130114 if : |-
131115 needs.triage.outputs.available_labels != '' &&
132- needs.triage.outputs.available_labels != '[]' &&
133- needs.triage.outputs.triaged_issues != '' &&
134- needs.triage.outputs.triaged_issues != '[]'
116+ needs.triage.outputs.triaged_issues != ''
135117 permissions :
136118 contents : ' read'
137119 issues : ' write'
@@ -141,7 +123,7 @@ jobs:
141123 id : ' mint_identity_token'
142124 if : |-
143125 ${{ vars.APP_ID }}
144- uses : ' actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf ' # ratchet:actions/create-github-app-token@v2
126+ uses : ' actions/create-github-app-token@v2 '
145127 with :
146128 app-id : ' ${{ vars.APP_ID }}'
147129 private-key : ' ${{ secrets.APP_PRIVATE_KEY }}'
@@ -153,56 +135,30 @@ jobs:
153135 env :
154136 AVAILABLE_LABELS : ' ${{ needs.triage.outputs.available_labels }}'
155137 TRIAGED_ISSUES : ' ${{ needs.triage.outputs.triaged_issues }}'
156- uses : ' actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd ' # ratchet:actions/github-script@v8.0.0
138+ uses : ' actions/github-script@v7 '
157139 with :
158- # Use the provided token so that the "gemini-cli" is the actor in the
159- # log for what changed the labels.
160140 github-token : ' ${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
161141 script : |-
162- // Parse the available labels
163142 const availableLabels = (process.env.AVAILABLE_LABELS || '').split(',')
164143 .map((label) => label.trim())
165144 .sort()
166145
167- // Parse out the triaged issues
168146 const triagedIssues = (JSON.parse(process.env.TRIAGED_ISSUES || '{}'))
169- .sort((a, b) => a.issue_number - b.issue_number)
170-
171- core.debug(`Triaged issues: ${JSON.stringify(triagedIssues)}`);
172147
173- // Iterate over each label
174148 for (const issue of triagedIssues) {
175- if (!issue) {
176- core.debug(`Skipping empty issue: ${JSON.stringify(issue)}`);
177- continue;
178- }
149+ if (!issue || !issue.issue_number) continue;
179150
180- const issueNumber = issue.issue_number;
181- if (!issueNumber) {
182- core.debug(`Skipping issue with no data: ${JSON.stringify(issue)}`);
183- continue;
184- }
185-
186- // Extract and reject invalid labels - we do this just in case
187- // someone was able to prompt inject malicious labels.
188151 let labelsToSet = (issue.labels_to_set || [])
189152 .map((label) => label.trim())
190153 .filter((label) => availableLabels.includes(label))
191154 .sort()
192155
193- core.debug(`Identified labels to set: ${JSON.stringify(labelsToSet)}`);
194-
195- if (labelsToSet.length === 0) {
196- core.info(`Skipping issue #${issueNumber} - no labels to set.`)
197- continue;
198- }
199-
200- core.debug(`Setting labels on issue #${issueNumber} to ${labelsToSet.join(', ')} (${issue.explanation || 'no explanation'})`)
156+ if (labelsToSet.length === 0) continue;
201157
202158 await github.rest.issues.setLabels({
203159 owner: context.repo.owner,
204160 repo: context.repo.repo,
205- issue_number: issueNumber ,
161+ issue_number: issue.issue_number ,
206162 labels: labelsToSet,
207163 });
208164 }
0 commit comments