fix(cli): copy Go binary for musl builds from glibc package#5200
Merged
Conversation
This update modifies the build script to include a step that copies the Go binary from the corresponding glibc package when building musl binaries. This ensures that the published musl npm package contains the necessary supabase-go binary for compatibility with LegacyGoProxy. The change enhances the build process by ensuring the correct binary is available for different target architectures.
Coly010
approved these changes
May 7, 2026
5 tasks
Coly010
added a commit
that referenced
this pull request
May 7, 2026
## Current Behavior
The release-CI smoke test for the npm/Verdaccio sub-test reports `[npm]
Error: ShellError: Failed with exit code 1` on linux + macos with no
further detail. The `await $` invocation in
`apps/cli/tests/helpers/npm-registry.ts` swallows stderr on non-zero
exit, so the actual cause is invisible.
Worse: even when the test passes, it has been doing so for a false
reason. With the diagnostics added in this PR, two regressions surface
that have been masked for some time:
1. `npm install` ignores the test project's `.npmrc` in environments
where pnpm has set `npm_config_*` env vars. The install silently
resolves `supabase` against `registry.npmjs.org` instead of the local
Verdaccio, fetching the public 2.x CLI (76 transitive deps). The version
regex `/^\d+\.\d+\.\d+/` matches whatever that package prints, so the
smoke test reports PASS while exercising none of our build artifacts.
The recent CI failure is the public package's postinstall now failing on
the runners — the symptom, not the cause.
2. Verdaccio is configured with `uplinks: {}`, so even when the local
registry is hit, transitive deps from the umbrella's runtime
`dependencies` (`@clack/prompts`, `effect`, `ink`, `react`, …) 404.
Those deps are bundled into `dist/supabase.js` at build time but `npm
install` still resolves them.
`b2b397af`'s `publishConfig.executableFiles` fix was correct —
diagnostics confirm tarball entries land at mode `0755`. The smoke test
just never reached them.
Smoke tests also currently only run post-merge in `release-shared.yml`.
Packaging regressions therefore slip through PR review and only surface
when a release is cut — 2.99.0-beta.1 being the most recent example.
## New Behavior
**Diagnostics (`2beff61a`)**
- Capture stdout / stderr / exit-code on the verify spawn instead of
letting Bun's `\$` collapse them into an opaque \`ShellError\`.
- After publish, \`tar -tvf\` each platform tarball from Verdaccio
storage and log the \`bin/\` mode bits — directly answers whether
\`executableFiles\` is being honoured.
- After install, dump the resolved tree: \`.bin/supabase\`'s symlink
target + mode, the umbrella shim's mode, every unpacked
\`@supabase/cli-*/bin/\` entry, and each platform package's
\`name@version\`.
- On verify failure, retry against the platform binary directly to
isolate "shim broken" vs "binary broken".
- \`runCli\` (already in \`release-shell.ts\`) is now the single spawn
primitive for both checks; \`verifyExpectedShell\`'s failure detail
includes captured stderr.
- Smoke-test runners log \`e.stack\` + \`e.stdout\` / \`e.stderr\`
instead of \`\${e}\` on every catch.
**Fix (`2beff61a`)**
- Pass \`--registry \${verdaccio_url}\` explicitly to \`npm install\`.
The CLI flag wins over env vars and \`.npmrc\`, so the install can no
longer fall through to the public registry.
- Pin \`supabase\` and \`@supabase/*\` to local-only resolution in
Verdaccio's \`packages\` config; configure an \`npmjs\` uplink for
everything else so the umbrella's bundled-in runtime deps still resolve.
Mirrors what a real \`npm install supabase\` does today.
**PR-CI smoke job (`2b9e2bee`)**
\`.github/workflows/smoke-test-pr.yml\` is a thin caller that reuses
\`release-shared.yml\` with \`dry_run: true\`. The shared workflow
already gates publish jobs on \`!inputs.dry_run\`, so only \`build\` +
\`smoke-test\` actually run.
- Triggers on \`pull_request\` events with paths under \`apps/cli/**\`,
plus the workflow files themselves so changes to the workflow re-trigger
on the PR that introduced them.
- Synthesises a PR-scoped version (\`0.0.0-pr-\${PR_NUMBER}\`) so
concurrent PRs do not collide on the build artifact name.
- Skips drafts and cancels superseded runs.
## Test plan
- [x] \`nx run supabase:check:all\` (types/lint/fmt/knip).
- [x] Local smoke run with stub binaries: \`0.0.1-smoke\` resolves to
the local umbrella (not the public 2.x CLI), platform binary mode is
\`0755\`, \`supabase --version\` returns \`0.0.1-smoke\`.
- [ ] Release-CI \`smoke-test\` matrix passes on this branch's run.
- [ ] On this PR, the new \`Smoke Test (PR) / smoke / build\` and four
\`Smoke Test (PR) / smoke / smoke-test (...)\` jobs appear and pass.
- [ ] Confirm \`publish\` / \`publish-homebrew\` / \`publish-scoop\`
jobs from the called workflow report skipped on this PR.
## Related Issue(s)
Follow-up to #5199, #5200, #5201.
avallete
added a commit
that referenced
this pull request
May 20, 2026
Fixes the backfill-release-notes workflow so it actually produces the right notes for an arbitrary historical tag, and moves the engine out of inline bash into a reusable bun script. ## Why the original workflow couldn't produce correct notes Backfilling an old tag isn't symmetric with running semantic-release on a normal push — it trips on five separate things at once, each of which silently sends it down a wrong path: - **Branch detection.** `cycjimmy/semantic-release-action` reads the branch via `env-ci` (`$GITHUB_REF` / `$GITHUB_REF_NAME`), not `git rev-parse --abbrev-ref HEAD`. Dispatching the workflow from any branch other than `develop`/`main` left semantic-release looking at an unconfigured branch and silently emitting no `new_release_*` outputs. - **"Behind remote" check.** semantic-release runs `git ls-remote <repositoryUrl> <branch>` and exits silently if the remote tip differs from local HEAD — which is always true when re-staging at an old tag. - **Channel notes for historical tags.** semantic-release reads `git log --notes=refs/notes/semantic-release*`. `actions/checkout` doesn't fetch `refs/notes/*` by default, and some historical tags (e.g. `v2.99.0-beta.1`) have no channel annotation at all — leaving them as `channels=[null]`, which the prerelease filter drops. semantic-release then walks past them and `lastRelease` drifts back far enough to drag unrelated commits into the changelog. - **Drift in `release.branches` config.** Before commit `2515885` (May 11) the `develop` branch had no explicit `"channel": "beta"`, so semantic-release defaulted the channel to the branch name; before #5316 the plugin chain didn't include `release-notes-generator`. A historical checkout therefore produces empty or misclassified notes. - **Output format.** Parsing `cycjimmy/semantic-release-action`'s stdout returns marked-terminal rendered ANSI/whitespace, not raw markdown — so even when the right notes were computed, the GH release body would render wrong. ## What this PR does Moves the workflow's logic into `apps/cli/scripts/backfill-release-notes.ts` and calls `semantic-release` *programmatically* so it can return `nextRelease.notes` as raw markdown directly. The script's setup works around each of the issues above in a temp clone (so the original workspace stays clean): 1. Clones the repo to a temp directory and fetches `refs/notes/*` from both the source repo and origin. 2. Synthesises a `develop`/`main` branch at the tag's commit and seeds the other configured branch from `refs/remotes/origin/<other>`. 3. Backfills missing channel notes on every reachable tag (`v*-beta.*` → `beta`, `v*-alpha.*` → `alpha`, else `latest`). 4. Patches the temp clone's `apps/cli/package.json` with the *current* `release` config so historical checkouts use today's `channel: "beta"` and plugin chain. 5. Uses `git config --local url.<local>.insteadOf <github>` so semantic-release's `ls-remote` silently targets the local clone (satisfying the "behind remote" check) while `repositoryUrl` stays the real GitHub URL — keeping commit/PR links correct in the rendered notes. 6. Calls `semanticRelease({ dryRun: true, noCi: true, repositoryUrl }, { cwd: ... })` and prints `nextRelease.notes` to stdout, or with `--apply` calls `gh release edit --notes-file`. The workflow itself reduces to: checkout, setup, `bun apps/cli/scripts/backfill-release-notes.ts --tag $TAG`, mirror to the job summary, then conditionally re-run with `--apply`. ## Sample output (`v2.99.0-beta.2`) ```sh $ bun apps/cli/scripts/backfill-release-notes.ts --tag v2.99.0-beta.2 ``` ```markdown # [2.99.0-beta.2](v2.99.0-beta.1...v2.99.0-beta.2) (2026-05-20) ### Bug Fixes * **ci:** make release re-cut reliable after stale-bytes runs ([#5209](#5209)) ([ef1b13a](ef1b13a)), closes [#5205](#5205) [#5207](#5207) [#5205](#5205) [#5207](#5207) [#App](https://github.com/supabase/cli/issues/App) * **cli:** make npm publish idempotent for partial-failure re-runs ([#5207](#5207)) ([bbeaec7](bbeaec7)), closes [#release-creation](https://github.com/supabase/cli/issues/release-creation) * **cli:** mark platform binaries executable in pnpm publish tarball ([#5201](#5201)) ([b2b397a](b2b397a)), closes [#5199](#5199) * **cli:** smoke test now actually verifies our local build ([#5205](#5205)) ([9109056](9109056)), closes [#5199](#5199) [#5200](#5200) ``` Exactly the 5 commits between `v2.99.0-beta.1` and `v2.99.0-beta.2`, with GitHub links rendered against `https://github.com/supabase/cli` regardless of the local-clone redirection. ## Related The same `release.repositoryUrl` / `ls-remote` interaction and channel-notes drift will need to be addressed on the production publish path (`.github/workflows/release-shared.yml`) once Stage B of the changelog plumbing (`claude/wire-release-notes-publish`) lands. --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What kind of change does this PR introduce?
Bug fix and metadata polish.
supabase-goby copying the matching static glibc Go binary into the musl package output duringapps/cli/scripts/build.ts.package.jsonfields (homepage,bugs,repository, plus main-packagedescription/licensewhere applicable) onsupabaseand the@supabase/cli-*platform packages.What is the current behavior?
supabase-goeven though LegacyGoProxy expects to resolve it—breaking Go-backed flows on musl installs.What is the new behavior?
shell === "legacy"musl targets, after the Bun compile step the script finds the glibc target with the samenfpmArch, copiespackages/<glibc-pkg>/bin/supabase-gotopackages/<musl-pkg>/bin/supabase-go, and logs the copy—so published musl tarballs match what LegacyGoProxy resolves.directory, issues URL, homepage).No UI changes; screenshots not applicable.
Additional context
build.ts: Go is built with CGO disabled (static), so the glibc-labeled Linux binary is appropriate to reuse on musl for the same CPU arch.build.ts:apps/cli/package.jsonand eachpackages/cli-*/package.jsonthat gained metadata.