Skip to content

Commit 197e866

Browse files
fix: πŸ› use gh to pull diff (#108)
βœ… Closes: CORE-246
1 parent 93a38ac commit 197e866

3 files changed

Lines changed: 344 additions & 23 deletions

File tree

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Auto PR Description Generator
2+
3+
A reusable GitHub Action that automatically generates pull request descriptions using AI (Google Gemini) based on the git diff of changes.
4+
5+
## Features
6+
7+
- πŸ€– **AI-Powered**: Uses Google Gemini to analyze code changes and generate meaningful descriptions
8+
- 🎯 **Smart Formatting**: Generates structured descriptions with Description, Changes, and Verification sections
9+
- πŸ–ΌοΈ **Image Preservation**: Maintains existing images at the top of PR descriptions
10+
- 🎫 **JIRA Integration**: Automatically extracts JIRA ticket IDs and adds ticket links
11+
- ⚑ **Fast & Lightweight**: Minimal dependencies and quick execution
12+
13+
## Usage
14+
15+
### Basic Usage
16+
17+
```yaml
18+
- name: Generate PR Description
19+
uses: ./.github/actions/auto-pr-description
20+
with:
21+
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
22+
github-token: ${{ secrets.GITHUB_TOKEN }}
23+
pr-number: ${{ github.event.pull_request.number }}
24+
```
25+
26+
### Complete Workflow Example
27+
28+
```yaml
29+
name: Auto PR Description
30+
on:
31+
pull_request:
32+
types: [labeled]
33+
34+
jobs:
35+
update-pr-description:
36+
name: Update PR Description
37+
runs-on: ubuntu-latest
38+
if: |
39+
github.event_name == 'pull_request' &&
40+
github.base_ref == 'main' &&
41+
(github.event.pull_request.draft == false || github.event.action == 'labeled') &&
42+
(contains(github.event.pull_request.labels.*.name, 'auto-pr-description') ||
43+
contains(github.event.pull_request.labels.*.name, 'test'))
44+
permissions:
45+
pull-requests: write
46+
contents: read
47+
steps:
48+
- uses: actions/checkout@v4
49+
50+
- name: Generate PR Description
51+
uses: ./.github/actions/auto-pr-description
52+
with:
53+
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
54+
github-token: ${{ secrets.GITHUB_TOKEN }}
55+
pr-number: ${{ github.event.pull_request.number }}
56+
jira-ticket-url-prefix: 'https://yourcompany.atlassian.net/browse/'
57+
```
58+
59+
## Inputs
60+
61+
| Input | Description | Required | Default |
62+
|-------|-------------|----------|---------|
63+
| `gemini-api-key` | The API key for the Gemini API | βœ… | - |
64+
| `github-token` | GitHub token for PR operations | βœ… | - |
65+
| `pr-number` | Pull request number | βœ… | - |
66+
| `jira-ticket-url-prefix` | JIRA ticket URL prefix | ❌ | `https://virdocs.atlassian.net/browse/` |
67+
68+
## Outputs
69+
70+
| Output | Description |
71+
|--------|-------------|
72+
| `description` | The generated PR description |
73+
| `updated` | Whether the PR description was updated |
74+
75+
## Generated Description Format
76+
77+
The action generates PR descriptions in this structured format:
78+
79+
```markdown
80+
## Description
81+
A concise summary of what the changes accomplish.
82+
83+
## Changes
84+
- [ ] Specific change or feature added
85+
- [ ] Another modification made
86+
- [ ] Bug fix or improvement
87+
88+
## Verification
89+
- [ ] Test that should be performed
90+
- [ ] Verification step to confirm functionality
91+
- [ ] Additional checks recommended
92+
93+
## Ticket
94+
https://yourcompany.atlassian.net/browse/TICKET-123
95+
```
96+
97+
## JIRA Integration
98+
99+
The action automatically detects JIRA ticket IDs from:
100+
1. **PR Title**: Extracts patterns like `CORE-1234`, `PAR-567`, etc.
101+
2. **Branch Name**: Falls back to branch name if not found in title
102+
103+
Example branch names that work:
104+
- `CORE-1234-feature-description`
105+
- `PAR-567-bug-fix`
106+
- `feature/CORE-1234-new-feature`
107+
108+
## Prerequisites
109+
110+
### Required Secrets
111+
112+
1. **GEMINI_API_KEY**: Get your API key from [Google AI Studio](https://makersuite.google.com/app/apikey)
113+
2. **GITHUB_TOKEN**: Automatically provided by GitHub Actions
114+
115+
### Required Permissions
116+
117+
The workflow must have these permissions:
118+
```yaml
119+
permissions:
120+
pull-requests: write
121+
contents: read
122+
```
123+
124+
## Trigger Patterns
125+
126+
### Label-Based Triggering
127+
Add these labels to trigger the action:
128+
- `auto-pr-description`: Specific label for PR description generation
129+
- `test`: Dual-purpose label that can trigger both testing and description generation
130+
131+
### Draft Mode Handling
132+
- **Draft PRs**: Action doesn't run automatically to save CI resources
133+
- **Label Override**: Adding trigger labels to draft PRs will run the action
134+
- **Ready for Review**: Converting draft to ready automatically triggers the action
135+
136+
## Error Handling
137+
138+
The action handles various error scenarios:
139+
- Missing or invalid Gemini API key
140+
- API rate limits and timeouts
141+
- Large diffs that exceed API limits
142+
- Network connectivity issues
143+
- Invalid PR numbers
144+
145+
## Customization
146+
147+
### Custom JIRA URL
148+
```yaml
149+
- uses: ./.github/actions/auto-pr-description
150+
with:
151+
jira-ticket-url-prefix: 'https://mycompany.atlassian.net/browse/'
152+
# ... other inputs
153+
```
154+
155+
### Using Outputs
156+
```yaml
157+
- name: Generate PR Description
158+
id: pr-desc
159+
uses: ./.github/actions/auto-pr-description
160+
with:
161+
# ... inputs
162+
163+
- name: Use generated description
164+
run: |
165+
echo "Generated description: ${{ steps.pr-desc.outputs.description }}"
166+
echo "Was updated: ${{ steps.pr-desc.outputs.updated }}"
167+
```
168+
169+
## Troubleshooting
170+
171+
### Common Issues
172+
173+
1. **Missing API Key**: Ensure `GEMINI_API_KEY` is set in repository secrets
174+
2. **Permission Denied**: Check that workflow has `pull-requests: write` permission
175+
3. **Large Diffs**: Very large changes might exceed API limits - consider smaller PRs
176+
4. **Rate Limits**: Gemini API has rate limits - add delays between calls if needed
177+
5. **Invalid PR Number**: Ensure the PR number is valid and accessible
178+
179+
### Debug Mode
180+
181+
Enable debug logging by setting:
182+
```yaml
183+
env:
184+
ACTIONS_STEP_DEBUG: true
185+
```
186+
187+
## License
188+
189+
MIT License - see LICENSE file for details.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: Auto PR Description Generator
2+
description: Automatically generate pull request descriptions using AI based on git diff
3+
inputs:
4+
gemini-api-key:
5+
description: 'The API key for the Gemini API'
6+
required: true
7+
github-token:
8+
description: 'GitHub token for PR operations'
9+
required: true
10+
pr-number:
11+
description: 'Pull request number'
12+
required: true
13+
jira-ticket-url-prefix:
14+
description: 'JIRA ticket URL prefix (e.g., https://company.atlassian.net/browse/)'
15+
required: false
16+
default: 'https://virdocs.atlassian.net/browse/'
17+
outputs:
18+
description:
19+
description: 'The generated PR description'
20+
value: ${{ steps.generate_description.outputs.description }}
21+
updated:
22+
description: 'Whether the PR description was updated'
23+
value: ${{ steps.update_pr.outputs.updated }}
24+
25+
runs:
26+
using: 'composite'
27+
steps:
28+
- name: Setup Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: '22.x'
32+
33+
- name: Install dependencies
34+
shell: bash
35+
run: |
36+
npm install
37+
working-directory: ${{ github.action_path }}
38+
39+
- name: Generate PR diff from GitHub
40+
shell: bash
41+
env:
42+
GH_TOKEN: ${{ inputs.github-token }}
43+
PR_NUMBER: ${{ inputs.pr-number }}
44+
run: |
45+
# Get the PR diff directly from GitHub using gh CLI
46+
gh pr diff ${{ inputs.pr-number }} > pr.diff
47+
echo "Generated diff file with $(wc -l < pr.diff) lines"
48+
49+
- name: Generate PR description
50+
id: generate_description
51+
shell: bash
52+
env:
53+
GEMINI_API_KEY: ${{ inputs.gemini-api-key }}
54+
GH_TOKEN: ${{ inputs.github-token }}
55+
PR_NUMBER: ${{ inputs.pr-number }}
56+
JIRA_TICKET_URL_PREFIX: ${{ inputs.jira-ticket-url-prefix }}
57+
run: |
58+
# Generate description using AI
59+
DESCRIPTION=$(node ${{ github.action_path }}/generate_pr_description.js pr.diff)
60+
61+
# Get existing PR body to check for images
62+
FIRST_LINE=$(gh pr view ${{ inputs.pr-number }} --json body --jq '.body' | head -n 1)
63+
64+
# Preserve images if they exist at the beginning
65+
if echo "$FIRST_LINE" | grep -qE '^(<img[^>]*>[[:space:]]*|!\[[^]]*\]\([^)]*\))$'; then
66+
printf '%s\n\n%s\n' "$FIRST_LINE" "$DESCRIPTION" > pr_body.md
67+
else
68+
printf '%s\n' "$DESCRIPTION" > pr_body.md
69+
fi
70+
71+
# Add JIRA ticket link if found
72+
PR_TITLE=$(gh pr view ${{ inputs.pr-number }} --json title --jq '.title')
73+
TICKET_ID=$(echo "$PR_TITLE" | grep -oE '[A-Z]+-[0-9]+' || true)
74+
if [ -z "$TICKET_ID" ]; then
75+
TICKET_ID=$(echo "$GITHUB_HEAD_REF" | grep -oE '[A-Z]+-[0-9]+' || true)
76+
fi
77+
if [ -n "$TICKET_ID" ]; then
78+
TICKET_URL="${{ inputs.jira-ticket-url-prefix }}${TICKET_ID}"
79+
printf '\n## Ticket\n%s\n' "$TICKET_URL" >> pr_body.md
80+
fi
81+
82+
# Output the description for other steps to use
83+
echo "description<<EOF" >> $GITHUB_OUTPUT
84+
cat pr_body.md >> $GITHUB_OUTPUT
85+
echo "EOF" >> $GITHUB_OUTPUT
86+
87+
- name: Update PR description
88+
id: update_pr
89+
shell: bash
90+
env:
91+
GH_TOKEN: ${{ inputs.github-token }}
92+
PR_NUMBER: ${{ inputs.pr-number }}
93+
run: |
94+
gh pr edit ${{ inputs.pr-number }} --body-file pr_body.md
95+
echo "updated=true" >> $GITHUB_OUTPUT
96+
echo "Successfully updated PR #${{ inputs.pr-number }} description"

0 commit comments

Comments
Β (0)