Skip to content

Commit f8f51bd

Browse files
authored
Merge pull request #39 from LeakIX/ci-changelog-commit-check
CI: enforce changelog in dedicated commits and add shellcheck
2 parents c43803e + 34c970d commit f8f51bd

4 files changed

Lines changed: 108 additions & 0 deletions

File tree

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env bash
2+
# Verify CHANGELOG.md hygiene in pull requests:
3+
# 1. CHANGELOG.md changes must be in their own dedicated commit
4+
# 2. Commit hashes referenced in new changelog entries must exist
5+
# in the branch
6+
# 3. Commit link URLs must match their reference keys
7+
#
8+
# Usage: check-changelog-commit.sh <base-sha>
9+
set -euo pipefail
10+
11+
base="${1:?Usage: check-changelog-commit.sh <base-sha>}"
12+
errors=0
13+
14+
# --- Check 1: CHANGELOG.md must be in dedicated commits ---
15+
16+
for commit in $(git log --format=%H "${base}..HEAD"); do
17+
files=$(git diff-tree --no-commit-id --name-only -r "$commit")
18+
if echo "$files" | grep -q "^CHANGELOG.md$"; then
19+
file_count=$(echo "$files" | wc -l | tr -d ' ')
20+
if [ "$file_count" -gt 1 ]; then
21+
echo "::error::Commit $commit modifies CHANGELOG.md alongside other files."
22+
echo "CHANGELOG.md changes must be in their own dedicated commit."
23+
errors=$((errors + 1))
24+
fi
25+
fi
26+
done
27+
28+
# --- Check 2: Referenced commit hashes must exist in the branch ---
29+
30+
# Get new changelog lines added in this PR
31+
changelog_diff=$(git diff "${base}..HEAD" -- CHANGELOG.md \
32+
| grep "^+" | grep -v "^+++" || true)
33+
34+
# Extract short commit hashes from inline references like ([abc1234], ...)
35+
inline_hashes=$(echo "$changelog_diff" \
36+
| grep -oE '\(\[([0-9a-f]{7,})\]' \
37+
| grep -oE '[0-9a-f]{7,}' | sort -u || true)
38+
39+
# Get all commits reachable from HEAD (not just this branch)
40+
for hash in $inline_hashes; do
41+
if ! git cat-file -t "$hash" >/dev/null 2>&1; then
42+
echo "::error::Commit $hash referenced in CHANGELOG.md does not exist."
43+
errors=$((errors + 1))
44+
fi
45+
done
46+
47+
# --- Check 3: Link definition URLs must match their keys ---
48+
# Matches lines like: [abc1234]: https://.../commit/xyz7890
49+
# and verifies abc1234 == xyz7890
50+
51+
link_lines=$(echo "$changelog_diff" \
52+
| grep -E '^\+\[[0-9a-f]{7,}\]: https://.*commit/' || true)
53+
54+
while IFS= read -r line; do
55+
[ -z "$line" ] && continue
56+
key=$(echo "$line" \
57+
| grep -oE '\[([0-9a-f]{7,})\]' | head -1 \
58+
| tr -d '[]')
59+
url_hash=$(echo "$line" \
60+
| grep -oE 'commit/[0-9a-f]{7,}' \
61+
| sed 's|commit/||')
62+
if [ -n "$key" ] && [ -n "$url_hash" ] && [ "$key" != "$url_hash" ]; then
63+
echo "::error::Link [$key] points to commit/$url_hash but should point to commit/$key"
64+
errors=$((errors + 1))
65+
fi
66+
done <<< "$link_lines"
67+
68+
# --- Summary ---
69+
70+
if [ "$errors" -gt 0 ]; then
71+
echo "Found $errors changelog error(s)."
72+
exit 1
73+
fi
74+
75+
echo "All changelog checks passed."

.github/workflows/changelog.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,25 @@ jobs:
1515
- uses: tarides/changelog-check-action@v3
1616
with:
1717
changelog: CHANGELOG.md
18+
19+
check-changelog-commit:
20+
name: Check changelog is in dedicated commit
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
- name: Verify CHANGELOG.md changes are in own commit
27+
run: >
28+
.github/scripts/check-changelog-commit.sh
29+
"${{ github.event.pull_request.base.sha }}"
30+
31+
shellcheck:
32+
name: Shellcheck
33+
runs-on: ubuntu-latest
34+
steps:
35+
- uses: actions/checkout@v4
36+
- name: Install shellcheck
37+
run: sudo apt-get install -y shellcheck
38+
- name: Run shellcheck
39+
run: make lint-shell

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ and this project adheres to
1515
- Tests now import from `l9format` package directly instead of
1616
`l9format.l9format` ([e8aef2e], [#21])
1717

18+
### Infrastructure
19+
20+
- CI: enforce CHANGELOG.md changes are in dedicated commits
21+
([d30efd2], [#35])
22+
1823
## [1.4.0] - 2026-02-07
1924

2025
### Added
@@ -132,6 +137,7 @@ and this project adheres to
132137

133138
<!-- Commit links -->
134139

140+
[d30efd2]: https://github.com/LeakIX/l9format-python/commit/d30efd2
135141
[1dcfbef]: https://github.com/LeakIX/l9format-python/commit/1dcfbef
136142
[e8aef2e]: https://github.com/LeakIX/l9format-python/commit/e8aef2e
137143
[8f45e82]: https://github.com/LeakIX/l9format-python/commit/8f45e82
@@ -193,3 +199,4 @@ and this project adheres to
193199
[#16]: https://github.com/LeakIX/l9format-python/pull/16
194200
[#18]: https://github.com/LeakIX/l9format-python/pull/18
195201
[#21]: https://github.com/LeakIX/l9format-python/issues/21
202+
[#35]: https://github.com/LeakIX/l9format-python/issues/35

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ lint: ## Lint code using ruff
4848
lint-fix: ## Lint and fix code using ruff
4949
poetry run ruff check --fix .
5050

51+
.PHONY: lint-shell
52+
lint-shell: ## Lint shell scripts using shellcheck
53+
shellcheck .github/scripts/*.sh
54+
5155
.PHONY: typecheck
5256
typecheck: ## Run mypy type checker
5357
poetry run mypy l9format

0 commit comments

Comments
 (0)