Skip to content

Move a GoReleaser project

A Go project that releases with GoReleaser keeps doing so. tapster add changes it so that GoReleaser builds and opens a draft. The hub does what needs keys: signing, notarization and the cask.

In .goreleaser.yaml:

release:
draft: true # the hub publishes after signing
checksum:
name_template: checksums.txt # the name the hub reads
# removed: notarize, homebrew_casks, brews, scoops

In the workflow that runs goreleaser/goreleaser-action (release.yml unless you pass --workflow ci.yml):

  • the MACOS_* and HOMEBREW_TAP_* variables leave the GoReleaser step;
  • the job gets contents: write, id-token: write and attestations: write;
  • a step named Attest the archives for tapster attests the files listed in dist/checksums.txt;
  • a step named Ring the tapster hub follows, for the doorbell.

When you name another workflow with --workflow, the hub entry records it, because the hub checks which workflow made each attestation.

The hub writes the cask from its own entry in tapster.yml. add fills that entry from GoReleaser’s homebrew_casks (or brews) section. Template values such as {{ .Env.X }} are left out.

In GoReleaser In the hub entry
description, homepage, license and completions the same keys
custom_block with app "MyTool.app" app.name
binaries under #{appdir}/MyTool.app/ app.binaries
uninstall with launchctl and quit cask.uninstall
zap with trash cask.zap
caveats cask.caveats
hooks.post.install that runs one of the tool’s commands cask.postflight

The app’s bundle id comes from an Info.plist in the project that names the app. A project that also builds for Linux keeps the app in on_macos and the bare binary in on_linux. tapster reads them from there too:

homebrew_casks:
- name: mytool
custom_block: |
on_macos do
app "MyTool.app"
binary "#{appdir}/MyTool.app/Contents/MacOS/mytool"
end
on_linux do
binary "mytool"
end

The hub entry then has the app and the Linux archives. The hub renders the same blocks, see With Linux builds. tapster reads only lines right inside those blocks. It lists what it does not carry, such as other hooks, deeper lines or other lines of custom_block. A hook is carried only in this form:

system_command "#{HOMEBREW_PREFIX}/bin/mytool", args: ["setup"], must_succeed: false

The new cask runs it as Homebrew’s postflight_steps, in Homebrew’s sandbox: without network or your home folder. A command that needs them does nothing there, so let the tool do that work the next time it runs. See tapster.yml.

When the archive holds an app, the hub signs, notarizes and staples it. A build hook that signed or notarized the app with the old secrets must now sign it ad hoc only:

Terminal window
codesign --force --sign - dist/MyTool.app

The hub needs to know the archive of each platform. tapster takes the names from the project’s latest release. A project with no release yet gets GoReleaser’s default names:

assets:
darwin-arm64: "mytool_{version}_darwin_arm64.tar.gz"
darwin-amd64: "mytool_{version}_darwin_amd64.tar.gz"
linux-amd64: "mytool_{version}_linux_amd64.tar.gz"

macOS archives must be .tar.gz. Windows builds may stay .zip; with them the entry also gets scoop: true. A project with universal_binaries gets one darwin-universal archive. If you set your own name_template for archives and have no release yet, tapster cannot guess the names: run tapster add again after the first draft.

A release workflow that moves a branch after GoReleaser, for example so that a site deploys from it, fails after tapster add: the project’s rules let only you move branches. tapster add names such a step. Instead:

The tag key created by --auto or --auto-tag may push tags only. It cannot move a release branch. For a site, prefer deploying build artifacts from a workflow triggered by release: { types: [published] }, which needs no branch write. If you keep a release branch, move it with your own GitHub sign-in after the hub has published:

Terminal window
git fetch origin --tags
git push origin "v1.2.3^{commit}:refs/heads/release"

The UI’s release-setting updates keep branch protection in place. They do not grant the tag key permission to push project code.

The release workflow starts only from a version tag, so merging docs never releases. Keep it that way: add no push or paths triggers on main to it. To keep docs-only pull requests off the full CI, see Docs and CI. When you merge several pull requests in a row, put [skip ci] in every merge message but the last. Never tag a commit whose message carries a skip marker.

  1. Run tapster add, merge the hub’s pull request and push the project’s changes, as in Add a project.

  2. Release the next version: in tapster setup, open the project under Projects and click Release. tapster tags the latest commit of the default branch on GitHub. GoReleaser opens a draft and the hub publishes it.

  3. The hub writes Casks/mytool.rb. If GoReleaser wrote the cask to the same tap before, the hub’s version replaces it. If GoReleaser wrote a formula (brews), delete Formula/mytool.rb from the tap: Homebrew installs a formula before a cask of the same name.

  4. Once the release is published, delete the secrets the project no longer needs. tapster add lists them:

    Terminal window
    gh secret delete MACOS_SIGN_P12 --repo you/mytool
    gh secret delete HOMEBREW_TAP_GITHUB_TOKEN --repo you/mytool