Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions .github/actions/auto-pr-description/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# Auto PR Description Generator

A reusable GitHub Action that automatically generates pull request descriptions using AI (Google Gemini) based on the git diff of changes.

## Features

- 🤖 **AI-Powered**: Uses Google Gemini to analyze code changes and generate meaningful descriptions
- 🎯 **Smart Formatting**: Generates structured descriptions with Description, Changes, and Verification sections
- 🖼️ **Image Preservation**: Maintains existing images at the top of PR descriptions
- 🎫 **JIRA Integration**: Automatically extracts JIRA ticket IDs and adds ticket links
- ⚡ **Fast & Lightweight**: Minimal dependencies and quick execution

## Usage

### Basic Usage

```yaml
- name: Generate PR Description
uses: ./.github/actions/auto-pr-description
with:
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
github-token: ${{ secrets.GITHUB_TOKEN }}
pr-number: ${{ github.event.pull_request.number }}
```

### Complete Workflow Example

```yaml
name: Auto PR Description
on:
pull_request:
types: [labeled]

jobs:
update-pr-description:
name: Update PR Description
runs-on: ubuntu-latest
if: |
github.event_name == 'pull_request' &&
github.base_ref == 'main' &&
(github.event.pull_request.draft == false || github.event.action == 'labeled') &&
(contains(github.event.pull_request.labels.*.name, 'auto-pr-description') ||
contains(github.event.pull_request.labels.*.name, 'test'))
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4

- name: Generate PR Description
uses: ./.github/actions/auto-pr-description
with:
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
github-token: ${{ secrets.GITHUB_TOKEN }}
pr-number: ${{ github.event.pull_request.number }}
jira-ticket-url-prefix: 'https://yourcompany.atlassian.net/browse/'
```

## Inputs

| Input | Description | Required | Default |
|-------|-------------|----------|---------|
| `gemini-api-key` | The API key for the Gemini API | ✅ | - |
| `github-token` | GitHub token for PR operations | ✅ | - |
| `pr-number` | Pull request number | ✅ | - |
| `jira-ticket-url-prefix` | JIRA ticket URL prefix | ❌ | `https://virdocs.atlassian.net/browse/` |

## Outputs

| Output | Description |
|--------|-------------|
| `description` | The generated PR description |
| `updated` | Whether the PR description was updated |

## Generated Description Format

The action generates PR descriptions in this structured format:

```markdown
## Description
A concise summary of what the changes accomplish.

## Changes
- [ ] Specific change or feature added
- [ ] Another modification made
- [ ] Bug fix or improvement

## Verification
- [ ] Test that should be performed
- [ ] Verification step to confirm functionality
- [ ] Additional checks recommended

## Ticket
https://yourcompany.atlassian.net/browse/TICKET-123
```

## JIRA Integration

The action automatically detects JIRA ticket IDs from:
1. **PR Title**: Extracts patterns like `CORE-1234`, `PAR-567`, etc.
2. **Branch Name**: Falls back to branch name if not found in title

Example branch names that work:
- `CORE-1234-feature-description`
- `PAR-567-bug-fix`
- `feature/CORE-1234-new-feature`

## Prerequisites

### Required Secrets

