Files
bluebluesodaandCommandCodeBot f6e0727ca4 ci(release): fetch the tag object before reading its notes
The release body is the tag's own annotation, but the runner's checkout only
had the commit — no tag object — so `git cat-file -t` failed and every release
silently fell back to "fix some bugs" (v1.8.0 included). The publish job now
fetches tags, and the notes step fetches the tag ref explicitly before reading
it, so the annotation always makes it into the release body.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-16 07:41:27 +00:00

129 lines
3.9 KiB
YAML

name: release
on:
push:
tags:
- 'v*'
permissions:
contents: write
id-token: write
attestations: write
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
arch: [amd64, arm64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: src/go.mod
cache: true
- name: Build (${{ matrix.arch }})
run: |
VERSION="${GITHUB_REF_NAME#v}"
cd src
CGO_ENABLED=0 GOOS=linux GOARCH=${{ matrix.arch }} go build \
-trimpath -buildvcs=false \
-ldflags="-s -w -X vpsmgr/internal/ver.Version=${VERSION}" \
-o "../vps-${{ matrix.arch }}" .
- name: Verify artifact
run: |
file vps-${{ matrix.arch }}
if [ "${{ matrix.arch }}" = "amd64" ]; then
./vps-${{ matrix.arch }} version
fi
# The project is pure Go (no cgo); keep tests C-free too so they never
# depend on a working C toolchain on the runner.
- name: Vet + test (CGO_ENABLED=0, amd64)
if: matrix.arch == 'amd64'
run: |
cd src
CGO_ENABLED=0 go vet ./...
CGO_ENABLED=0 go test ./...
- name: Attest build provenance
uses: actions/attest@v4
with:
subject-path: vps-${{ matrix.arch }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: vps-${{ matrix.arch }}
path: vps-${{ matrix.arch }}
if-no-files-found: error
publish:
needs: build
runs-on: ubuntu-latest
steps:
# The release notes come from the tag OBJECT, so its annotation has to be
# local: `fetch-tags` brings it, and the notes step fetches the tag ref
# explicitly as well (a checkout that only fetched the commit leaves no
# tag behind, which is how a tag message silently becomes the fallback).
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Generate checksums
run: |
cd dist
sha256sum vps-amd64 vps-arm64 | tee SHA256SUMS
# The release body is the tag's own annotation: write the notes at tag
# time with
# git tag -a v1.2.3 -m "new feature X
#
# - bullet"
# A lightweight tag (`git tag v1.2.3`) carries no message, so the release
# falls back to "fix some bugs". GitHub appends the auto-generated
# "Full changelog" compare link to whatever body we pass.
- name: Build release notes
run: |
TAG="${GITHUB_REF_NAME}"
# The tag's annotation IS the release body, so make sure the tag object
# (not just the commit) is local; without this the notes silently fall
# back to "fix some bugs".
git fetch --force --no-tags origin "+refs/tags/$TAG:refs/tags/$TAG" || true
notes=""
if [ "$(git cat-file -t "$TAG" 2>/dev/null)" = "tag" ]; then
notes="$(git for-each-ref "refs/tags/$TAG" --format='%(contents)')"
# A signed tag's message carries a PGP block; drop it.
notes="${notes%%-----BEGIN PGP SIGNATURE-----*}"
fi
if [ -z "$(printf '%s' "$notes" | tr -d '[:space:]')" ]; then
notes="fix some bugs"
fi
printf '%s\n' "$notes" > release-notes.md
echo "----- release notes -----"
cat release-notes.md
- name: Release
uses: softprops/action-gh-release@v2
with:
body_path: release-notes.md
files: |
dist/vps-amd64
dist/vps-arm64
dist/SHA256SUMS
generate_release_notes: true