Generate a changelog from merged PRs using conventional commits format.
/plugin marketplace add el-feo/ai-context/plugin install ghpm@jebs-dev-toolsDefault behavior:
from provided, uses the most recent tag<usage_examples> Generate changelog since last tag:
/ghpm:changelog
Generate changelog between versions:
/ghpm:changelog from=v1.0.0 to=v1.1.0
Generate changelog to specific file:
/ghpm:changelog output=docs/CHANGELOG.md
Generate changelog from date:
/ghpm:changelog from=2024-01-01
</usage_examples>
<operating_rules>
<changelog_format>
# Changelog
## [Unreleased] OR [vX.Y.Z] - YYYY-MM-DD
### Breaking Changes
- **scope:** description (#PR) @contributor
### Features
- **scope:** description (#PR) @contributor
### Bug Fixes
- **scope:** description (#PR) @contributor
### Performance
- **scope:** description (#PR) @contributor
### Code Refactoring
- **scope:** description (#PR) @contributor
### Documentation
- **scope:** description (#PR) @contributor
### Testing
- **scope:** description (#PR) @contributor
### Maintenance
- **scope:** description (#PR) @contributor
| Commit Type | Changelog Section |
|---|---|
feat | Features |
fix | Bug Fixes |
perf | Performance |
refactor | Code Refactoring |
docs | Documentation |
test | Testing |
chore | Maintenance |
build | Maintenance |
ci | Maintenance |
style | (excluded) |
revert | Reverts |
</changelog_format>
<workflow># Get most recent tag if from not specified
FROM_REF="${FROM:-$(git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)}"
TO_REF="${TO:-HEAD}"
echo "Generating changelog from $FROM_REF to $TO_REF"
# Get merged PRs in range
gh pr list \
--state merged \
--base main \
--json number,title,author,mergedAt,labels \
--jq '.[] | select(.mergedAt >= "'$FROM_DATE'")' \
> /tmp/prs.json
Alternatively, parse git log:
git log "$FROM_REF".."$TO_REF" --oneline --format="%s|%h|%an" > /tmp/commits.txt
For each PR title or commit message, extract:
feat, fix, refactor, etc.! after type or BREAKING CHANGE: in body(#123) referenceRegex pattern:
^(feat|fix|refactor|perf|test|docs|chore|build|ci|style|revert)(\(.+\))?(!)?:\s*(.+?)(?:\s*\(#(\d+)\))?$
Organize parsed commits into sections:
breaking_changes = []
features = []
fixes = []
performance = []
refactoring = []
documentation = []
testing = []
maintenance = []
reverts = []
Build markdown content with:
to ref or "Unreleased")- **scope:** description (#PR) @authorOUTPUT_FILE="${OUTPUT:-CHANGELOG.md}"
# If file exists, insert new content after header
# Otherwise create new file
# Write content
cat > "$OUTPUT_FILE" << 'EOF'
# Changelog
<generated content>
EOF
If prepending to existing changelog:
# Read existing content (skip header)
EXISTING=$(tail -n +3 "$OUTPUT_FILE")
# Write new content + existing
cat > "$OUTPUT_FILE" << EOF
# Changelog
<new version content>
$EXISTING
EOF
</workflow>
<error_handling> If no conventional commits found:
If no PRs in range:
If output file not writable:
<success_criteria> Command completes successfully when:
Output summary:
Changelog generated:
- Range: v1.0.0..HEAD
- PRs processed: 15
- Features: 5
- Bug Fixes: 3
- Refactoring: 4
- Other: 3
- Output: CHANGELOG.md
</success_criteria>
Proceed now.