1. **GEMINI_API_KEY**: Get your API key from [Google AI Studio](https://makersuite.google.com/app/apikey)
2. **GITHUB_TOKEN**: Automatically provided by GitHub Actions

### Required Permissions

The workflow must have these permissions:
```yaml
permissions:
pull-requests: write
contents: read
```

## Trigger Patterns

### Label-Based Triggering
Add these labels to trigger the action:
- `auto-pr-description`: Specific label for PR description generation
- `test`: Dual-purpose label that can trigger both testing and description generation

### Draft Mode Handling
- **Draft PRs**: Action doesn't run automatically to save CI resources
- **Label Override**: Adding trigger labels to draft PRs will run the action
- **Ready for Review**: Converting draft to ready automatically triggers the action

## Error Handling

The action handles various error scenarios:
- Missing or invalid Gemini API key
- API rate limits and timeouts
- Large diffs that exceed API limits
- Network connectivity issues
- Invalid PR numbers

## Customization

### Custom JIRA URL
```yaml
- uses: ./.github/actions/auto-pr-description
with:
jira-ticket-url-prefix: 'https://mycompany.atlassian.net/browse/'
# ... other inputs
```

### Using Outputs
```yaml
- name: Generate PR Description
id: pr-desc
uses: ./.github/actions/auto-pr-description
with:
# ... inputs

- name: Use generated description
run: |
echo "Generated description: ${{ steps.pr-desc.outputs.description }}"
echo "Was updated: ${{ steps.pr-desc.outputs.updated }}"
```

## Troubleshooting

### Common Issues

1. **Missing API Key**: Ensure `GEMINI_API_KEY` is set in repository secrets
2. **Permission Denied**: Check that workflow has `pull-requests: write` permission
3. **Large Diffs**: Very large changes might exceed API limits - consider smaller PRs
4. **Rate Limits**: Gemini API has rate limits - add delays between calls if needed
5. **Invalid PR Number**: Ensure the PR number is valid and accessible

### Debug Mode

Enable debug logging by setting:
```yaml
env:
ACTIONS_STEP_DEBUG: true
```

## License

MIT License - see LICENSE file for details.
96 changes: 96 additions & 0 deletions .github/actions/auto-pr-description/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Auto PR Description Generator
description: Automatically generate pull request descriptions using AI based on git diff
inputs:
gemini-api-key:
description: 'The API key for the Gemini API'
required: true
github-token:
description: 'GitHub token for PR operations'
required: true
pr-number:
description: 'Pull request number'
required: true
jira-ticket-url-prefix:
description: 'JIRA ticket URL prefix (e.g., https://company.atlassian.net/browse/)'
required: false
default: 'https://virdocs.atlassian.net/browse/'
outputs:
description:
description: 'The generated PR description'
value: ${{ steps.generate_description.outputs.description }}
updated:
description: 'Whether the PR description was updated'
value: ${{ steps.update_pr.outputs.updated }}

runs:
using: 'composite'
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22.x'

- name: Install dependencies
shell: bash
run: |
npm install
working-directory: ${{ github.action_path }}

- name: Generate PR diff from GitHub
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
PR_NUMBER: ${{ inputs.pr-number }}
run: |
# Get the PR diff directly from GitHub using gh CLI
gh pr diff ${{ inputs.pr-number }} > pr.diff
echo "Generated diff file with $(wc -l < pr.diff) lines"

- name: Generate PR description
id: generate_description
shell: bash
env:
GEMINI_API_KEY: ${{ inputs.gemini-api-key }}
GH_TOKEN: ${{ inputs.github-token }}
PR_NUMBER: ${{ inputs.pr-number }}
JIRA_TICKET_URL_PREFIX: ${{ inputs.jira-ticket-url-prefix }}
run: |
# Generate description using AI
DESCRIPTION=$(node ${{ github.action_path }}/generate_pr_description.js pr.diff)

# Get existing PR body to check for images
FIRST_LINE=$(gh pr view ${{ inputs.pr-number }} --json body --jq '.body' | head -n 1)

# Preserve images if they exist at the beginning
if echo "$FIRST_LINE" | grep -qE '^(<img[^>]*>[[:space:]]*|!\[[^]]*\]\([^)]*\))$'; then
printf '%s\n\n%s\n' "$FIRST_LINE" "$DESCRIPTION" > pr_body.md
else
printf '%s\n' "$DESCRIPTION" > pr_body.md
fi

# Add JIRA ticket link if found
PR_TITLE=$(gh pr view ${{ inputs.pr-number }} --json title --jq '.title')
TICKET_ID=$(echo "$PR_TITLE" | grep -oE '[A-Z]+-[0-9]+' || true)
if [ -z "$TICKET_ID" ]; then
TICKET_ID=$(echo "$GITHUB_HEAD_REF" | grep -oE '[A-Z]+-[0-9]+' || true)
fi
if [ -n "$TICKET_ID" ]; then
TICKET_URL="${{ inputs.jira-ticket-url-prefix }}${TICKET_ID}"
printf '\n## Ticket\n%s\n' "$TICKET_URL" >> pr_body.md
fi

# Output the description for other steps to use
echo "description<<EOF" >> $GITHUB_OUTPUT
cat pr_body.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Update PR description
id: update_pr
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
PR_NUMBER: ${{ inputs.pr-number }}
run: |
gh pr edit ${{ inputs.pr-number }} --body-file pr_body.md
echo "updated=true" >> $GITHUB_OUTPUT
echo "Successfully updated PR #${{ inputs.pr-number }} description"
Loading