Skip to content

Commit d364a44

Browse files
kvapsclaude
andauthored
ci(release): auto-create GitHub Release from CHANGELOG on tag (#167)
release.yml previously only built/pushed the ghcr images on a version tag; the GitHub Release object was created manually. Add a github-release job (needs: build-push) that extracts the matching CHANGELOG.md section and cuts the Release (pre-release + not-latest for -rc/-alpha/-beta tags, idempotent on re-run). Signed-off-by: Andrei Kvapil <kvapss@gmail.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9866305 commit d364a44

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ name: Release Images
1919
# Pre-release tags (v1.33.0-rc.1) get `1.33.0-rc.1` only — no `latest`.
2020
# This matches the repo's `vMAJOR.MINOR.PATCH[-rc.N]` tag convention
2121
# (see `git tag -l`).
22+
#
23+
# After the images publish, the workflow ALSO cuts the GitHub Release object
24+
# for the tag (body taken from the matching CHANGELOG.md section).
2225

2326
on:
2427
push:
@@ -122,3 +125,57 @@ jobs:
122125
GIT_HASH=${{ steps.stamp.outputs.git_hash }}
123126
BUILD_TIME=${{ steps.stamp.outputs.build_time }}
124127
provenance: false
128+
129+
github-release:
130+
name: Create GitHub Release
131+
# After all three images publish, cut the GitHub Release for the tag:
132+
# title = the tag, body = the matching "## <tag> — <date>" section of
133+
# CHANGELOG.md (the same content used for prior releases). Pre-release tags
134+
# (vMAJOR.MINOR.PATCH-rc.N / -alpha / -beta) are marked pre-release and not
135+
# "Latest". Idempotent: updates the release if it already exists (re-run).
136+
needs: build-push
137+
runs-on: ubuntu-latest
138+
permissions:
139+
contents: write
140+
steps:
141+
- name: Clone the code
142+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
143+
with:
144+
persist-credentials: false
145+
146+
- name: Cut the GitHub Release from the CHANGELOG section
147+
env:
148+
GH_TOKEN: ${{ github.token }}
149+
TAG: ${{ github.ref_name }}
150+
run: |
151+
set -euo pipefail
152+
153+
# vMAJOR.MINOR.PATCH[-rc.N] convention: pre-release tags are not Latest.
154+
prerelease=()
155+
latest=(--latest)
156+
case "$TAG" in
157+
*-rc*|*-alpha*|*-beta*) prerelease=(--prerelease); latest=(--latest=false) ;;
158+
esac
159+
160+
# Body = the CHANGELOG.md section under "## <tag> — <date>", up to the
161+
# next "## " heading; leading/trailing blank lines trimmed.
162+
notes="$(mktemp)"
163+
awk -v tag="$TAG" '
164+
index($0, "## " tag " ") == 1 { f=1; next }
165+
f && /^## / { exit }
166+
f { print }
167+
' CHANGELOG.md | sed '/./,$!d' > "$notes"
168+
awk 'NF{p=NR} {a[NR]=$0} END{for (i=1;i<=p;i++) print a[i]}' "$notes" > "$notes.trim"
169+
mv "$notes.trim" "$notes"
170+
171+
if gh release view "$TAG" >/dev/null 2>&1; then
172+
echo "Release $TAG already exists; updating it."
173+
edit_body=()
174+
[ -s "$notes" ] && edit_body=(--notes-file "$notes")
175+
gh release edit "$TAG" --title "$TAG" "${edit_body[@]}" "${prerelease[@]}" "${latest[@]}"
176+
elif [ -s "$notes" ]; then
177+
gh release create "$TAG" --title "$TAG" --verify-tag --notes-file "$notes" "${prerelease[@]}" "${latest[@]}"
178+
else
179+
echo "::warning::CHANGELOG.md has no section for $TAG; using auto-generated notes."
180+
gh release create "$TAG" --title "$TAG" --verify-tag --generate-notes "${prerelease[@]}" "${latest[@]}"
181+
fi

0 commit comments

Comments
 (0)