ci: derive release notes from CHANGELOG.md + support version tags
All checks were successful
release / build-and-release (push) Successful in 33s
All checks were successful
release / build-and-release (push) Successful in 33s
- Extract the relevant CHANGELOG.md section as the release body instead of the static "Auto-built from SHA": on a vX.Y tag take that version's section, else the latest released version section. - Publish step is now tag-aware: a vX.Y tag push builds, signs and publishes a named non-prerelease (keeping the git tag); main/dispatch keep the rolling 'latest' prerelease. Body built with jq for safe escaping. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f89093212f
commit
043faa50cf
1 changed files with 49 additions and 18 deletions
|
|
@ -4,6 +4,7 @@ on:
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
tags: ['v*']
|
||||||
paths:
|
paths:
|
||||||
- '**.go'
|
- '**.go'
|
||||||
- 'go.mod'
|
- 'go.mod'
|
||||||
|
|
@ -97,40 +98,70 @@ jobs:
|
||||||
xetup.exe
|
xetup.exe
|
||||||
echo "Signed and timestamped xetup.exe"
|
echo "Signed and timestamped xetup.exe"
|
||||||
|
|
||||||
- name: Publish latest release
|
- name: Extract release notes from CHANGELOG.md
|
||||||
|
run: |
|
||||||
|
# On a version tag (v0.7) take that version's section; otherwise the
|
||||||
|
# latest released version section (first "## [<digit>"). Falls back to
|
||||||
|
# [Unreleased], then to a placeholder.
|
||||||
|
case "${{ github.ref }}" in
|
||||||
|
refs/tags/v*)
|
||||||
|
HEADER="## [$(echo "${{ github.ref }}" | sed 's#refs/tags/v##')]" ;;
|
||||||
|
*)
|
||||||
|
HEADER=$(grep -m1 -E '^## \[[0-9]' CHANGELOG.md 2>/dev/null || true) ;;
|
||||||
|
esac
|
||||||
|
[ -n "$HEADER" ] || HEADER="## [Unreleased]"
|
||||||
|
# Print the section body from HEADER (prefix match) until the next "## ".
|
||||||
|
awk -v h="$HEADER" '
|
||||||
|
index($0, h) == 1 { f = 1; next }
|
||||||
|
f && /^## / { exit }
|
||||||
|
f { print }
|
||||||
|
' CHANGELOG.md > /tmp/notes.md
|
||||||
|
[ -s /tmp/notes.md ] || echo "See CHANGELOG.md." > /tmp/notes.md
|
||||||
|
echo "Release notes for '$HEADER':"; cat /tmp/notes.md
|
||||||
|
|
||||||
|
- name: Publish release
|
||||||
env:
|
env:
|
||||||
TOKEN: ${{ secrets.FORGEJO_TOKEN }}
|
TOKEN: ${{ secrets.FORGEJO_TOKEN }}
|
||||||
API: http://xetup-forgejo:3000/api/v1
|
API: http://xetup-forgejo:3000/api/v1
|
||||||
REPO: ${{ github.repository }}
|
REPO: ${{ github.repository }}
|
||||||
run: |
|
run: |
|
||||||
SHORT=$(echo "${{ github.sha }}" | cut -c1-7)
|
SHORT=$(echo "${{ github.sha }}" | cut -c1-7)
|
||||||
|
# Version tag -> named, non-prerelease; anything else -> rolling 'latest'.
|
||||||
|
case "${{ github.ref }}" in
|
||||||
|
refs/tags/*)
|
||||||
|
RELTAG=$(echo "${{ github.ref }}" | sed 's#refs/tags/##')
|
||||||
|
RELNAME="$RELTAG"; PRERELEASE=false ;;
|
||||||
|
*)
|
||||||
|
RELTAG="latest"; RELNAME="latest"; PRERELEASE=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
# Delete existing 'latest' release and tag to recreate cleanly
|
# Body = changelog section + build footer; built with jq so newlines and
|
||||||
|
# quotes are escaped safely.
|
||||||
|
BODY=$(printf '%s\n\n_Built from %s_' "$(cat /tmp/notes.md)" "$SHORT")
|
||||||
|
PAYLOAD=$(jq -n --arg tag "$RELTAG" --arg name "$RELNAME" \
|
||||||
|
--arg body "$BODY" --argjson pre "$PRERELEASE" \
|
||||||
|
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}')
|
||||||
|
|
||||||
|
# Replace any existing release for this tag. For rolling 'latest' also
|
||||||
|
# drop the git tag so it re-points to the new commit; never delete a
|
||||||
|
# real version tag.
|
||||||
RID=$(curl -sf -H "Authorization: token $TOKEN" \
|
RID=$(curl -sf -H "Authorization: token $TOKEN" \
|
||||||
"$API/repos/$REPO/releases/tags/latest" | jq -r '.id // empty')
|
"$API/repos/$REPO/releases/tags/$RELTAG" | jq -r '.id // empty')
|
||||||
if [ -n "$RID" ]; then
|
[ -n "$RID" ] && curl -sf -X DELETE -H "Authorization: token $TOKEN" \
|
||||||
curl -sf -X DELETE -H "Authorization: token $TOKEN" \
|
|
||||||
"$API/repos/$REPO/releases/$RID" || true
|
"$API/repos/$REPO/releases/$RID" || true
|
||||||
fi
|
[ "$RELTAG" = "latest" ] && curl -sf -X DELETE -H "Authorization: token $TOKEN" \
|
||||||
curl -sf -X DELETE -H "Authorization: token $TOKEN" \
|
|
||||||
"$API/repos/$REPO/tags/latest" || true
|
"$API/repos/$REPO/tags/latest" || true
|
||||||
|
|
||||||
# Create new 'latest' release
|
|
||||||
RID=$(curl -sf -X POST \
|
RID=$(curl -sf -X POST \
|
||||||
-H "Authorization: token $TOKEN" \
|
-H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
||||||
-H "Content-Type: application/json" \
|
"$API/repos/$REPO/releases" -d "$PAYLOAD" | jq -r '.id')
|
||||||
"$API/repos/$REPO/releases" \
|
|
||||||
-d "{\"tag_name\":\"latest\",\"name\":\"latest\",\"body\":\"Auto-built from ${SHORT}\",\"prerelease\":true}" \
|
|
||||||
| jq -r '.id')
|
|
||||||
|
|
||||||
# Upload xetup.exe
|
|
||||||
curl -sf -X POST \
|
curl -sf -X POST \
|
||||||
-H "Authorization: token $TOKEN" \
|
-H "Authorization: token $TOKEN" -H "Content-Type: application/octet-stream" \
|
||||||
-H "Content-Type: application/octet-stream" \
|
|
||||||
"$API/repos/$REPO/releases/$RID/assets?name=xetup.exe" \
|
"$API/repos/$REPO/releases/$RID/assets?name=xetup.exe" \
|
||||||
--data-binary @xetup.exe
|
--data-binary @xetup.exe
|
||||||
|
|
||||||
echo "Released xetup.exe (commit ${SHORT})"
|
echo "Released xetup.exe as '$RELNAME' (commit $SHORT)"
|
||||||
|
|
||||||
- name: Update deploy.json
|
- name: Update deploy.json
|
||||||
# Cosmetic "last build" indicator. Requires docker.sock in the job
|
# Cosmetic "last build" indicator. Requires docker.sock in the job
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue