Skip to content

Commit 00195e6

Browse files
authored
chore: Enable Gemini CLI Github Actions (#3880)
Following https://github.com/google-github-actions/run-gemini-cli Code is generated with `/setup-github`
1 parent c34e384 commit 00195e6

File tree

4 files changed

+933
-0
lines changed

4 files changed

+933
-0
lines changed

.github/workflows/gemini-cli.yml

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
name: '💬 Gemini CLI'
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
concurrency:
8+
group: '${{ github.workflow }}-${{ github.event.issue.number }}'
9+
cancel-in-progress: |-
10+
${{ github.event.sender.type == 'User' && ( github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'COLLABORATOR') }}
11+
12+
defaults:
13+
run:
14+
shell: 'bash'
15+
16+
permissions:
17+
contents: 'write'
18+
id-token: 'write'
19+
pull-requests: 'write'
20+
issues: 'write'
21+
22+
jobs:
23+
gemini-cli:
24+
# This condition is complex to ensure we only run when explicitly invoked.
25+
if: |-
26+
github.event_name == 'workflow_dispatch' ||
27+
(
28+
github.event_name == 'issues' && github.event.action == 'opened' &&
29+
contains(github.event.issue.body, '@gemini-cli') &&
30+
!contains(github.event.issue.body, '@gemini-cli /review') &&
31+
!contains(github.event.issue.body, '@gemini-cli /triage') &&
32+
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association)
33+
) ||
34+
(
35+
github.event_name == 'issue_comment' &&
36+
contains(github.event.comment.body, '@gemini-cli') &&
37+
!contains(github.event.comment.body, '@gemini-cli /review') &&
38+
!contains(github.event.comment.body, '@gemini-cli /triage') &&
39+
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
40+
)
41+
timeout-minutes: 10
42+
runs-on: 'ubuntu-latest'
43+
44+
steps:
45+
- name: 'Get context from event'
46+
id: 'get_context'
47+
env:
48+
EVENT_NAME: '${{ github.event_name }}'
49+
EVENT_PAYLOAD: '${{ toJSON(github.event) }}'
50+
run: |-
51+
set -euo pipefail
52+
53+
USER_REQUEST=""
54+
ISSUE_NUMBER=""
55+
IS_PR="false"
56+
57+
if [[ "${EVENT_NAME}" == "issues" ]]; then
58+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.body)
59+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
60+
elif [[ "${EVENT_NAME}" == "issue_comment" ]]; then
61+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
62+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
63+
if [[ $(echo "${EVENT_PAYLOAD}" | jq -r .issue.pull_request) != "null" ]]; then
64+
IS_PR="true"
65+
fi
66+
fi
67+
68+
# Clean up user request
69+
USER_REQUEST=$(echo "${USER_REQUEST}" | sed 's/.*@gemini-cli//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
70+
71+
{
72+
echo "user_request=${USER_REQUEST}"
73+
echo "issue_number=${ISSUE_NUMBER}"
74+
echo "is_pr=${IS_PR}"
75+
} >> "${GITHUB_OUTPUT}"
76+
77+
- name: 'Set up git user for commits'
78+
run: |-
79+
git config --global user.name 'gemini-cli[bot]'
80+
git config --global user.email 'gemini-cli[bot]@users.noreply.github.com'
81+
82+
- name: 'Checkout PR branch'
83+
if: |-
84+
${{ steps.get_context.outputs.is_pr == 'true' }}
85+
uses: 'actions/checkout@v5'
86+
with:
87+
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
88+
repository: '${{ github.repository }}'
89+
ref: 'refs/pull/${{ steps.get_context.outputs.issue_number }}/head'
90+
fetch-depth: 0
91+
92+
- name: 'Checkout main branch'
93+
if: |-
94+
${{ steps.get_context.outputs.is_pr == 'false' }}
95+
uses: 'actions/checkout@v5'
96+
with:
97+
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
98+
repository: '${{ github.repository }}'
99+
fetch-depth: 0
100+
101+
- name: 'Acknowledge request'
102+
env:
103+
GITHUB_ACTOR: '${{ github.actor }}'
104+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
105+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
106+
REPOSITORY: '${{ github.repository }}'
107+
REQUEST_TYPE: '${{ steps.get_context.outputs.request_type }}'
108+
run: |-
109+
set -euo pipefail
110+
MESSAGE="@${GITHUB_ACTOR} I've received your request and I'm working on it now! 🤖"
111+
if [[ -n "${MESSAGE}" ]]; then
112+
gh issue comment "${ISSUE_NUMBER}" \
113+
--body "${MESSAGE}" \
114+
--repo "${REPOSITORY}"
115+
fi
116+
117+
- name: 'Get description'
118+
id: 'get_description'
119+
env:
120+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
121+
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
122+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
123+
run: |-
124+
set -euo pipefail
125+
if [[ "${IS_PR}" == "true" ]]; then
126+
DESCRIPTION=$(gh pr view "${ISSUE_NUMBER}" --json body --template '{{.body}}')
127+
else
128+
DESCRIPTION=$(gh issue view "${ISSUE_NUMBER}" --json body --template '{{.body}}')
129+
fi
130+
{
131+
echo "description<<EOF"
132+
echo "${DESCRIPTION}"
133+
echo "EOF"
134+
} >> "${GITHUB_OUTPUT}"
135+
136+
- name: 'Get comments'
137+
id: 'get_comments'
138+
env:
139+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
140+
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
141+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
142+
run: |-
143+
set -euo pipefail
144+
if [[ "${IS_PR}" == "true" ]]; then
145+
COMMENTS=$(gh pr view "${ISSUE_NUMBER}" --json comments --template '{{range .comments}}{{.author.login}}: {{.body}}{{"\n"}}{{end}}')
146+
else
147+
COMMENTS=$(gh issue view "${ISSUE_NUMBER}" --json comments --template '{{range .comments}}{{.author.login}}: {{.body}}{{"\n"}}{{end}}')
148+
fi
149+
{
150+
echo "comments<<EOF"
151+
echo "${COMMENTS}"
152+
echo "EOF"
153+
} >> "${GITHUB_OUTPUT}"
154+
155+
- name: 'Run Gemini'
156+
id: 'run_gemini'
157+
uses: 'google-github-actions/run-gemini-cli@v0'
158+
env:
159+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
160+
REPOSITORY: '${{ github.repository }}'
161+
USER_REQUEST: '${{ steps.get_context.outputs.user_request }}'
162+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
163+
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
164+
with:
165+
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
166+
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
167+
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
168+
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
169+
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
170+
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
171+
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
172+
settings: |-
173+
{
174+
"maxSessionTurns": 50,
175+
"telemetry": {
176+
"enabled": false,
177+
"target": "gcp"
178+
}
179+
}
180+
prompt: |-
181+
## Role
182+
183+
You are a helpful AI assistant invoked via a CLI interface in a GitHub workflow. You have access to tools to interact with the repository and respond to the user.
184+
185+
## Context
186+
187+
- **Repository**: `${{ github.repository }}`
188+
- **Triggering Event**: `${{ github.event_name }}`
189+
- **Issue/PR Number**: `${{ steps.get_context.outputs.issue_number }}`
190+
- **Is this a PR?**: `${{ steps.get_context.outputs.is_pr }}`
191+
- **Issue/PR Description**:
192+
`${{ steps.get_description.outputs.description }}`
193+
- **Comments**:
194+
`${{ steps.get_comments.outputs.comments }}`
195+
196+
## User Request
197+
198+
The user has sent the following request:
199+
`${{ steps.get_context.outputs.user_request }}`
200+
201+
## How to Respond to Issues, PR Comments, and Questions
202+
203+
This workflow supports three main scenarios:
204+
205+
1. **Creating a Fix for an Issue**
206+
- Carefully read the user request and the related issue or PR description.
207+
- Use available tools to gather all relevant context (e.g., `gh issue view`, `gh pr view`, `gh pr diff`, `cat`, `head`, `tail`).
208+
- Identify the root cause of the problem before proceeding.
209+
- **Show and maintain a plan as a checklist**:
210+
- At the very beginning, outline the steps needed to resolve the issue or address the request and post them as a checklist comment on the issue or PR (use GitHub markdown checkboxes: `- [ ] Task`).
211+
- Example:
212+
```
213+
### Plan
214+
- [ ] Investigate the root cause
215+
- [ ] Implement the fix in `file.py`
216+
- [ ] Add/modify tests
217+
- [ ] Update documentation
218+
- [ ] Verify the fix and close the issue
219+
```
220+
- Use: `gh pr comment "${ISSUE_NUMBER}" --body "<plan>"` or `gh issue comment "${ISSUE_NUMBER}" --body "<plan>"` to post the initial plan.
221+
- As you make progress, keep the checklist visible and up to date by editing the same comment (check off completed tasks with `- [x]`).
222+
- To update the checklist:
223+
1. Find the comment ID for the checklist (use `gh pr comment list "${ISSUE_NUMBER}"` or `gh issue comment list "${ISSUE_NUMBER}"`).
224+
2. Edit the comment with the updated checklist:
225+
- For PRs: `gh pr comment --edit <comment-id> --body "<updated plan>"`
226+
- For Issues: `gh issue comment --edit <comment-id> --body "<updated plan>"`
227+
3. The checklist should only be maintained as a comment on the issue or PR. Do not track or update the checklist in code files.
228+
- If the fix requires code changes, determine which files and lines are affected. If clarification is needed, note any questions for the user.
229+
- Make the necessary code or documentation changes using the available tools (e.g., `write_file`). Ensure all changes follow project conventions and best practices. Reference all shell variables as `"${VAR}"` (with quotes and braces) to prevent errors.
230+
- Run any relevant tests or checks to verify the fix works as intended. If possible, provide evidence (test output, screenshots, etc.) that the issue is resolved.
231+
- **Branching and Committing**:
232+
- **NEVER commit directly to the `main` branch.**
233+
- If you are working on a **pull request** (`IS_PR` is `true`), the correct branch is already checked out. Simply commit and push to it.
234+
- `git add .`
235+
- `git commit -m "feat: <describe the change>"`
236+
- `git push`
237+
- If you are working on an **issue** (`IS_PR` is `false`), create a new branch for your changes. A good branch name would be `issue/${ISSUE_NUMBER}/<short-description>`.
238+
- `git checkout -b issue/${ISSUE_NUMBER}/my-fix`
239+
- `git add .`
240+
- `git commit -m "feat: <describe the fix>"`
241+
- `git push origin issue/${ISSUE_NUMBER}/my-fix`
242+
- After pushing, you can create a pull request: `gh pr create --title "Fixes #${ISSUE_NUMBER}: <short title>" --body "This PR addresses issue #${ISSUE_NUMBER}."`
243+
- Summarize what was changed and why in a markdown file: `write_file("response.md", "<your response here>")`
244+
- Post the response as a comment:
245+
- For PRs: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
246+
- For Issues: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
247+
248+
2. **Addressing Comments on a Pull Request**
249+
- Read the specific comment and the context of the PR.
250+
- Use tools like `gh pr view`, `gh pr diff`, and `cat` to understand the code and discussion.
251+
- If the comment requests a change or clarification, follow the same process as for fixing an issue: create a checklist plan, implement, test, and commit any required changes, updating the checklist as you go.
252+
- **Committing Changes**: The correct PR branch is already checked out. Simply add, commit, and push your changes.
253+
- `git add .`
254+
- `git commit -m "fix: address review comments"`
255+
- `git push`
256+
- If the comment is a question, answer it directly and clearly, referencing code or documentation as needed.
257+
- Document your response in `response.md` and post it as a PR comment: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
258+
259+
3. **Answering Any Question on an Issue**
260+
- Read the question and the full issue context using `gh issue view` and related tools.
261+
- Research or analyze the codebase as needed to provide an accurate answer.
262+
- If the question requires code or documentation changes, follow the fix process above, including creating and updating a checklist plan and **creating a new branch for your changes as described in section 1.**
263+
- Write a clear, concise answer in `response.md` and post it as an issue comment: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
264+
265+
## Guidelines
266+
267+
- **Be concise and actionable.** Focus on solving the user's problem efficiently.
268+
- **Always commit and push your changes if you modify code or documentation.**
269+
- **If you are unsure about the fix or answer, explain your reasoning and ask clarifying questions.**
270+
- **Follow project conventions and best practices.**
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
name: '🏷️ Gemini Automated Issue Triage'
2+
3+
on:
4+
issues:
5+
types:
6+
- 'opened'
7+
- 'reopened'
8+
issue_comment:
9+
types:
10+
- 'created'
11+
workflow_dispatch:
12+
inputs:
13+
issue_number:
14+
description: 'issue number to triage'
15+
required: true
16+
type: 'number'
17+
18+
concurrency:
19+
group: '${{ github.workflow }}-${{ github.event.issue.number }}'
20+
cancel-in-progress: true
21+
22+
defaults:
23+
run:
24+
shell: 'bash'
25+
26+
permissions:
27+
contents: 'read'
28+
id-token: 'write'
29+
issues: 'write'
30+
statuses: 'write'
31+
32+
jobs:
33+
triage-issue:
34+
if: |-
35+
github.event_name == 'issues' ||
36+
github.event_name == 'workflow_dispatch' ||
37+
(
38+
github.event_name == 'issue_comment' &&
39+
contains(github.event.comment.body, '@gemini-cli /triage') &&
40+
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
41+
)
42+
timeout-minutes: 5
43+
runs-on: 'ubuntu-latest'
44+
45+
steps:
46+
- name: 'Checkout repository'
47+
uses: 'actions/checkout@v5'
48+
49+
- name: 'Run Gemini Issue Triage'
50+
uses: './'
51+
id: 'gemini_issue_triage'
52+
env:
53+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
54+
ISSUE_TITLE: '${{ github.event.issue.title }}'
55+
ISSUE_BODY: '${{ github.event.issue.body }}'
56+
ISSUE_NUMBER: '${{ github.event.issue.number }}'
57+
REPOSITORY: '${{ github.repository }}'
58+
with:
59+
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
60+
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
61+
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
62+
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
63+
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
64+
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
65+
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
66+
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
67+
settings: |-
68+
{
69+
"maxSessionTurns": 25,
70+
"coreTools": [
71+
"run_shell_command(echo)",
72+
"run_shell_command(gh label list)",
73+
"run_shell_command(gh issue edit)"
74+
],
75+
"telemetry": {
76+
"enabled": true,
77+
"target": "gcp"
78+
}
79+
}
80+
prompt: |-
81+
## Role
82+
83+
You are an issue triage assistant. Analyze the current GitHub issue
84+
and apply the most appropriate existing labels. Use the available
85+
tools to gather information; do not ask for information to be
86+
provided.
87+
88+
## Steps
89+
90+
1. Run: `gh label list` to get all available labels.
91+
2. Review the issue title and body provided in the environment
92+
variables: "${ISSUE_TITLE}" and "${ISSUE_BODY}".
93+
3. Classify issues by their kind (bug, enhancement, documentation,
94+
cleanup, etc) and their priority (p0, p1, p2, p3). Set the
95+
labels accoridng to the format `kind/*` and `priority/*` patterns.
96+
4. Apply the selected labels to this issue using:
97+
`gh issue edit "${ISSUE_NUMBER}" --add-label "label1,label2"`
98+
5. If the "status/needs-triage" label is present, remove it using:
99+
`gh issue edit "${ISSUE_NUMBER}" --remove-label "status/needs-triage"`
100+
101+
## Guidelines
102+
103+
- Only use labels that already exist in the repository
104+
- Do not add comments or modify the issue content
105+
- Triage only the current issue
106+
- Assign all applicable labels based on the issue content
107+
- Reference all shell variables as "${VAR}" (with quotes and braces)
108+
109+
- name: 'Post Issue Triage Failure Comment'
110+
if: |-
111+
${{ failure() && steps.gemini_issue_triage.outcome == 'failure' }}
112+
uses: 'actions/github-script@v7'
113+
with:
114+
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
115+
script: |-
116+
github.rest.issues.createComment({
117+
owner: '${{ github.repository }}'.split('/')[0],
118+
repo: '${{ github.repository }}'.split('/')[1],
119+
issue_number: '${{ github.event.issue.number }}',
120+
body: 'There is a problem with the Gemini CLI issue triaging. Please check the [action logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.'
121+
})

0 commit comments

Comments
 (0)