Skip to content

ci: cut releases by bumping version.json - #16

Open
bajtos wants to merge 5 commits into
mainfrom
claude/gha-tagged-releases-workflow-ui097w
Open

ci: cut releases by bumping version.json#16
bajtos wants to merge 5 commits into
mainfrom
claude/gha-tagged-releases-workflow-ui097w

Conversation

@bajtos

@bajtos bajtos commented Aug 21, 2026

Copy link
Copy Markdown
Member

Installing ucantool requires a Go toolchain, and the binary it produces reports no version, so there is no way to tell which build is sitting on a machine.

Releases are cut by bumping version in version.json. Open a pull request with that one change:

  • Release Checker validates the semver, reports any Go API changes against the previous release, and creates a draft GitHub Release whose notes you can edit by hand.
  • Merging the PR publishes that release, and publishing is what creates the vX.Y.Z tag, at the merge commit.
  • Binaries Releaser uses GoReleaser to cross-compile Linux and macOS binaries for amd64 and arm64 and attaches them, with a SHA-256 checksums file, to the release.

A version with a pre-release suffix such as v0.1.0-rc1 is published as a pre-release.

Nobody pushes a v* tag by hand. If someone does, Tag Push Checker opens an issue asking them to reconcile version.json.

Release Checker, Releaser and Tag Push Checker are reusable workflows from ipdxco/unified-github-workflows, the release process fil-forge/piri already runs. Binaries Releaser is local and adds three things over piri's:

  • The build starts only when Releaser succeeded.
  • A concurrency group keeps a release published with a PAT from racing itself.
  • The checkout pins the commit Releaser tagged, so a later push to main cannot be built by mistake.

Every action and reusable workflow is pinned to a commit SHA.

ucantool version reports the version, commit, build date and builder. ucantool --version prints the version alone. Release builds take the version from ldflags. Other builds fall back to version.json and append the short VCS revision the Go toolchain embeds, so a development binary identifies itself too.

To see what the binaries would look like without publishing anything:

goreleaser release --snapshot --clean

The README covers downloading a binary, verifying the checksum, and cutting a release.

claude added 2 commits August 21, 2026 13:11
Add a GoReleaser-based release workflow that fires on `v*` tag pushes and
publishes a GitHub Release with binaries for Linux, macOS and Windows on
both amd64 and arm64.

The dependency graph is free of cgo, so all six targets cross-compile from
a single ubuntu-latest runner with CGO_ENABLED=0.

Also add version reporting to the CLI: the release build stamps the version
via -ldflags, with a runtime/debug.ReadBuildInfo() fallback so `go install`
builds identify themselves too. Cobra exposes this as `ucantool --version`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019j6gFX7vv3eYbmMn8NTQch
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019j6gFX7vv3eYbmMn8NTQch

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ee42c9e4d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/release.yml Outdated
Comment thread README.md
@bajtos
bajtos requested a review from alanshaw August 21, 2026 13:31
@bajtos bajtos changed the title Add release automation with GoReleaser chore: add release automation with GoReleaser Aug 21, 2026
@bajtos bajtos changed the title chore: add release automation with GoReleaser ci: publish tagged releases with pre-built binaries Aug 21, 2026
claude added 2 commits August 21, 2026 14:59
Replace the tag-triggered release workflow with the version.json-driven
process used by fil-forge/piri, so the tag is created by the automation
rather than pushed by hand.

Releases are now cut by bumping version.json in a PR: Release Checker
validates the semver and pre-creates a draft release, Releaser publishes
it on merge (creating the tag), and Binaries Releaser attaches the
GoReleaser artifacts. Tag Push Checker nags on manually pushed tags.

Because Releaser publishes with GITHUB_TOKEN, the new tag and release
emit no workflow-triggering events, so Binaries Releaser listens on
workflow_run from Releaser instead of on the tag.

Version reporting moves to pkg/build, mirroring piri: a version
subcommand reports version, commit, build date and builder, with the
short VCS revision appended and version.json as the development
fallback.

Targets are now linux and darwin on amd64 and arm64, matching piri and
the existing go-test-config.json which already skips Windows.

Three hardenings over piri's workflow, all in release-binaries.yml: only
run when Releaser succeeded, a concurrency group so a PAT-published
release cannot race, and an explicit checkout of the tagged commit so a
later push to main cannot be built by mistake.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019j6gFX7vv3eYbmMn8NTQch
sha256sum is not part of a stock macOS install, so the verification
instruction only worked on Linux. Document shasum alongside it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019j6gFX7vv3eYbmMn8NTQch
@bajtos bajtos changed the title ci: publish tagged releases with pre-built binaries ci: cut releases by bumping version.json Aug 21, 2026
@bajtos

bajtos commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b29a589aab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pkg/build/version.go
Comment on lines +37 to +40
version, err = readVersionFromFile()
if err != nil {
// Use the default version
version = defaultVersion

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Derive source-install versions from build metadata

When users follow the documented go install github.com/fil-forge/ucantool@latest path, no ldflag sets version, and the installed binary reads version.json from its runtime working directory rather than from its build source. Running it normally therefore reports v0.0.0-unknown (or even adopts an unrelated project's version.json) instead of the installed module version; use the version embedded in debug.ReadBuildInfo or another build-time value rather than a runtime-relative file.

Useful? React with 👍 / 👎.

Comment thread pkg/build/version.go
}
}

Version = fmt.Sprintf("%s-%s", version, revision.Revision)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the tagged version in release builds

When GoReleaser supplies a tagged version such as v0.1.0 through the configured ldflag, this unconditional suffix makes the official stable binary report v0.1.0-<revision>. Under SemVer that identifies a prerelease rather than the published v0.1.0 release, so version checks and upgrade logic can misclassify every release artifact; append the revision only for development/fallback builds, while the separate Commit field can retain release provenance.

Useful? React with 👍 / 👎.

Comment thread README.md
then extract the `ucantool` binary onto your `PATH`. Linux archives are named
`ucantool_<version>_linux_<arch>.tar.gz` and macOS archives
`ucantool_<version>_mac_os_<arch>.zip`, for both `amd64` and `arm64`. Each release
also publishes a `ucantool_<version>_checksums.txt` with SHA-256 checksums:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Match the documented checksum filename to GoReleaser

The GoReleaser configuration does not define checksum.name_template, so GoReleaser v2 emits its default checksums.txt, not the documented ucantool_<version>_checksums.txt. Consequently both verification commands point users at a file that is absent from the release; either configure that name template or document and pass the actual checksums.txt asset.

Useful? React with 👍 / 👎.

concurrency:
# A release published with a PAT can fire both `release` and `workflow_run`.
# Queue rather than cancel, so an in-flight asset upload is never interrupted.
group: ${{ github.workflow }}-${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.ref }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use one concurrency key for both release triggers

When Releaser publishes with a PAT and consequently emits both events described above, the release run uses a key ending in refs/tags/vX.Y.Z, while the workflow_run run uses one ending in the raw commit SHA. These are different concurrency groups, so the two GoReleaser jobs run simultaneously and race while uploading the same assets despite cancel-in-progress: false; derive both keys from the same tag or commit identity.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants