Skip to content

fix(cli): copy Go binary for musl builds from glibc package#5200

Merged
avallete merged 3 commits into
developfrom
fix/ci-publish-release
May 7, 2026
Merged

fix(cli): copy Go binary for musl builds from glibc package#5200
avallete merged 3 commits into
developfrom
fix/ci-publish-release

Conversation

@avallete
Copy link
Copy Markdown
Member

@avallete avallete commented May 7, 2026

What kind of change does this PR introduce?

Bug fix and metadata polish.

  • Bug fix: Ensures Linux musl optional binary packages built with legacy shell include supabase-go by copying the matching static glibc Go binary into the musl package output during apps/cli/scripts/build.ts.
  • Feature / packaging: Adds standard npm package.json fields (homepage, bugs, repository, plus main-package description / license where applicable) on supabase and the @supabase/cli-* platform packages.

What is the current behavior?

  • Musl builds compile the Bun CLI but, in legacy mode, may omit supabase-go even though LegacyGoProxy expects to resolve it—breaking Go-backed flows on musl installs.
  • Published packages lack homepage / bugs / repository links that npm and tooling often surface.

What is the new behavior?

  • For shell === "legacy" musl targets, after the Bun compile step the script finds the glibc target with the same nfpmArch, copies packages/<glibc-pkg>/bin/supabase-go to packages/<musl-pkg>/bin/supabase-go, and logs the copy—so published musl tarballs match what LegacyGoProxy resolves.
  • npm metadata is consistent across the main CLI and optional architecture packages (repo URL + per-package directory, issues URL, homepage).

No UI changes; screenshots not applicable.

Additional context

  • The inline rationale in 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.
  • Files touched besides build.ts: apps/cli/package.json and each packages/cli-*/package.json that gained metadata.

avallete added 2 commits May 7, 2026 10:50
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.
@avallete avallete requested a review from a team as a code owner May 7, 2026 08:55
@avallete avallete enabled auto-merge (squash) May 7, 2026 09:12
@avallete avallete merged commit 62509de into develop May 7, 2026
9 checks passed
@avallete avallete deleted the fix/ci-publish-release branch May 7, 2026 09:12
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>
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