Why
The only documented install path is:
go install github.com/everscribe/cli/cmd/es@latest
That requires the user to have a Go toolchain. es is aimed at Everscribe
customers generally, most of whom are not Go developers, so the install
instruction currently asks them to set up a language runtime to get a CLI.
Prebuilt binaries remove that. Target outcome: brew install everscribe/tap/es
on macOS, and a downloadable archive per platform for everyone else, produced
automatically when a tag is pushed.
Current state
- Module
github.com/everscribe/cli, go 1.25.0, MIT.
- Single binary
es, entrypoint ./cmd/es, cobra-based.
cmd/es/main.go has var version = "dev", already documented as
link-time overridable via -X main.version=, wired into cobra's Version.
- No
.github/ directory, so no CI of any kind yet.
- No tags.
@latest currently resolves to a pseudo-version
(v0.0.0-20260705175551-3c3e79d9dd17).
- No
everscribe/homebrew-tap repo yet (confirmed 404).
Steps
1. Decisions to make first
- Tap repo name. Homebrew requires the
homebrew- prefix:
everscribe/homebrew-tap gives users brew install everscribe/tap/es.
- Platforms. Suggested: darwin and linux on both amd64 and arm64, plus
windows/amd64. CGO_ENABLED=0 so everything cross-compiles cleanly.
- First tag.
v0.1.0. Note the release workflow only runs on a tag push,
so nothing happens until one exists.
2. Add .goreleaser.yaml
Starting point. GoReleaser v2 has renamed some keys across minor versions, so
run goreleaser check and reconcile against the current docs rather than
trusting this verbatim.
version: 2
project_name: es
before:
hooks:
- go mod tidy
builds:
- id: es
main: ./cmd/es
binary: es
env:
- CGO_ENABLED=0
goos: [darwin, linux, windows]
goarch: [amd64, arm64]
ignore:
- goos: windows
goarch: arm64
ldflags:
- -s -w -X main.version={{.Version}}
archives:
- name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
format_overrides:
- goos: windows
format: zip
checksum:
name_template: checksums.txt
changelog:
sort: asc
filters:
exclude: ['^docs:', '^test:', '^chore:', '^style:']
The ldflags line is what makes released binaries report a real version
instead of dev.
3. Add the release workflow
.github/workflows/release.yml:
name: release
on:
push:
tags: ['v*']
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # required, or the changelog is empty
- uses: actions/setup-go@v5
with:
go-version: '1.25'
- uses: goreleaser/goreleaser-action@v6
with:
version: '~> v2'
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
fetch-depth: 0 is not optional. A shallow clone has no tag history and the
changelog comes out empty.
4. Create the tap and wire the formula
- Create
everscribe/homebrew-tap as a public repo. Homebrew cannot read
a private tap. An empty repo with a README is enough; GoReleaser commits the
formula into it.
- Add to
.goreleaser.yaml:
brews:
- name: es
repository:
owner: everscribe
name: homebrew-tap
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
homepage: "https://everscribe.io"
description: "Command-line interface for Everscribe"
license: MIT
test: |
system "#{bin}/es", "--version"
5. The token, which is the step that trips people up
The workflow's built-in GITHUB_TOKEN is scoped to this repo only, so it
cannot push a formula to homebrew-tap. A separate credential is required:
- Create a fine-grained PAT with
Contents: read and write on
everscribe/homebrew-tap only.
- Add it to this repo as the secret
HOMEBREW_TAP_TOKEN.
- Note the expiry. When it lapses, releases still succeed but the formula
silently stops updating, so a dated reminder is worth setting.
6. Dry run before tagging anything
goreleaser check # validates the config
goreleaser release --snapshot --clean # builds everything, publishes nothing
ls dist/
./dist/es_darwin_arm64/es --version # must print the version, not "dev"
Only tag once the snapshot looks right. A tag is cheap to delete but a
published GitHub Release is noisier to walk back.
Verification
Related
Separate from this, es --version prints dev for anyone who installs via
go install, because ldflags only apply to builds we control. The installed
binary already carries its version in its build metadata
(go version -m es shows the module version), so reading
debug.ReadBuildInfo().Main.Version and falling back to the version var
fixes that case. Worth doing first so every install path reports correctly.
Why
The only documented install path is:
That requires the user to have a Go toolchain.
esis aimed at Everscribecustomers generally, most of whom are not Go developers, so the install
instruction currently asks them to set up a language runtime to get a CLI.
Prebuilt binaries remove that. Target outcome:
brew install everscribe/tap/eson macOS, and a downloadable archive per platform for everyone else, produced
automatically when a tag is pushed.
Current state
github.com/everscribe/cli, go 1.25.0, MIT.es, entrypoint./cmd/es, cobra-based.cmd/es/main.gohasvar version = "dev", already documented aslink-time overridable via
-X main.version=, wired into cobra'sVersion..github/directory, so no CI of any kind yet.@latestcurrently resolves to a pseudo-version(
v0.0.0-20260705175551-3c3e79d9dd17).everscribe/homebrew-taprepo yet (confirmed 404).Steps
1. Decisions to make first
homebrew-prefix:everscribe/homebrew-tapgives usersbrew install everscribe/tap/es.windows/amd64.
CGO_ENABLED=0so everything cross-compiles cleanly.v0.1.0. Note the release workflow only runs on a tag push,so nothing happens until one exists.
2. Add
.goreleaser.yamlStarting point. GoReleaser v2 has renamed some keys across minor versions, so
run
goreleaser checkand reconcile against the current docs rather thantrusting this verbatim.
The
ldflagsline is what makes released binaries report a real versioninstead of
dev.3. Add the release workflow
.github/workflows/release.yml:fetch-depth: 0is not optional. A shallow clone has no tag history and thechangelog comes out empty.
4. Create the tap and wire the formula
everscribe/homebrew-tapas a public repo. Homebrew cannot reada private tap. An empty repo with a README is enough; GoReleaser commits the
formula into it.
.goreleaser.yaml:5. The token, which is the step that trips people up
The workflow's built-in
GITHUB_TOKENis scoped to this repo only, so itcannot push a formula to
homebrew-tap. A separate credential is required:Contents: read and writeoneverscribe/homebrew-taponly.HOMEBREW_TAP_TOKEN.silently stops updating, so a dated reminder is worth setting.
6. Dry run before tagging anything
Only tag once the snapshot looks right. A tag is cheap to delete but a
published GitHub Release is noisier to walk back.
Verification
goreleaser checkpasses--snapshotproduces archives for every intended platform pluschecksums.txtdevv0.1.0creates a GitHub Release with all archives attachedeverscribe/homebrew-tapreceives anes.rbcommitbrew install everscribe/tap/es && es --versionworks on a clean machinego install github.com/everscribe/cli/cmd/es@lateststill works and nowresolves to
v0.1.0rather than a pseudo-version/docs/cli/installationto lead with brew and keepgo installas the from-source option
Related
Separate from this,
es --versionprintsdevfor anyone who installs viago install, because ldflags only apply to builds we control. The installedbinary already carries its version in its build metadata
(
go version -m esshows the module version), so readingdebug.ReadBuildInfo().Main.Versionand falling back to theversionvarfixes that case. Worth doing first so every install path reports correctly.