Skip to content

Commit 561f95b

Browse files
galdawavesethvargojerop
authored
feat: Add generic workflow and example (gemini-cli) (#13)
* Generic Prompting: Unlike the specialized /review or /triage slash commands, the `@gemini-cli` command is designed for general-purpose interaction. Users can ask any question or give any instruction, and the CLI will process it. * `examples/gemini-cli.yml`: A new workflow that triggers on PR comments containing `@gemini-cli`. It checks out the PR branch, runs the Gemini CLI with the comment body as the user request, and pushes any resulting code changes back to the branch. * `.gitignore`: Updated to ignore temporary gha-creds-*.json files generated by the create-github-app-token action. --------- Co-authored-by: Seth Vargo <seth@sethvargo.com> Co-authored-by: Jerop Kipruto <jerop@google.com>
1 parent 04eecce commit 561f95b

4 files changed

Lines changed: 673 additions & 0 deletions

File tree

.github/workflows/gemini-cli.yml

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
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.head_ref || github.ref || github.event.issue.number }}'
16+
cancel-in-progress: true
17+
18+
defaults:
19+
run:
20+
shell: 'bash'
21+
22+
permissions:
23+
contents: 'write'
24+
id-token: 'write'
25+
pull-requests: 'write'
26+
issues: 'write'
27+
28+
jobs:
29+
gemini-cli:
30+
# This condition is complex to ensure we only run when explicitly invoked.
31+
if: |
32+
github.event_name == 'workflow_dispatch' ||
33+
(
34+
github.event_name == 'issues' && github.event.action == 'opened' &&
35+
contains(github.event.issue.body, '@gemini-cli') &&
36+
!contains(github.event.issue.body, '/review') &&
37+
!contains(github.event.issue.body, '/triage') &&
38+
(
39+
github.event.sender.type == 'User' && (
40+
github.event.issue.author_association == 'OWNER' ||
41+
github.event.issue.author_association == 'MEMBER' ||
42+
github.event.issue.author_association == 'COLLABORATOR'
43+
)
44+
)
45+
) ||
46+
(
47+
github.event_name == 'issue_comment' &&
48+
contains(github.event.comment.body, '@gemini-cli') &&
49+
!contains(github.event.comment.body, '/review') &&
50+
!contains(github.event.comment.body, '/triage') &&
51+
(
52+
github.event.sender.type == 'User' && (
53+
github.event.comment.author_association == 'OWNER' ||
54+
github.event.comment.author_association == 'MEMBER' ||
55+
github.event.comment.author_association == 'COLLABORATOR'
56+
)
57+
)
58+
) ||
59+
(
60+
github.event_name == 'pull_request_review' &&
61+
contains(github.event.review.body, '@gemini-cli') &&
62+
!contains(github.event.review.body, '/review') &&
63+
!contains(github.event.review.body, '/triage') &&
64+
(
65+
github.event.sender.type == 'User' && (
66+
github.event.review.author_association == 'OWNER' ||
67+
github.event.review.author_association == 'MEMBER' ||
68+
github.event.review.author_association == 'COLLABORATOR'
69+
)
70+
)
71+
) ||
72+
(
73+
github.event_name == 'pull_request_review_comment' &&
74+
contains(github.event.comment.body, '@gemini-cli') &&
75+
!contains(github.event.comment.body, '/review') &&
76+
!contains(github.event.comment.body, '/triage') &&
77+
(
78+
github.event.sender.type == 'User' && (
79+
github.event.comment.author_association == 'OWNER' ||
80+
github.event.comment.author_association == 'MEMBER' ||
81+
github.event.comment.author_association == 'COLLABORATOR'
82+
)
83+
)
84+
)
85+
timeout-minutes: 15
86+
runs-on: 'ubuntu-latest'
87+
88+
steps:
89+
- name: 'Generate GitHub App Token'
90+
id: 'generate_token'
91+
if: |-
92+
${{ vars.APP_ID }}
93+
uses: 'actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e' # ratchet:actions/create-github-app-token@v2
94+
with:
95+
app-id: '${{ vars.APP_ID }}'
96+
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
97+
98+
- name: 'Get context from event'
99+
id: 'get_context'
100+
env:
101+
EVENT_NAME: '${{ github.event_name }}'
102+
EVENT_PAYLOAD: '${{ toJSON(github.event) }}'
103+
run: |-
104+
set -euo pipefail
105+
106+
USER_REQUEST=""
107+
ISSUE_NUMBER=""
108+
IS_PR="false"
109+
110+
if [[ "${EVENT_NAME}" == "issues" ]]; then
111+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.body)
112+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
113+
elif [[ "${EVENT_NAME}" == "issue_comment" ]]; then
114+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
115+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
116+
if [[ $(echo "${EVENT_PAYLOAD}" | jq -r .issue.pull_request) != "null" ]]; then
117+
IS_PR="true"
118+
fi
119+
elif [[ "${EVENT_NAME}" == "pull_request_review" ]]; then
120+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .review.body)
121+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .pull_request.number)
122+
IS_PR="true"
123+
elif [[ "${EVENT_NAME}" == "pull_request_review_comment" ]]; then
124+
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
125+
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .pull_request.number)
126+
IS_PR="true"
127+
fi
128+
129+
# Clean up user request
130+
USER_REQUEST=$(echo "${USER_REQUEST}" | sed 's/.*@gemini-cli//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
131+
132+
{
133+
echo "user_request=${USER_REQUEST}"
134+
echo "issue_number=${ISSUE_NUMBER}"
135+
echo "is_pr=${IS_PR}"
136+
} >> "${GITHUB_OUTPUT}"
137+
138+
- name: 'Checkout PR branch'
139+
if: |-
140+
${{ steps.get_context.outputs.is_pr == 'true' }}
141+
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
142+
with:
143+
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
144+
repository: '${{ github.repository }}'
145+
ref: 'refs/pull/${{ steps.get_context.outputs.issue_number }}/head'
146+
fetch-depth: 0
147+
148+
- name: 'Checkout main branch'
149+
if: |-
150+
${{ steps.get_context.outputs.is_pr == 'false' }}
151+
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
152+
with:
153+
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
154+
repository: '${{ github.repository }}'
155+
fetch-depth: 0
156+
157+
- name: 'Acknowledge request'
158+
env:
159+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
160+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
161+
REPOSITORY: '${{ github.repository }}'
162+
run: |-
163+
gh issue comment "${ISSUE_NUMBER}" \
164+
--body "I've received your request and I'm working on it now! 🤖" \
165+
--repo "${REPOSITORY}"
166+
167+
- name: 'Run Gemini'
168+
uses: './'
169+
env:
170+
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
171+
REPOSITORY: '${{ github.repository }}'
172+
USER_REQUEST: '${{ steps.get_context.outputs.user_request }}'
173+
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
174+
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
175+
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
176+
OTLP_GCP_WIF_PROVIDER: '${{ vars.OTLP_GCP_WIF_PROVIDER }}'
177+
OTLP_GOOGLE_CLOUD_PROJECT: '${{ vars.OTLP_GOOGLE_CLOUD_PROJECT }}'
178+
with:
179+
settings_json: |
180+
{
181+
"coreTools": [
182+
"run_shell_command(echo)",
183+
"run_shell_command(gh pr view)",
184+
"run_shell_command(gh pr diff)",
185+
"run_shell_command(gh pr list)",
186+
"run_shell_command(gh issue view)",
187+
"run_shell_command(gh issue comment)",
188+
"run_shell_command(gh issue list)",
189+
"run_shell_command(gh pr comment)",
190+
"run_shell_command(cat)",
191+
"run_shell_command(head)",
192+
"run_shell_command(tail)",
193+
"run_shell_command(grep)",
194+
"run_shell_command(git config)",
195+
"run_shell_command(git status)",
196+
"run_shell_command(git add)",
197+
"run_shell_command(git commit)",
198+
"run_shell_command(git push)",
199+
"run_shell_command(git diff)",
200+
"write_file"
201+
],
202+
"telemetry": {
203+
"enabled": true,
204+
"target": "gcp"
205+
},
206+
"sandbox": false
207+
}
208+
prompt: |
209+
## Role
210+
211+
You are a helpful AI assistant invoked via a CLI interface in a GitHub workflow.
212+
You have access to tools to interact with the repository and respond to the user.
213+
214+
## Context
215+
216+
- **Repository**: `${{ github.repository }}`
217+
- **Triggering Event**: `${{ github.event_name }}`
218+
- **Issue/PR Number**: `${{ steps.get_context.outputs.issue_number }}`
219+
- **Is this a PR?**: `${{ steps.get_context.outputs.is_pr }}`
220+
221+
## User Request
222+
223+
The user has sent the following request:
224+
`${{ steps.get_context.outputs.user_request }}`
225+
226+
## Steps
227+
228+
1. **Understand the context.** Use the available tools to gather information about the issue or PR.
229+
- For PRs, you can use `gh pr view "${ISSUE_NUMBER}"`, `gh pr diff "${ISSUE_NUMBER}"` and `gh pr list`.
230+
- For issues, you can use `gh issue view "${ISSUE_NUMBER}"` or `gh issue list` to list all issues.
231+
- To view file contents, use `cat`, `head`, or `tail`.
232+
- The code has been checked out for you if this is a PR.
233+
234+
2. **Fulfill the user's request.** The request is: `${{ steps.get_context.outputs.user_request }}`.
235+
- If the request involves modifying code, use `write_file` or other tools to make the changes.
236+
- After making changes, you **MUST** commit them.
237+
- `git add .`
238+
- `git commit -m "Your descriptive commit message"`
239+
- `git push`
240+
241+
3. **Respond to the user.**
242+
- Write your final response in a markdown file: `write_file("response.md", "<your response here>")`
243+
- Post the response as a comment:
244+
- For PRs: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
245+
- For Issues: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
246+
247+
## Guidelines
248+
249+
- **Be concise.** Provide the information or perform the action requested without unnecessary chatter.
250+
- **Reference all shell variables as `"${VAR}"`** (with quotes and braces) to prevent errors.
251+
- **If you make changes, always commit and push them.**

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,6 @@ Thumbs.db
6262

6363
# gemini-cli settings
6464
.gemini/
65+
66+
# GitHub App credentials
67+
gha-creds-*.json

0 commit comments

Comments
 (0)