Skip to content

feat(release): make holodeck installable via Homebrew#825

Open
ArangoGutierrez wants to merge 15 commits into
NVIDIA:mainfrom
ArangoGutierrez:dreamy-rhodes-556456
Open

feat(release): make holodeck installable via Homebrew#825
ArangoGutierrez wants to merge 15 commits into
NVIDIA:mainfrom
ArangoGutierrez:dreamy-rhodes-556456

Conversation

@ArangoGutierrez
Copy link
Copy Markdown
Collaborator

Implements docs/superpowers/specs/2026-05-26-holodeck-brew-installable-design.md.

Summary

  • Adds GoReleaser config + release workflow on v* tags
  • Adds homebrew-validate workflow (audit + style on Formula/** changes)
  • Refactors cmd/cli/main.go to use a version package variable for ldflag injection (fixes stale hardcoded 0.2.18)
  • Replaces make release (dead code — built binaries to bin/ but never published) with make snapshot for local dry-runs; adds dist/ to .gitignore
  • Adds README "Install via Homebrew" section
  • Adds docs/release.md with the full release process + PAT setup

The first GoReleaser run (triggered by tagging v0.3.5 after this merges) will create Formula/holodeck.rb via an auto-opened PR.

How users will install after v0.3.5

brew tap nvidia/holodeck https://github.com/NVIDIA/holodeck
brew install nvidia/holodeck/holodeck
holodeck --help

Testing done

  • goreleaser check → passes (one non-fatal brews deprecation warning, tracked as follow-up)
  • make snapshot → produces 6 binary archives + checksums + source + draft formula in dist/ in ~11s
  • go build -ldflags "-X main.version=v0.3.5" ./cmd/cli && ./holodeck --version → prints holodeck version v0.3.5
  • YAML syntax validated for both new workflows
  • All 11 commits GPG-signed + DCO

Pre-push hardening (caught during principal-engineer review)

  • DCO sign-off in formula-bump commitscommit_msg_template in .goreleaser.yaml now includes a Signed-off-by: trailer so the auto-opened PR can pass the DCO required check.
  • Pre-flight PAT checkrelease.yaml fails fast with a clear error if HOMEBREW_TAP_GITHUB_TOKEN is unset (otherwise the release would publish but the formula PR would silently not open).
  • Explicit release.github owner/name pin.goreleaser.yaml pins NVIDIA/holodeck so a contributor running goreleaser release from a fork checkout doesn't accidentally publish to the wrong repo.

Required before tagging v0.3.5

  • Create HOMEBREW_TAP_GITHUB_TOKEN repo secret per docs/release.md → "One-time setup". Fine-grained PAT scoped to NVIDIA/holodeck with Contents: read/write and Pull requests: read/write. Without it, the new pre-flight check fails the release workflow immediately.

Follow-ups (out of scope for this PR)

  • Cut v0.3.5 to exercise the pipeline (after this merges + PAT is configured)
  • Post-release smoke test on a clean macOS arm64 machine
  • Migrate brews:homebrew: block when bumping GoReleaser to v3
  • Pre-existing doc bug: README "Install from source" mentions make build, but the Makefile only has make build-cli / make build-action (separate small PR)
  • Homebrew-core submission (future, once the tap is proven)
  • Signed binaries (cosign / sigstore — future)

Spec & plan

  • Spec: docs/superpowers/specs/2026-05-26-holodeck-brew-installable-design.md
  • Plan: docs/superpowers/plans/2026-05-26-holodeck-brew-installable.md

@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented May 26, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

Land the design for shipping holodeck via Homebrew using GoReleaser,
with the formula hosted in NVIDIA/holodeck main branch.

- Same-repo tap (Formula/holodeck.rb), custom-URL brew tap form
- GoReleaser cross-builds binaries + auto-generates the formula on each tag
- GitHub Action triggered on v* tags drives the release
- README install section + Makefile snapshot target for local dry-run
- Existing make release target removed (replaced by GoReleaser)

See docs/superpowers/specs/2026-05-26-holodeck-brew-installable-design.md.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
11 tasks covering:
- Task 1: cmd/cli version variable refactor for ldflag injection
- Task 2: .goreleaser.yaml config
- Task 3: Makefile snapshot target (replaces dead release: target)
- Task 4: release.yaml workflow on v* tags
- Task 5: homebrew-validate.yaml workflow
- Task 6: README Homebrew install section
- Task 7: docs/release.md release process doc
- Task 8: PR + review + merge
- Task 9: PAT setup (manual, one-time)
- Task 10: cut v0.3.5 bootstrap release
- Task 11: post-release smoke test

Resolves the spec's open questions:
- Branch protection: PR mode required (signed-commits + 1-reviewer rule)
- Version variable: add 'var version = "dev"' at package level
- Action pins: @v6 to match existing workflows

Spec: docs/superpowers/specs/2026-05-26-holodeck-brew-installable-design.md
Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Replace the hardcoded "0.2.18" version string with a package-level
`version` variable so GoReleaser can inject the real tag via
-ldflags -X main.version=<tag> at build time.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Cross-builds holodeck CLI for linux/darwin x amd64/arm64 and the
action binary for linux x amd64/arm64. Produces tar.gz archives,
sha256 checksums, source tarball, and auto-generates a Homebrew
formula at Formula/holodeck.rb via PR mode (required because main
has branch protection with required signed commits).

The PR mode token is read from $HOMEBREW_TAP_GITHUB_TOKEN at
release time — see docs/release.md for setup.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
The previous `make release` target cross-built binaries to bin/ but
never published them — dead code now that GoReleaser handles the
release flow.

`make snapshot` is the new local dry-run: runs GoReleaser in
--snapshot mode to validate the build matrix and inspect the
generated formula before tagging.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Triggers on `push: tags: v*`. Runs goreleaser release --clean which
publishes binaries to the GitHub Release and opens a PR updating
Formula/holodeck.rb.

Uses the workflow's default GITHUB_TOKEN to publish the release.
The formula-bump PR is opened via a separate PAT
(HOMEBREW_TAP_GITHUB_TOKEN) — required because the default token
cannot open PRs against a protected branch from within the same
repo workflow context.

See docs/release.md for PAT setup.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Runs `brew audit --strict --online` and `brew style` against
Formula/holodeck.rb on PRs that touch Formula/** and on pushes to
main. Path-filtered so it stays dormant until the first formula
lands.

Catches formula syntax errors before they reach users.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Documents the `brew tap nvidia/holodeck <url> && brew install`
flow. Retains the existing make-build path as 'Install from source'
for contributors.

The custom-URL tap form is required because the formula lives in
NVIDIA/holodeck rather than a dedicated homebrew-* repo.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Documents the GoReleaser-driven release flow, PAT setup for
HOMEBREW_TAP_GITHUB_TOKEN, dry-run via `make snapshot`, tag-and-push
ritual, post-release smoke test, and rollback procedure for bad
releases.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
GoReleaser's PR-mode commits are server-signed via the GitHub API
(satisfying main's required-signed-commits rule), but the commit
message had no `Signed-off-by:` trailer. The DCO bot is an
independently required status check on NVIDIA/holodeck:main, so
without a trailer the auto-opened formula-bump PR would land
in 'cannot merge' purgatory.

Add a `Signed-off-by:` trailer to the brews `commit_msg_template`
attributing the sign-off to the nvidia-ci identity. Update
docs/release.md so its explanation of the PAT-vs-default-token
rationale also covers DCO (previously claimed signed-commits
satisfied DCO, which is wrong).

Caught during pre-push principal-engineer review.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Two follow-ups from the pre-push principal-engineer review:

1. Pre-flight HOMEBREW_TAP_GITHUB_TOKEN check in release.yaml.
   If the secret is unset (or revoked/expired between rotations),
   GoReleaser would publish the release successfully and then
   silently skip the formula-bump PR — leaving users stuck on
   the previous formula version. Fail fast with a clear error
   pointing at docs/release.md instead.

2. Pin release.github.owner/name in .goreleaser.yaml.
   Without it, GoReleaser autodetects owner/repo from the git
   remote — fine in NVIDIA/holodeck CI, but a fork-foot-gun
   if a contributor accidentally runs `goreleaser release`
   (not --snapshot) from their fork checkout. Explicit pin
   removes the ambiguity. Verified locally: snapshot now
   produces URLs against NVIDIA/holodeck regardless of the
   local origin remote.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
Follow-up after rebasing onto upstream/main: upstream already added
`const ProgramVersion = "0.3.2"` in cmd/cli/main.go (PR #?). To
keep the established naming, the conflict-resolution in the
refactor(cli) commit converted ProgramVersion from `const` to `var`
(required for ldflag injection) and removed the now-redundant
`var version` declaration.

This commit updates .goreleaser.yaml to inject into the renamed
variable: -X main.version → -X main.ProgramVersion.

Verified: snapshot binary prints `holodeck version 0.3.4-SNAPSHOT-<sha>`.
Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
After rebasing onto upstream/main, three CI checks failed:

1. Unit test `TestNewApp` (cmd/cli/main_test.go) asserted
   `app.Version \!= "0.3.2"` — pinning the binary to a literal
   constant. That contract is invalid under the new ldflag
   injection model (`go test` builds with no ldflag, falling back
   to "dev"; release builds inject the tag). Rewrite the assertion
   to non-emptiness so the test doesn't need bumping on every tag.

2. `docs/release.md` triggered MD005, MD007, MD029, MD034 violations
   (inconsistent indent, bare URLs, ambiguous list ordering).
   Rewrite the doc with mdl-friendly structure: prose paragraphs
   where lists weren't load-bearing, code fence for the asset
   manifest, wrapped URLs in <>, and single-line ordered items.
   Content unchanged.

3. `docs/superpowers/{specs,plans}/*.md` triggered many style
   violations. These are internal AI-assisted planning artifacts
   (work-in-progress authoring docs), not user-facing documentation.
   Exclude `docs/superpowers/` from `scripts/mdlint.sh` with a
   commented rationale. The exclusion sits alongside the existing
   `docs/vendor/` exclusion.

Verified locally:
  - `go test ./cmd/cli/ -run TestNewApp` passes
  - `make snapshot` succeeds in 8s

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
@coveralls
Copy link
Copy Markdown

coveralls commented May 26, 2026

Coverage Report for CI Build 26458628453

Coverage remained the same at 48.745%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 11558
Covered Lines: 5634
Line Coverage: 48.75%
Coverage Strength: 0.54 hits per line

💛 - Coveralls

Round-two mdlint fix:
- MD013 line length: wrap all prose to 80 cols
- MD029 ordered list item prefix: use '1.' for every numbered
  step (mdl's :one style — also accepted by :one_or_ordered)
- Convert bare URLs to named reference links for readability

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
The previous mdlint exclusion only updated scripts/mdlint.sh, but
the docs_check.yaml workflow embeds its own `find` command and
doesn't call the script. Apply the same docs/superpowers exclusion
inline in the workflow so CI matches the script behaviour.

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
@ArangoGutierrez ArangoGutierrez marked this pull request as ready for review May 26, 2026 17:15
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