Skip to content

Commit c957ce0

Browse files
committed
Add GeminiCLI Github Action experimentally
All settings of this Github Action is generated from the Gemini CLI.
1 parent de68d35 commit c957ce0

4 files changed

Lines changed: 1223 additions & 0 deletions

File tree

.github/workflows/gemini-cli.yml

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: '💬 Gemini CLI'
16+
17+
on:
18+
pull_request_review_comment:
19+
types:
20+
- 'created'
21+
pull_request_review:
22+
types:
23+
- 'submitted'
24+
issue_comment:
25+
types:
26+
- 'created'
27+
28+
concurrency:
29+
group: '${{ github.workflow }}-${{ github.event.issue.number }}'
30+
cancel-in-progress: |-
31+
${{ github.event.sender.type == 'User' && ( github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'COLLABORATOR') }}
32+
33+
defaults:
34+
run:
35+
shell: 'bash'
36+
37+
permissions:
38+
contents: 'write'
39+
id-token: 'write'
40+
pull-requests: 'write'
41+
issues: 'write'
42+
43+
jobs:
44+
gemini-cli:
45+
# This condition seeks to ensure the action is only run when it is triggered by a trusted user.
46+
# For private repos, users who have access to the repo are considered trusted.
47+
# For public repos, users who members, owners, or collaborators are considered trusted.
48+
if: |-
49+
github.event_name == 'workflow_dispatch' ||
50+
(
51+
github.event_name == 'issues' && github.event.action == 'opened' &&
52+
contains(github.event.issue.body, '@gemini-cli') &&
53+
!contains(github.event.issue.body, '@gemini-cli /review') &&
54+
!contains(github.event.issue.body, '@gemini-cli /triage') &&
55+
(
56+
github.event.repository.private == true ||
57+
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association)
58+
)
59+
) ||
60+
(
61+
(
62+
github.event_name == 'issue_comment' ||
63+
github.event_name == 'pull_request_review_comment'
64+
) &&
65+
contains(github.event.comment.body, '@gemini-cli') &&
66+
!contains(github.event.comment.body, '@gemini-cli /review') &&
67+
!contains(github.event.comment.body, '@gemini-cli /triage') &&
68+
(
69+
github.event.repository.private == true ||
70+
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
71+
)
72+
) ||
73+
(
74+
github.event_name == 'pull_request_review' &&
75+
contains(github.event.review.body, '@gemini-cli') &&
76+
!contains(github.event.review.body, '@gemini-cli /review') &&
77+
!contains(github.event.review.body, '@gemini-cli /triage') &&
78+
(
79+
github.event.repository.private == true ||
80+
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)
81+
)
82+
)
83+
timeout-minutes: 10
84+
runs-on: 'ubuntu-latest'
85+
steps:
86+
- name: 'Generate GitHub App Token'
87+
id: 'generate_token'
88+
if: |-
89+
${{ vars.APP_ID }}
90+
uses: 'actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e' # ratchet:actions/create-github-app-token@v2
91+
with:
92+
app-id: '${{ vars.APP_ID }}'
93+
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
94+
95+
- name: 'Get context from event'
96+
id: 'get_context'
97+
env:
98+
EVENT_NAME: '${{ github.event_name }}'
99+
EVENT_PAYLOAD: '${{ toJSON(github.event) }}'
100+
run: |-
101+
set -euo pipefail
102+
103+
USER_REQUEST=""
104+
ISSUE_NUMBER=""
105+
IS_PR="false"
106+
107+
if [[ "${EVENT_NAME}" == "issues" ]]; then
108+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.body)
109+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
110+
elif [[ "${EVENT_NAME}" == "issue_comment" ]]; then
111+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
112+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
113+
if [[ $(echo "${EVENT_PAYLOAD}" | jq -r .issue.pull_request) != "null" ]]; then
114+
IS_PR="true"
115+
fi
116+
elif [[ "${EVENT_NAME}" == "pull_request_review" ]]; then
117+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .review.body)
118+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .pull_request.number)
119+
IS_PR="true"
120+
elif [[ "${EVENT_NAME}" == "pull_request_review_comment" ]]; then
121+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
122+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .pull_request.number)
123+
IS_PR="true"
124+
fi
125+
126+
# Clean up user request
127+
USER_REQUEST=$(echo "${USER_REQUEST}" | sed 's/.*@gemini-cli//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
128+
129+
{
130+
echo "user_request=${USER_REQUEST}"
131+
echo "issue_number=${ISSUE_NUMBER}"
132+
echo "is_pr=${IS_PR}"
133+
} >> "${GITHUB_OUTPUT}"
134+
135+
- name: 'Set up git user for commits'
136+
run: |-
137+
git config --global user.name 'gemini-cli[bot]'
138+
git config --global user.email 'gemini-cli[bot]@users.noreply.github.com'
139+
140+
- name: 'Checkout PR branch'
141+
if: |-
142+
${{ steps.get_context.outputs.is_pr == 'true' }}
143+
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
144+
with:
145+
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
146+
repository: '${{ github.repository }}'
147+
ref: 'refs/pull/${{ steps.get_context.outputs.issue_number }}/head'
148+
fetch-depth: 0
149+
150+
- name: 'Checkout main branch'
151+
if: |-
152+
${{ steps.get_context.outputs.is_pr == 'false' }}
153+
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
154+
with:
155+
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
156+
repository: '${{ github.repository }}'
157+
fetch-depth: 0
158+
159+
- name: 'Acknowledge request'
160+
env:
161+
GITHUB_ACTOR: '${{ github.actor }}'
162+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
163+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
164+
REPOSITORY: '${{ github.repository }}'
165+
REQUEST_TYPE: '${{ steps.get_context.outputs.request_type }}'
166+
run: |-
167+
set -euo pipefail
168+
MESSAGE="@${GITHUB_ACTOR} I've received your request and I'm working on it now! 🤖"
169+
if [[ -n "${MESSAGE}" ]]; then
170+
gh issue comment "${ISSUE_NUMBER}" \
171+
--body "${MESSAGE}" \
172+
--repo "${REPOSITORY}"
173+
fi
174+
175+
- name: 'Get description'
176+
id: 'get_description'
177+
env:
178+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
179+
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
180+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
181+
run: |-
182+
set -euo pipefail
183+
if [[ "${IS_PR}" == "true" ]]; then
184+
DESCRIPTION=$(gh pr view "${ISSUE_NUMBER}" --json body --template '{{.body}}')
185+
else
186+
DESCRIPTION=$(gh issue view "${ISSUE_NUMBER}" --json body --template '{{.body}}')
187+
fi
188+
{
189+
echo "description<<EOF"
190+
echo "${DESCRIPTION}"
191+
echo "EOF"
192+
} >> "${GITHUB_OUTPUT}"
193+
194+
- name: 'Get comments'
195+
id: 'get_comments'
196+
env:
197+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
198+
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
199+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
200+
run: |-
201+
set -euo pipefail
202+
if [[ "${IS_PR}" == "true" ]]; then
203+
COMMENTS=$(gh pr view "${ISSUE_NUMBER}" --json comments --template '{{range .comments}}{{.author.login}}: {{.body}}{{"\n"}}{{end}}')
204+
else
205+
COMMENTS=$(gh issue view "${ISSUE_NUMBER}" --json comments --template '{{range .comments}}{{.author.login}}: {{.body}}{{"\n"}}{{end}}')
206+
fi
207+
{
208+
echo "comments<<EOF"
209+
echo "${COMMENTS}"
210+
echo "EOF"
211+
} >> "${GITHUB_OUTPUT}"
212+
213+
- name: 'Run Gemini'
214+
id: 'run_gemini'
215+
uses: 'google-github-actions/run-gemini-cli@v0'
216+
env:
217+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
218+
REPOSITORY: '${{ github.repository }}'
219+
USER_REQUEST: '${{ steps.get_context.outputs.user_request }}'
220+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
221+
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
222+
with:
223+
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
224+
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
225+
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
226+
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
227+
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
228+
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
229+
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
230+
settings: |-
231+
{
232+
"debug": ${{ fromJSON(env.DEBUG || env.ACTIONS_STEP_DEBUG || false) }},
233+
"maxSessionTurns": 50,
234+
"telemetry": {
235+
"enabled": false,
236+
"target": "gcp"
237+
}
238+
}
239+
prompt: |-
240+
## Role
241+
242+
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.
243+
244+
## Context
245+
246+
- **Repository**: `${{ github.repository }}`
247+
- **Triggering Event**: `${{ github.event_name }}`
248+
- **Issue/PR Number**: `${{ steps.get_context.outputs.issue_number }}`
249+
- **Is this a PR?**: `${{ steps.get_context.outputs.is_pr }}`
250+
- **Issue/PR Description**:
251+
`${{ steps.get_description.outputs.description }}`
252+
- **Comments**:
253+
`${{ steps.get_comments.outputs.comments }}`
254+
255+
## User Request
256+
257+
The user has sent the following request:
258+
`${{ steps.get_context.outputs.user_request }}`
259+
260+
## How to Respond to Issues, PR Comments, and Questions
261+
262+
This workflow supports three main scenarios:
263+
264+
1. **Creating a Fix for an Issue**
265+
- Carefully read the user request and the related issue or PR description.
266+
- Use available tools to gather all relevant context (e.g., `gh issue view`, `gh pr view`, `gh pr diff`, `cat`, `head`, `tail`).
267+
- Identify the root cause of the problem before proceeding.
268+
- **Show and maintain a plan as a checklist**:
269+
- 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`).
270+
- Example:
271+
```
272+
### Plan
273+
- [ ] Investigate the root cause
274+
- [ ] Implement the fix in `file.py`
275+
- [ ] Add/modify tests
276+
- [ ] Update documentation
277+
- [ ] Verify the fix and close the issue
278+
```
279+
- Use: `gh pr comment "${ISSUE_NUMBER}" --body "<plan>"` or `gh issue comment "${ISSUE_NUMBER}" --body "<plan>"` to post the initial plan.
280+
- As you make progress, keep the checklist visible and up to date by editing the same comment (check off completed tasks with `- [x]`).
281+
- To update the checklist:
282+
1. Find the comment ID for the checklist (use `gh pr comment list "${ISSUE_NUMBER}"` or `gh issue comment list "${ISSUE_NUMBER}"`).
283+
2. Edit the comment with the updated checklist:
284+
- For PRs: `gh pr comment --edit <comment-id> --body "<updated plan>"`
285+
- For Issues: `gh issue comment --edit <comment-id> --body "<updated plan>"`
286+
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.
287+
- If the fix requires code changes, determine which files and lines are affected. If clarification is needed, note any questions for the user.
288+
- 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.
289+
- 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.
290+
- **Branching and Committing**:
291+
- **NEVER commit directly to the `main` branch.**
292+
- 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.
293+
- `git add .`
294+
- `git commit -m "feat: <describe the change>"`
295+
- `git push`
296+
- 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>`.
297+
- `git checkout -b issue/${ISSUE_NUMBER}/my-fix`
298+
- `git add .`
299+
- `git commit -m "feat: <describe the fix>"`
300+
- `git push origin issue/${ISSUE_NUMBER}/my-fix`
301+
- After pushing, you can create a pull request: `gh pr create --title "Fixes #${ISSUE_NUMBER}: <short title>" --body "This PR addresses issue #${ISSUE_NUMBER}."`
302+
- Summarize what was changed and why in a markdown file: `write_file("response.md", "<your response here>")`
303+
- Post the response as a comment:
304+
- For PRs: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
305+
- For Issues: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
306+
307+
2. **Addressing Comments on a Pull Request**
308+
- Read the specific comment and the context of the PR.
309+
- Use tools like `gh pr view`, `gh pr diff`, and `cat` to understand the code and discussion.
310+
- 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.
311+
- **Committing Changes**: The correct PR branch is already checked out. Simply add, commit, and push your changes.
312+
- `git add .`
313+
- `git commit -m "fix: address review comments"`
314+
- `git push`
315+
- If the comment is a question, answer it directly and clearly, referencing code or documentation as needed.
316+
- Document your response in `response.md` and post it as a PR comment: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
317+
318+
3. **Answering Any Question on an Issue**
319+
- Read the question and the full issue context using `gh issue view` and related tools.
320+
- Research or analyze the codebase as needed to provide an accurate answer.
321+
- 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.**
322+
- Write a clear, concise answer in `response.md` and post it as an issue comment: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
323+
324+
## Guidelines
325+
326+
- **Be concise and actionable.** Focus on solving the user's problem efficiently.
327+
- **Always commit and push your changes if you modify code or documentation.**
328+
- **If you are unsure about the fix or answer, explain your reasoning and ask clarifying questions.**
329+
- **Follow project conventions and best practices.**

0 commit comments

Comments
 (0)