Skip to content

Commit c391a3c

Browse files
authored
Merge pull request #3 from e-kotov/gemini-cli
add gemini cli
2 parents 863026b + 4077892 commit c391a3c

File tree

4 files changed

+1013
-0
lines changed

4 files changed

+1013
-0
lines changed

.github/workflows/gemini-cli.yml

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

0 commit comments

Comments
 (0)