Skip to content

Commit 6aa472d

Browse files
Automate changelog updates on PR merge (#874)
Manual changelog updates cause merge delays and missing entries. This PR automates the process using GitHub Actions. ## Implementation **Workflow** (`.github/workflows/update-changelog.yml`) - Triggers on PR merge to `main` - Maps PR labels to changelog categories (bug→Fixed, enhancement→Added, etc.) - Inserts entry under appropriate category in Unreleased section - Commits directly to main - Uses standalone script for better maintainability and testing **Standalone Script** (`bin/update-changelog.sh`) - Extracted awk logic into a reusable bash script - Can be run locally for testing: `./bin/update-changelog.sh "PR Title" "123" "Fixed"` - Includes error handling and CHANGELOG.md validation - Portable shebang (`#!/usr/bin/env bash`) for cross-platform compatibility - Contains built-in help text when called without arguments **Label Mapping** ``` bug|fix → Fixed enhancement|feature|added → Added changed → Changed deprecated → Deprecated removed → Removed security → Security breaking → Changed (default) → Changed ``` **Documentation** (`CONTRIBUTING.md`) - Added Pull Requests section documenting the automation - Contributors no longer need to update CHANGELOG.md manually - PR title becomes the changelog entry ## Technical Details The awk script handles: - Inserting into existing categories (newest-first ordering) - Creating new categories when needed - Empty Unreleased sections Entry format matches Keep a Changelog spec: ``` - PR title ([#123](url)) ``` ## Developer Benefits - **Easy local testing**: Test changelog updates before pushing changes - **Better maintainability**: Script logic separated from workflow YAML - **Improved debugging**: Standalone script is easier to test and modify <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>Automate changelog entry once PR is merged</issue_title> > <issue_description>In order to have a up to date changelog I've been asking people to add an entry or add it myself. This is causing delays in getting PR's merged or a missing changelog entry if missed. > > This should be solvable using GitHub actions e.g. https://github.com/claudiodekker/changelog-updater?tab=readme-ov-file</issue_description> > > <agent_instructions>The goal is to have people create PR's without having to go back to their changes add an entry to the changelog.md with the correct PR number and put it under the correct type of change. > > Create a github workflow that once merged into main it starts and adds an entry to the cahanglog in the format this repo is using.</agent_instructions> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > </comments> > </details> <!-- START COPILOT CODING AGENT SUFFIX --> - Fixes #862 <!-- START COPILOT CODING AGENT TIPS --> --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: DannyvdSluijs <618940+DannyvdSluijs@users.noreply.github.com>
1 parent c92cd56 commit 6aa472d

File tree

4 files changed

+211
-0
lines changed

4 files changed

+211
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: "Update Changelog"
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
branches:
7+
- main
8+
9+
jobs:
10+
update-changelog:
11+
name: "Update CHANGELOG.md"
12+
if: github.event.pull_request.merged == true
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: write
16+
pull-requests: read
17+
18+
steps:
19+
- name: "Checkout"
20+
uses: "actions/checkout@v4"
21+
with:
22+
ref: main
23+
fetch-depth: 0
24+
25+
- name: "Determine changelog category from labels"
26+
id: category
27+
run: |
28+
# Get PR labels
29+
LABELS=$(cat <<'EOF'
30+
${{ toJson(github.event.pull_request.labels.*.name) }}
31+
EOF
32+
)
33+
34+
echo "Labels: $LABELS"
35+
36+
# Determine category based on labels
37+
# Priority order: breaking -> added -> changed -> deprecated -> removed -> fixed -> security
38+
if echo "$LABELS" | grep -qi "breaking"; then
39+
CATEGORY="Changed"
40+
elif echo "$LABELS" | grep -qi "enhancement\|feature\|added"; then
41+
CATEGORY="Added"
42+
elif echo "$LABELS" | grep -qi "changed"; then
43+
CATEGORY="Changed"
44+
elif echo "$LABELS" | grep -qi "deprecated"; then
45+
CATEGORY="Deprecated"
46+
elif echo "$LABELS" | grep -qi "removed"; then
47+
CATEGORY="Removed"
48+
elif echo "$LABELS" | grep -qi "bug\|fix"; then
49+
CATEGORY="Fixed"
50+
elif echo "$LABELS" | grep -qi "security"; then
51+
CATEGORY="Security"
52+
else
53+
# Default category if no matching label
54+
CATEGORY="Changed"
55+
fi
56+
57+
echo "category=$CATEGORY" >> $GITHUB_OUTPUT
58+
echo "Determined category: $CATEGORY"
59+
60+
- name: "Update CHANGELOG.md"
61+
run: |
62+
PR_TITLE="${{ github.event.pull_request.title }}"
63+
PR_NUMBER="${{ github.event.pull_request.number }}"
64+
CATEGORY="${{ steps.category.outputs.category }}"
65+
66+
# Use the standalone script to update the changelog
67+
export GITHUB_REPOSITORY_URL="https://github.com/${{ github.repository }}"
68+
./bin/update-changelog.sh "$PR_TITLE" "$PR_NUMBER" "$CATEGORY"
69+
70+
- name: "Commit and push changes"
71+
run: |
72+
git config user.name "github-actions[bot]"
73+
git config user.email "github-actions[bot]@users.noreply.github.com"
74+
75+
if git diff --quiet CHANGELOG.md; then
76+
echo "No changes to CHANGELOG.md"
77+
exit 0
78+
fi
79+
80+
git add CHANGELOG.md
81+
git commit -m "docs: Update CHANGELOG.md for PR #${{ github.event.pull_request.number }}"
82+
git push origin main

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/vendor
22
/bin
33
!/bin/validate-json
4+
!/bin/update-changelog.sh
45
coverage
56
.buildpath
67
.project

CONTRIBUTING.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ All types of contributions are encouraged and valued. See the [Table of Contents
1616
- [I Want To Contribute](#i-want-to-contribute)
1717
- [Reporting Bugs](#reporting-bugs)
1818
- [Suggesting Enhancements](#suggesting-enhancements)
19+
- [Pull Requests](#pull-requests)
1920

2021
## I Have a Question
2122

@@ -90,6 +91,34 @@ Enhancement suggestions are tracked as [GitHub issues](https://github.com/jsonra
9091
- You may want to **include screenshots or screen recordings** which help you demonstrate the steps or point out the part which the suggestion is related to.
9192
- **Explain why this enhancement would be useful** to most JSON Schema users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
9293

94+
## Pull Requests
95+
96+
When submitting a pull request, please keep the following in mind:
97+
98+
### Automated Changelog
99+
100+
This project uses an automated changelog system. When your PR is merged to `main`, a GitHub Actions workflow will automatically add an entry to the CHANGELOG.md file under the "Unreleased" section.
101+
102+
**PR Labels and Changelog Categories:**
103+
104+
The workflow determines which category to place your entry under based on the labels on your PR:
105+
106+
- `bug`, `fix`**Fixed** - for bug fixes
107+
- `enhancement`, `feature`, `added`**Added** - for new features
108+
- `changed`**Changed** - for changes in existing functionality
109+
- `deprecated`**Deprecated** - for soon-to-be removed features
110+
- `removed`**Removed** - for now removed features
111+
- `security`**Security** - for security-related changes
112+
- `breaking`**Changed** - for breaking changes
113+
- No matching label → **Changed** (default)
114+
115+
**What this means for you:**
116+
117+
- ✅ You do NOT need to manually update CHANGELOG.md in your PR
118+
- ✅ Make sure your PR title is clear and descriptive (it will become the changelog entry)
119+
- ✅ Add appropriate labels to your PR to ensure it appears in the correct category
120+
- ✅ Maintainers will add labels during the review process if needed
121+
93122
<!-- You might want to create an issue template for enhancement suggestions that can be used as a guide and that defines the structure of the information to be included. If you do so, reference it here in the description. -->
94123

95124
## Attribution

bin/update-changelog.sh

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# Script to update CHANGELOG.md with a new entry
5+
# Usage: ./bin/update-changelog.sh "PR Title" "123" "Fixed"
6+
#
7+
# Arguments:
8+
# $1 - PR title (the changelog entry text)
9+
# $2 - PR number
10+
# $3 - Category (Added, Changed, Fixed, Deprecated, Removed, Security)
11+
#
12+
# Example:
13+
# ./bin/update-changelog.sh "Fix bug in validation" "456" "Fixed"
14+
15+
if [ $# -lt 3 ]; then
16+
echo "Usage: $0 <pr_title> <pr_number> <category>"
17+
echo ""
18+
echo "Categories: Added, Changed, Fixed, Deprecated, Removed, Security"
19+
echo ""
20+
echo "Example: $0 'Fix bug in validation' '456' 'Fixed'"
21+
exit 1
22+
fi
23+
24+
PR_TITLE="$1"
25+
PR_NUMBER="$2"
26+
CATEGORY="$3"
27+
REPO_URL="${GITHUB_REPOSITORY_URL:-https://github.com/jsonrainbow/json-schema}"
28+
29+
# Remove trailing .git if present
30+
REPO_URL="${REPO_URL%.git}"
31+
32+
# Create the changelog entry
33+
ENTRY="- ${PR_TITLE} ([#${PR_NUMBER}](${REPO_URL}/pull/${PR_NUMBER}))"
34+
35+
echo "Adding entry: $ENTRY"
36+
echo "Under category: ### $CATEGORY"
37+
38+
# Check if CHANGELOG.md exists
39+
if [ ! -f CHANGELOG.md ]; then
40+
echo "Error: CHANGELOG.md not found in current directory"
41+
exit 1
42+
fi
43+
44+
# Use awk to insert the entry under the correct category in the Unreleased section
45+
if ! awk -v entry="$ENTRY" -v category="### $CATEGORY" '
46+
BEGIN { in_unreleased=0; found_category=0; added=0 }
47+
48+
# Detect Unreleased section
49+
/^## \[Unreleased\]/ { in_unreleased=1; print; next }
50+
51+
# Detect next version section (end of Unreleased)
52+
/^## \[/ {
53+
if (in_unreleased && !added) {
54+
# If we are leaving Unreleased and haven'\''t added entry yet
55+
# Add category and entry before this line
56+
if (!found_category) {
57+
print category
58+
}
59+
print entry
60+
print ""
61+
added=1
62+
}
63+
in_unreleased=0
64+
found_category=0
65+
print
66+
next
67+
}
68+
69+
# If in Unreleased section, look for matching category
70+
in_unreleased && $0 == category {
71+
found_category=1
72+
print
73+
# Add entry right after category header
74+
print entry
75+
added=1
76+
next
77+
}
78+
79+
# Always print the current line
80+
{ print }
81+
82+
# At end of file, if still in unreleased and not added
83+
END {
84+
if (in_unreleased && !added) {
85+
if (!found_category) {
86+
print category
87+
}
88+
print entry
89+
}
90+
}
91+
' CHANGELOG.md > CHANGELOG.md.tmp; then
92+
echo "Error: Failed to update CHANGELOG.md"
93+
rm -f CHANGELOG.md.tmp
94+
exit 1
95+
fi
96+
97+
mv CHANGELOG.md.tmp CHANGELOG.md
98+
99+
echo "CHANGELOG.md updated successfully"

0 commit comments

Comments
 (0)