From b0092cd340cc39a2a507b20dd8f673a2a5333d9e Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Tue, 29 Sep 2026 16:12:51 +0000 Subject: [PATCH 1/3] Let GoReleaser create the release from a tag push GitHub immutable releases are on for this repo. After a release is published, no one can add assets to it. dev-bin/release.sh published the release with `gh release create`. Then GoReleaser ran on `release: published` and tried to upload assets to that release. Immutable releases block this upload. mmdbconvert v0.2.0 had the same failure. Now release.sh pushes an annotated tag with the release notes in its message. The tag push starts the Release workflow in the `release` environment. GoReleaser reads the notes from the tag, creates a draft release, uploads the assets, then publishes the release. The workflow fetches the tags again after checkout. On a tag push, actions/checkout replaces the annotated tag with a lightweight tag. Set `permissions: {}` at the workflow level. Each job sets the permissions that it needs. Remove `release.target_commitish` from .goreleaser.yml. The tag already points at the correct commit. Set `release.name_template` to keep the "2.0.0"-style release titles that `gh release create` made. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 29 ++++++++++++++++++++++++----- .goreleaser.yml | 2 +- README.dev.md | 15 +++++++++------ dev-bin/release.sh | 9 ++++++++- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 65f85c3..b257914 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,13 +6,15 @@ on: push: branches: - main - release: - types: - - published + tags: + - 'v*' + +permissions: {} jobs: goreleaser: - if: github.event_name == 'release' && github.event.action == 'published' + name: Release with GoReleaser + if: github.event_name == 'push' && github.ref_type == 'tag' runs-on: ubuntu-latest environment: release permissions: @@ -24,6 +26,23 @@ jobs: fetch-depth: 0 persist-credentials: false + # On a tag push, actions/checkout replaces the annotated tag with a + # lightweight tag. Fetch the tags again to get the tag message. + - name: Fetch annotated tags + run: git fetch --force --tags + + - name: Get release notes from the tag + run: | + if [ "$(git cat-file -t "$GITHUB_REF_NAME")" != tag ]; then + echo "Tag $GITHUB_REF_NAME is not an annotated tag. Create it with dev-bin/release.sh." + exit 1 + fi + git tag -l --format='%(contents:body)' "$GITHUB_REF_NAME" > "$RUNNER_TEMP/release-notes.md" + if ! grep -q '[^[:space:]]' "$RUNNER_TEMP/release-notes.md"; then + echo "Tag $GITHUB_REF_NAME has no release notes. Create it with dev-bin/release.sh." + exit 1 + fi + - name: Set up Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: @@ -35,6 +54,6 @@ jobs: with: distribution: goreleaser version: latest - args: release --clean + args: release --clean --release-notes ${{ runner.temp }}/release-notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml index dc0ffcd..76930ef 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -68,4 +68,4 @@ nfpms: dst: '/usr/share/doc/mmdbinspect/README.md' release: - target_commitish: "{{ .FullCommit }}" + name_template: "{{.Version}}" diff --git a/README.dev.md b/README.dev.md index c5e2689..9db8fa6 100644 --- a/README.dev.md +++ b/README.dev.md @@ -1,8 +1,7 @@ # Prereqs - You must have the [GitHub CLI tool (gh)](https://cli.github.com/) installed, - in your path, and logged into an account that can make GitHub releases on the - repo. + in your path, and logged into an account that can push to the repo. - Your environment also must have `bash`, `git` and `sed` available. # Releasing @@ -18,9 +17,13 @@ - Run `dev-bin/release.sh`. - You might need to initialize/update submodules to successfully run tests, eg. `git submodule update --init --recursive`. + - The script pushes the branch. Then it pushes an annotated tag, for example + `v2.0.1`. The tag message contains the release notes from `CHANGELOG.md`. +- The tag push starts the Release workflow. The authorized releasers receive an + email to review the pending deployment. If you are an authorized releaser, + approve the deployment. If you are not, wait for an authorized releaser to do + so. +- After the approval, GoReleaser creates the GitHub release with the notes from + the tag. It uploads the binaries and packages, then publishes the release. - Verify the release on the GitHub Releases page. -- If everything goes well, the authorized releasers will receive an email to - review the pending deployment. If you are an authorized releaser, you will - need to approve the release deployment run. If you are not, you will have to - wait for an authorized releaser to do so. - Make a PR and get it merged. diff --git a/dev-bin/release.sh b/dev-bin/release.sh index 2eb2327..92f2698 100755 --- a/dev-bin/release.sh +++ b/dev-bin/release.sh @@ -94,4 +94,11 @@ fi git push -gh release create --target "$(git branch --show-current)" -t "$version" -n "$notes" "$tag" +# The tag message is the version, a blank line, and the release notes. The +# Release workflow uses the notes for the GitHub release. "verbatim" keeps any +# "#" lines, which git would otherwise strip as comments. +git tag -a --cleanup=verbatim -m "$version + +$notes" "$tag" + +git push origin "$tag" From 3dc9898cea4a20472c73e42e109625a867940f30 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Tue, 29 Sep 2026 16:14:07 +0000 Subject: [PATCH 2/3] Check the GoReleaser config on PRs and main Before, the Release workflow ran GoReleaser only at release time. A broken .goreleaser.yml or build showed up only during a release. Add a job that runs a GoReleaser snapshot build on PRs, on pushes to main, and on manual runs. The job does not publish anything. mmdbconvert has the same check. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b257914..5d556ad 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,32 @@ on: permissions: {} jobs: + goreleaser-check: + name: Check GoReleaser + if: github.ref_type != 'tag' + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Set up Go + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version: stable + cache: false + + - name: Check GoReleaser + uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3 + with: + distribution: goreleaser + version: latest + args: release --snapshot --clean --skip=publish + goreleaser: name: Release with GoReleaser if: github.event_name == 'push' && github.ref_type == 'tag' From 4ab751ed9b9ab9573a6e28be77f5d310f619fa5c Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Wed, 30 Sep 2026 17:41:32 +0000 Subject: [PATCH 3/3] Fix release notes and tag handling --- .github/workflows/release.yml | 3 ++- .goreleaser.yml | 3 --- dev-bin/release.sh | 14 +++++++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5d556ad..0710b94 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,7 +59,7 @@ jobs: - name: Get release notes from the tag run: | - if [ "$(git cat-file -t "$GITHUB_REF_NAME")" != tag ]; then + if [ "$(git cat-file -t "refs/tags/$GITHUB_REF_NAME")" != tag ]; then echo "Tag $GITHUB_REF_NAME is not an annotated tag. Create it with dev-bin/release.sh." exit 1 fi @@ -83,3 +83,4 @@ jobs: args: release --clean --release-notes ${{ runner.temp }}/release-notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GORELEASER_CURRENT_TAG: ${{ github.ref_name }} diff --git a/.goreleaser.yml b/.goreleaser.yml index 76930ef..b3136e6 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -41,9 +41,6 @@ checksum: snapshot: version_template: "{{ .Tag }}-next" -changelog: - disable: true - nfpms: - id: 'mmdbinspect' builds: diff --git a/dev-bin/release.sh b/dev-bin/release.sh index 92f2698..a639756 100755 --- a/dev-bin/release.sh +++ b/dev-bin/release.sh @@ -69,6 +69,11 @@ date="${BASH_REMATCH[3]}" notes="$(echo "${BASH_REMATCH[4]}" | sed -n -E '/^## [0-9]+\.[0-9]+\.[0-9]+(-[^ ]+)?/,$!p')" tag="v$version" +if ! grep -q '[^[:space:]]' <<<"$notes"; then + echo "Release notes for $tag are empty. Add notes to CHANGELOG.md." >&2 + exit 1 +fi + if [[ "$date" != "$(date +"%Y-%m-%d")" ]]; then echo "$date is not today!" exit 1 @@ -94,11 +99,10 @@ fi git push -# The tag message is the version, a blank line, and the release notes. The -# Release workflow uses the notes for the GitHub release. "verbatim" keeps any -# "#" lines, which git would otherwise strip as comments. -git tag -a --cleanup=verbatim -m "$version +# The tag message is the version, a blank line, and the release notes. +# "whitespace" keeps Markdown headings and adds a newline before a signature. +git tag -a --cleanup=whitespace -m "$version $notes" "$tag" -git push origin "$tag" +git push origin "refs/tags/$tag"