Skip to content

feat(cli): automate Scoop manifest updates to upstream#5260

Open
avallete wants to merge 5 commits into
developfrom
claude/sync-scoop-releases-aygAQ
Open

feat(cli): automate Scoop manifest updates to upstream#5260
avallete wants to merge 5 commits into
developfrom
claude/sync-scoop-releases-aygAQ

Conversation

@avallete
Copy link
Copy Markdown
Member

Add automation to submit Scoop manifest updates to the upstream ScoopInstaller/Main bucket for stable releases.

Changes:

  • New script update-scoop-main.ts: Automates the process of opening pull requests against ScoopInstaller/Main with updated Scoop manifests. The script:

    • Clones the fork, syncs it with upstream, and creates a feature branch
    • Generates the manifest using shared logic
    • Detects if the manifest is already current upstream (e.g., from the excavator bot) and exits cleanly
    • Pushes the branch and opens a PR, gracefully handling cases where a PR already exists
  • Extracted shared manifest builder: Moved manifest generation logic into lib/scoop-manifest.ts to eliminate duplication between update-scoop.ts (our own bucket) and the new update-scoop-main.ts (upstream PR). This ensures both buckets produce identical manifests.

  • New workflow job publish-scoop-main: Added to .github/workflows/release-shared.yml to run after publish-scoop. The job:

    • Only runs for stable releases (not beta, not dry-run)
    • Uses a GitHub App token scoped to the scoop-main fork
    • Invokes the new script to open the upstream PR
  • Updated update-scoop.ts: Refactored to use the shared buildScoopManifest and readChecksums functions from the new library module.

  • Updated package.json knip ignore: Changed scripts/*.ts to scripts/**/*.ts to properly ignore the new lib/ subdirectory.

This enables the stable CLI to be automatically submitted to the upstream Scoop bucket without manual intervention, while beta releases continue to use the private supabase/scoop-bucket.

https://claude.ai/code/session_01MJzvj7b1VuL5tcVmDGRFas

After a stable release, push the manifest to our own scoop-bucket and
also open a PR from supabase/scoop-main (our fork of
ScoopInstaller/Main) to upstream so users of the default Scoop bucket
pick up new versions immediately, rather than waiting for the upstream
excavator bot to catch up.

The PR rewrites the upstream manifest to match the format we produce
for supabase/scoop-bucket (.zip artifacts with version in filename,
hashes embedded). A shared builder keeps the two scripts from
drifting.
@avallete avallete requested a review from a team as a code owner May 18, 2026 11:12
Copy link
Copy Markdown
Member Author

Why we're not sourcing Scoop/Brew from the npm registry

While researching this PR I looked into the alternative pattern of pointing Scoop (and Homebrew) at npm tarballs as their CDN — the only example in ScoopInstaller/Main is bucket/gactions.json, which works like this:

  • Tarball URL: https://registry.npmjs.org/<pkg>/-/<basename>-<version>.tgz
  • extract_dir: "package\bin" (tarballs unpack under package/)
  • checkver against /<pkg>/latest, hash from $.dist.shasum (note: sha1: prefix required)
  • bin aliases a platform-specific prebuilt like gactions-win32-x64.exe → gactions

In theory we could do the same: ship Windows binaries inside our npm tarballs (we already publish @supabase/cli-win32-x64 etc. via the per-platform wrapper packages), then have a single source of truth — "npm release works ⇒ everything works."

We're not doing this. Reasons:

  1. GitHub Releases is already our canonical artifact source. Goreleaser/semantic-release publishes signed .zip and .tar.gz per platform on each tag. Scoop, Homebrew, the install script, and our own download tooling all consume the same artifacts. Switching Scoop/Brew to npm would mean introducing a second binary distribution channel without retiring the first — net more surface, not less.

  2. Npm publish is downstream of the release, not the release itself. In our pipeline, GitHub Release + artifacts come first; npm dist-tag publish is one of several fan-out steps. If npm fails or lags, GitHub Release is still authoritative. Inverting that — making Scoop/Brew block on npm — couples package-manager updates to an extra hop that can fail independently.

  3. Hash story is weaker. Npm exposes dist.shasum (SHA‑1). Scoop accepts it with a sha1: prefix, but SHA‑1 is a step down from the SHA‑256 we already publish in checksums.txt next to the GitHub Release.

  4. Brew's npm path requires a Node runtime on the user's machine. The "tarball-as-CDN" approach (gactions-style) avoids that, but at that point npm is just a slower mirror of files we already host on github.com/.../releases/download/. There's no real benefit.

  5. Versioning indirection. checkver against registry.npmjs.org/.../latest works, but binds Scoop's notion of "latest" to npm's dist-tag rather than the GitHub release tag (the thing the rest of the docs, install script, and CI all reference). One source of truth — the GitHub release tag — is easier to reason about during incidents.

The PR keeps the existing model: stable release lands → artifacts on GitHub → update-scoop.ts pushes to our bucket → update-scoop-main.ts opens a PR to upstream. Both manifests point at the same GitHub Release URLs, so a successful release is sufficient to make every installer work.


Generated by Claude Code

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