Skip to content

Commit 861d7af

Browse files
committed
ci(release): run changelog extraction in build job to gate PyPI publish
Move the AWK-based changelog extraction from the post-publish github-release job into the build job, so a missing or unrenamed "## Unreleased" entry fails before any PyPI upload runs. Previously the extraction lived after publish-to-pypi, meaning a forgotten rename would happily ship the package and only then fail when trying to build a GitHub Release — a state that required manual cleanup. Since publish-to-pypi and publish-to-testpypi both depend on build, failing the new step transitively blocks every downstream job. No changes are needed in the PyPI jobs themselves. Changes: - build job gets two gated steps (if: startsWith(github.ref, 'refs/tags/')): "Extract changelog for tagged release" (runs AWK against CHANGELOG.md, fails fast on empty output) and "Upload release notes" (publishes release-notes.md as a dedicated artifact). - github-release job drops the checkout step (no longer needs CHANGELOG.md on disk) and the duplicate extract step, and adds a "Download release notes" step to consume the new artifact. - The gh release create invocation is unchanged — --notes-file release-notes.md works the same regardless of where the file comes from.
1 parent 1a86942 commit 861d7af

1 file changed

Lines changed: 27 additions & 20 deletions

File tree

.github/workflows/release.yml

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,29 @@ jobs:
2929
with:
3030
name: python-package-distributions
3131
path: dist/
32+
- name: Extract changelog for tagged release
33+
if: startsWith(github.ref, 'refs/tags/')
34+
run: |
35+
VERSION="${{ github.ref_name }}"
36+
VERSION="${VERSION#v}"
37+
awk "
38+
/^## ${VERSION}/ { found=1; next }
39+
found && /^## / { exit }
40+
found { print }
41+
" CHANGELOG.md > release-notes.md
42+
if [[ ! -s release-notes.md ]]; then
43+
echo "::error::No changelog section found for version ${VERSION}."
44+
echo "::error::Did you forget to rename '## Unreleased' in CHANGELOG.md before tagging?"
45+
exit 1
46+
fi
47+
echo "--- Extracted release notes ---"
48+
cat release-notes.md
49+
- name: Upload release notes
50+
if: startsWith(github.ref, 'refs/tags/')
51+
uses: actions/upload-artifact@v7
52+
with:
53+
name: release-notes
54+
path: release-notes.md
3255

3356
publish-to-pypi:
3457
name: >-
@@ -64,37 +87,21 @@ jobs:
6487
id-token: write # IMPORTANT: mandatory for sigstore
6588

6689
steps:
67-
- name: Checkout repository at tag
68-
uses: actions/checkout@v6
69-
with:
70-
ref: ${{ github.ref_name }}
7190
- name: Download all the dists
7291
uses: actions/download-artifact@v8
7392
with:
7493
name: python-package-distributions
7594
path: dist/
95+
- name: Download release notes
96+
uses: actions/download-artifact@v8
97+
with:
98+
name: release-notes
7699
- name: Sign the dists with Sigstore
77100
uses: sigstore/gh-action-sigstore-python@v3.3.0
78101
with:
79102
inputs: >-
80103
./dist/*.tar.gz
81104
./dist/*.whl
82-
- name: Extract changelog for this version
83-
run: |
84-
VERSION="${{ github.ref_name }}"
85-
VERSION="${VERSION#v}"
86-
awk "
87-
/^## ${VERSION}/ { found=1; next }
88-
found && /^## / { exit }
89-
found { print }
90-
" CHANGELOG.md > release-notes.md
91-
if [[ ! -s release-notes.md ]]; then
92-
echo "::error::No changelog section found for version ${VERSION}."
93-
echo "::error::Did you forget to rename '## Unreleased' in CHANGELOG.md before tagging?"
94-
exit 1
95-
fi
96-
echo "--- Extracted release notes ---"
97-
cat release-notes.md
98105
- name: Create GitHub Release
99106
env:
100107
GITHUB_TOKEN: ${{ github.token }}

0 commit comments

Comments
 (0)