ci(publish): wire Scoop bucket + Homebrew tap jobs (D3 §3b/§3c)
Add sibling publish.yaml jobs (scoop-bucket, homebrew-tap) that render a manifest from the release .sha256 sidecars and idempotently push it to the org-level lazyeval/scoop-bucket and lazyeval/homebrew-tap repos, using the scoped lazyeval-ci bot token (LAZYEVAL_PKG_TOKEN). Render logic lives in dependency-free bash (the CI image has no jq/ruby): scripts/render-scoop-manifest.sh and scripts/render-homebrew-formula.sh. scripts/test-package-renders.sh exercises both: it validates the Scoop JSON with node and asserts fields on both manifests, and additionally runs `ruby -c` on the formula where ruby is present (dev box), skipping it gracefully otherwise. A new ci.yaml `manifests` job runs that test on every push so a render regression surfaces immediately, not at the next manual publish dispatch. The CI image has no ruby, so in CI the gate covers the Scoop JSON (node) and field assertions for both manifests; the formula's Ruby syntax is checked dev-side only (the static heredoc's variable parts cannot introduce syntax errors). - Scoop: x64 (gnu) + arm64 (gnullvm); #/-rename fragment so the bin shim is version-stable; checkver, no autoupdate (the pipeline is the updater). - Homebrew: on_macos/on_linux x arch bare-binary formula; no Windows. Docs: ADR-0056 Amendment 2 (+ README index, requirements D3). Unverified pending real use: scoop/brew install, the HEAD:main branch assumption, macOS Gatekeeper-via-brew on the ad-hoc-signed binary.
This commit is contained in:
@@ -110,3 +110,69 @@ API pre-check + `cargo publish` as the backstop) — so future
|
||||
Scoop/Homebrew/winget jobs can be added alongside without breaking one
|
||||
another or re-runs. The first such job's `tag`-vs-`Cargo.toml` guard
|
||||
mirrors `release.yaml`.
|
||||
|
||||
## Amendment 2 — 2026-06-19: Scoop bucket + Homebrew tap (D3 §3b/§3c)
|
||||
|
||||
Two more package managers wired as **sibling `publish.yaml` jobs**
|
||||
(`scoop-bucket`, `homebrew-tap`), following Amendment 1's independent +
|
||||
idempotent pattern. Each fetches the release's `.sha256` sidecars, renders
|
||||
a manifest, and commits it into a per-manager repo.
|
||||
|
||||
**Repos — org-level and multi-package.** Both live under a new **`lazyeval`
|
||||
Gitea organisation** (created with the `oli` account, which gives the
|
||||
`git.lazyeval.net/lazyeval/...` paths): `lazyeval/scoop-bucket` and
|
||||
`lazyeval/homebrew-tap`. A Scoop *bucket* and a Homebrew *tap* are by
|
||||
definition **collections of manifests**, so these are reusable for future
|
||||
tools, not single-package repos. Homebrew's `homebrew-` repo-name prefix is
|
||||
mandatory (→ referenced as `lazyeval/tap`); Scoop's bucket name is free.
|
||||
Users: `scoop bucket add lazyeval <url>` (the label is local/arbitrary;
|
||||
only the URL owner is real) then `scoop install rdbms-playground`; and
|
||||
`brew tap lazyeval/tap https://git.lazyeval.net/lazyeval/homebrew-tap`
|
||||
(the explicit-URL form — the `user/repo` shorthand assumes GitHub) then
|
||||
`brew install lazyeval/tap/rdbms-playground`.
|
||||
|
||||
**Credential — a scoped bot user, not an `oli` PAT.** Gitea PATs scope by
|
||||
**permission category, not per-repository** (`write:repository` grants
|
||||
write to *every* repo the account can reach — there is no repo picker like
|
||||
GitHub fine-grained PATs). So an `oli` token would also be able to push to
|
||||
`oli/rdbms-playground` itself. Instead a dedicated bot user **`lazyeval-ci`**
|
||||
is a member of a `lazyeval` org team with **Write** to the package repos
|
||||
only; its `write:repository` PAT is therefore effectively scoped to those
|
||||
repos and **cannot touch the main project repo**. Stored as the
|
||||
`LAZYEVAL_PKG_TOKEN` Actions secret on `oli/rdbms-playground` (where the
|
||||
workflow runs — *not* an org secret, which wouldn't reach a user-repo
|
||||
workflow; *not* on the target repos, which only receive pushes). Passed via
|
||||
`env:` (never inlined), so it stays masked and only materialises in the
|
||||
clone URL at runtime; pushes go to `HEAD:main` (assumes the repos default
|
||||
to `main`).
|
||||
|
||||
**Render scripts are dependency-free bash.** The CI job container is
|
||||
`node:22-bookworm-slim` — **no jq, no ruby** — so
|
||||
`scripts/render-{scoop-manifest,homebrew-formula}.sh` are pure bash
|
||||
(heredocs, no external deps) taking a version + the relevant hashes and
|
||||
emitting the manifest on stdout. `scripts/test-package-renders.sh` is their
|
||||
test (JSON validated with `node` — present in the image — plus `jq`/`ruby`
|
||||
when available; field-level assertions). The job validates the rendered
|
||||
Scoop JSON with `node -e JSON.parse` before committing.
|
||||
|
||||
**Manifest specifics.**
|
||||
- *Scoop* (`rdbms-playground.json` at bucket root): `64bit` =
|
||||
`x86_64-pc-windows-gnu.exe`, `arm64` =
|
||||
`aarch64-pc-windows-gnullvm.exe`; each URL carries a
|
||||
`#/rdbms-playground.exe` rename fragment so the `bin` shim resolves
|
||||
regardless of version. Carries `checkver` (lets `scoop status` / the
|
||||
community excavator see lag) but **no `autoupdate`** — our pipeline is the
|
||||
updater.
|
||||
- *Homebrew* (`Formula/rdbms-playground.rb`): `on_macos`/`on_linux` ×
|
||||
`on_arm`/`on_intel` selecting the four bare-binary assets (macOS direct;
|
||||
Linux = the static `-musl` build). **Windows absent** — Homebrew has no
|
||||
Windows port. `install` drops the single staged binary under a stable
|
||||
name; the `test` block runs `--version`.
|
||||
|
||||
**Unverified (validate on first real use):** an actual `scoop install` and
|
||||
`brew install`/`brew test`; the `HEAD:main` default-branch assumption; and
|
||||
whether macOS Gatekeeper accepts the **ad-hoc-signed** mac binary via
|
||||
`brew` (execution should be fine — ad-hoc satisfies arm64's signing
|
||||
requirement and `brew`'s curl download sets no quarantine xattr, unlike a
|
||||
browser download — but this rides on the still-parked Developer-ID signing
|
||||
decision). **Remaining D3:** winget (komac on Linux CI, or a manual PR).
|
||||
|
||||
Reference in New Issue
Block a user