Explore shipping Aspire CLI as a homebrew-core formula
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
## Goal
Make `brew install aspire` work on macOS and Linux with no `brew tap` step, by listing the Aspire CLI as a formula in `Homebrew/homebrew-core`. This is an exploration / preparatory issue — the formula itself is not built yet.
## Pre-implementation spikes
These answer "is the design viable" before formula authoring starts.
- [x] **SDK strategy** → **vendor SDK per-RID via `resource` blocks, version sourced from release-tag `global.json`** (NOT `depends_on "dotnet"`). Shipping binary must be built with the SDK we develop/test against; homebrew-core `dotnet` tracks 1xx band only. Maintainer-pushback risk is real and documented; fallbacks listed.
- [x] **Brew extract-dir** → **option (a) install-time pre-extract** via `aspire setup --install-path libexec --force` (existing hidden command). No CLI change. Empirically confirmed: marker file + `versions//` + `bundle` symlink all created correctly.
- [x] **NativeAOT publish** → all 4 platforms (`osx-{arm64,x64}`, `linux-{x64,arm64}`) build cleanly with `clang` + `zlib1g-dev`. Binaries 36–38 MB unbundled, 130 MB bundled. Runtime deps = system stdlib only (no `libicu`/`libssl`). Ship `arm64_linux` from day one.
- [x] **`brew bump-formula-pr` automation** → custom rewriter + `gh pr create` from a dedicated `aspire-homebrew-bot` service account (classic PAT, `public_repo` scope). `brew bump-formula-pr` cannot refresh per-RID resources; `quire-io/quire-cli` is the template. Add `no_autobump!` to formula. Workflow lives in Aspire repo GitHub Actions, triggered post-tag.
- [x] **`test do` block** → `aspire new aspire-empty --language csharp --non-interactive --suppress-agent-init -o testpath/smoke -n SmokeTest`. The four flags are load-bearing (interactive prompts would abort in brew test sandbox). Empirically confirmed: creates `apphost.cs` + `aspire.config.json`. One network call ("Resolving template version") — pinnable via `--version` if maintainers push back.
- [x] **Cask + formula coexistence** → no `conflicts_with` declaration; rely on homebrew's native symlink-conflict behavior. Document interaction in `eng/homebrew-core/README.md`. Future homebrew-cask submission carries the `conflicts_with formula: "aspire"` annotation from its side. Empirical (uninstall behavior) deferred until Linux end-to-end CI.
- [x] **`brew audit --strict --new` dry-run** → `brew style`, `brew audit --strict`, `brew audit --new` all clean (exit 0, zero findings) on the draft formula. Includes online checks (URL reachability, license classification, notability).
## Bonus: bundle-functional build (was deferred, now resolved)
- [x] **Single-shot bundled build** → `eng/homebrew-core/build-cli.sh` wraps `eng/Bundle.proj` and produces a NativeAOT binary with the Aspire bundle (managed runtime, DCP, templates) embedded. End-to-end smoke on osx-arm64 passes: build → `aspire setup` pre-extract → `aspire new aspire-empty` creates a real project. Includes a small `Bundle.proj` fix to forward `AspireCliChannel` (was being silently dropped before).
## Repo artifacts on `ankj/homebrew-core-formula` branch
- `eng/Bundle.proj` — forwards `AspireCliChannel` (1-line + comment fix)
- `eng/homebrew-core/aspire.rb.template` — canonical formula source-of-truth
- `eng/homebrew-core/build-cli.sh` — single-shot bundled build wrapper for the formula's install block
- `eng/homebrew-core/README.md` — design rationale + validation-ring documentation
## Open decisions (still need leadership input)
- Formula name `aspire` — accept maintainer pushback fallback (`aspire-cli`)?
- Bump-PR fork ownership / auth identity (personal vs org-owned vs service account `aspire-homebrew-bot`).
- Target release tag for first submission — must already ship brew self-update gating.
- **SDK-vendoring pushback contingency**: if maintainers reject `resource`-pinned SDK on first PR, ranked fallbacks are (1) contribute 2xx-band tracking to upstream dotnet formula, (2) accept SDK drift via `depends_on "dotnet"`, (3) drop homebrew-core and keep the custom tap.
## Spike reports
Detailed write-ups for each spike are in the session worktree (not committed); summaries in this issue.
## Next: Phase 2 onward
The plan's Phase 2 (CLI self-update gating for brew route) and Phase 3+ (full formula authoring, validation pipeline, bump automation, first submission) can now proceed against the spike findings.
## Phase progress
- [x] **Phase 2: CLI self-update gating for the brew route** — `aspire update --self` now gates on the install sidecar's `"source":"brew"` field, prints `brew upgrade aspire`, and exits 0 without invoking the GitHub-binary downloader. Mirrors the existing dotnet-tool and npm gates at all four call sites in `UpdateCommand.cs` (direct self-update, post-project-update prompt, pre-guest-project-update prompt, no-project-found prompt suppression). Includes unit tests for `BrewInstallDetection` and integration tests for each gate site. Audit: `ICliDownloader` has a single consumer (this command), so no other code path needs the gate; `aspire setup` only extracts the embedded bundle and does not replace the binary.
- [ ] Phase 3+ — formula authoring, validation pipeline, bump automation, first submission.
Contributor guide
Assessment
This issue has not been assessed yet.