From 6def8f8581684b1f9ecab8edef2f38ba0d393d7a Mon Sep 17 00:00:00 2001 From: Roman Milyushkevich Date: Tue, 20 Oct 2026 15:06:18 +0300 Subject: [PATCH] ci(release): release by merging a VERSION bump Merging a PR that changes VERSION now tags the merge commit v and runs goreleaser in the same job. A tag pushed with GITHUB_TOKEN doesn't start another workflow run, so the build can't wait for the tag trigger. If .github/release-notes/v.md exists, it becomes the release body instead of the generated changelog. Pushing a v* tag by hand still releases as before. This lets the release be a reviewable PR, and lets automation that can open and merge PRs but can't push tags cut releases. VERSION starts at 0.2.2, the current release, so merging this PR tags nothing. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 41 ++++++++++++++++++++++++++++++++++- README.md | 2 ++ VERSION | 1 + 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 VERSION diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e3df99..2631ec3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,14 @@ name: release +# Two ways to cut a release: +# 1. Merge a PR that bumps VERSION. This workflow tags the merge commit +# v and builds it. If .github/release-notes/v.md exists, +# it becomes the release body instead of the generated changelog. +# 2. Push a v* tag by hand, as before. on: push: + branches: [main] + paths: [VERSION] tags: - "v*" @@ -16,7 +23,38 @@ jobs: with: fetch-depth: 0 + # A tag pushed with GITHUB_TOKEN doesn't start another workflow run, so + # tag and build in this job rather than waiting for the tag trigger. + - name: tag VERSION bump + id: tag + if: github.ref_type == 'branch' + run: | + version=$(tr -d '[:space:]' < VERSION) + if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then + echo "VERSION must be semver like 0.3.0, got '$version'" + exit 1 + fi + tag="v$version" + if git rev-parse -q --verify "refs/tags/$tag" >/dev/null; then + echo "$tag already exists; nothing to release." + echo "skip=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + git tag "$tag" + git push origin "$tag" + echo "tag=$tag" >> "$GITHUB_OUTPUT" + + - name: release notes + id: notes + if: steps.tag.outputs.skip != 'true' + run: | + notes=".github/release-notes/${{ steps.tag.outputs.tag || github.ref_name }}.md" + if [ -f "$notes" ]; then + echo "args=--release-notes $notes" >> "$GITHUB_OUTPUT" + fi + - uses: actions/setup-go@v5 + if: steps.tag.outputs.skip != 'true' with: go-version: "1.24" cache: true @@ -35,10 +73,11 @@ jobs: # owner: HasData - uses: goreleaser/goreleaser-action@v6 + if: steps.tag.outputs.skip != 'true' with: distribution: goreleaser version: latest - args: release --clean + args: release --clean ${{ steps.notes.outputs.args }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # HOMEBREW_TAP_TOKEN: ${{ steps.app_token.outputs.token }} diff --git a/README.md b/README.md index 0da2dab..2081e8e 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,8 @@ go build ./... go test ./... ``` +Releasing: bump `VERSION` in a PR. Merging it tags `v` and publishes the release; add `.github/release-notes/v.md` to write the release body yourself. Pushing a `v*` tag by hand still works. + ## Resources - **HasData docs** — diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..ee1372d --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.2.2