1- # This action requires that any PR targeting the main branch should touch at
2- # least one CHANGELOG file. If a CHANGELOG entry is not required, add the "Skip
3- # Changelog" label to disable this action.
1+ # This action requires that any PR targeting the main branch should add a
2+ # changelog fragment file in the .changelog/ directory. If a changelog entry
3+ # is not required, add the "Skip Changelog" label to disable this action.
44
55name : changelog
66
99 types : [opened, synchronize, reopened, labeled, unlabeled]
1010 branches :
1111 - main
12+ merge_group :
1213
1314permissions :
1415 contents : read
@@ -17,23 +18,70 @@ jobs:
1718 changelog :
1819 runs-on : ubuntu-latest
1920 if : |
21+ github.event_name != 'merge_group' &&
2022 !contains(github.event.pull_request.labels.*.name, 'Skip Changelog')
2123 && github.actor != 'otelbot[bot]'
2224
2325 steps :
2426 - uses : actions/checkout@v4
27+ with :
28+ fetch-depth : 0
2529
26- - name : Check for CHANGELOG changes
30+ - name : Fetch base branch
31+ run : git fetch origin ${{ github.base_ref }} --depth=1
32+
33+ - name : Ensure no direct changes to CHANGELOG.md
2734 run : |
28- # Only the latest commit of the feature branch is available
29- # automatically. To diff with the base branch, we need to
30- # fetch that too (and we only need its latest commit).
31- git fetch origin ${{ github.base_ref }} --depth=1
32- if [[ $(git diff --name-only FETCH_HEAD | grep CHANGELOG) ]]
35+ if [[ $(git diff --name-only FETCH_HEAD -- 'CHANGELOG.md') ]]
3336 then
34- echo "A CHANGELOG was modified. Looks good!"
35- else
36- echo "No CHANGELOG was modified."
37- echo "Please add a CHANGELOG entry, or add the \"Skip Changelog\" label if not required."
37+ echo "CHANGELOG.md should not be directly modified."
38+ echo "Please add a changelog fragment file to the .changelog/ directory instead."
39+ echo "See CONTRIBUTING.md for details."
40+ echo ""
41+ echo "Or add the \"Skip Changelog\" label if this job should be skipped."
42+ false
43+ fi
44+
45+ - name : Install towncrier
46+ run : pip install towncrier==25.8.0
47+
48+ - name : Check for changelog fragment
49+ run : |
50+ if ! towncrier check --compare-with origin/${{ github.base_ref }}; then
51+ echo ""
52+ echo "No changelog fragment found for this PR."
53+ echo "Add a file named .changelog/${{ github.event.pull_request.number }}.<type>"
54+ echo "where <type> is one of: added, changed, deprecated, removed, fixed"
55+ echo "See CONTRIBUTING.md for details."
56+ echo ""
57+ echo "Or add the \"Skip Changelog\" label if this job should be skipped."
3858 false
3959 fi
60+
61+ - name : Validate fragment filenames
62+ env :
63+ PR_NUMBER : ${{ github.event.pull_request.number }}
64+ run : |
65+ fragments=$(git diff --diff-filter=A --name-only origin/${{ github.base_ref }} -- '.changelog/*' | grep -v '/\.gitignore$' || true)
66+ [ -z "$fragments" ] && exit 0
67+ invalid=()
68+ while IFS= read -r f; do
69+ base=$(basename "$f")
70+ if [[ ! "$base" =~ ^([0-9]+)\.(added|changed|deprecated|removed|fixed)$ ]]; then
71+ invalid+=("$f (expected <PR_NUMBER>.<type>; type one of added, changed, deprecated, removed, fixed)")
72+ continue
73+ fi
74+ if [[ "${BASH_REMATCH[1]}" != "${PR_NUMBER}" ]]; then
75+ invalid+=("$f (PR number ${BASH_REMATCH[1]} does not match this PR's number ${PR_NUMBER})")
76+ fi
77+ done <<< "$fragments"
78+ if (( ${#invalid[@]} > 0 )); then
79+ echo "Invalid changelog fragment(s):"
80+ for msg in "${invalid[@]}"; do
81+ echo " $msg"
82+ done
83+ exit 1
84+ fi
85+
86+ - name : Preview changelog
87+ run : towncrier build --draft --version Unreleased
0 commit comments