From 683317fcac2ba90954b749938ac48a6d2c8bda6d Mon Sep 17 00:00:00 2001 From: Andrew Valleteau Date: Tue, 19 May 2026 10:48:27 +0200 Subject: [PATCH 1/2] fix(cli): fix smoke test shell and npm tag quoting in release workflow (#5294) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes two issues in the release workflow that affect cross-platform compatibility and npm publishing: - **Smoke test shell**: Added explicit `shell: bash` to the smoke test step. The Windows runner defaults to PowerShell, which treats `${VERSION}` and `${NPM_TAG}` as empty variables (PowerShell uses `$env:VAR` syntax). This ensures consistent variable expansion across the ubuntu/macos/windows matrix. - **NPM tag quoting**: Removed unnecessary double-quoting of the `${NPM_TAG}` variable in the publish step (`""${NPM_TAG}""` → `"${NPM_TAG}"`). The extra quotes were being passed literally to the script, causing incorrect tag values. https://claude.ai/code/session_018LbJcjCcwYkz86cN5Qw19s Co-authored-by: Claude --- .github/workflows/release-shared.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-shared.yml b/.github/workflows/release-shared.yml index df0990c4d..726967779 100644 --- a/.github/workflows/release-shared.yml +++ b/.github/workflows/release-shared.yml @@ -134,6 +134,10 @@ jobs: run: chmod +x packages/cli-*/bin/supabase || true - name: Run smoke tests + # Force bash so ${VERSION}/${NPM_TAG} expand identically across the + # ubuntu/macos/windows matrix — windows-latest defaults to pwsh, which + # treats those as empty PowerShell variables (env vars are `$env:VAR`). + shell: bash run: pnpm run test:smoke -- --version "${VERSION}" --tag "${NPM_TAG}" working-directory: apps/cli @@ -164,7 +168,7 @@ jobs: run: pnpm exec bun apps/cli/scripts/sync-versions.ts --version "${VERSION}" - name: Publish to npm - run: pnpm exec bun apps/cli/scripts/publish.ts --tag ""${NPM_TAG}"" + run: pnpm exec bun apps/cli/scripts/publish.ts --tag "${NPM_TAG}" # Push the version tag to origin as soon as npm has the bytes, before any # downstream step that can fail. Without this, a failure in the GH-release From e1f857ab0fd10ea610d5bbb6d879ace2ceeb594b Mon Sep 17 00:00:00 2001 From: Vaibhav <117663341+7ttp@users.noreply.github.com> Date: Tue, 19 May 2026 14:55:03 +0530 Subject: [PATCH 2/2] fix: hide legacy hidden subcommands (#5295) ## TL;DR hide legacy subcommands from help output when the go cli marks them hidden, while keeping them callable ## prob the legacy ts cli still showed a few subcommands in `--help` that the go cli explicitly marks as hidden: - `branches disable` - `db branch` - `db remote` - `db test` this happened because the existing hidden help mechanism only covered flags, not subcommands change extends the same pattern to hidden subcommands and annotates the affected parent commands accordingly execution is unchanged, so the subcommands remain callable directly ## ref: - extends https://github.com/supabase/cli/pull/5278 --- .../commands/branches/branches.command.ts | 2 + apps/cli/src/legacy/commands/db/db.command.ts | 2 + apps/cli/src/shared/cli/hidden-flag.ts | 36 ++++++++++++++-- .../src/shared/cli/hidden-flag.unit.test.ts | 42 +++++++++++++++++++ 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/apps/cli/src/legacy/commands/branches/branches.command.ts b/apps/cli/src/legacy/commands/branches/branches.command.ts index 223414eda..21d3eda1c 100644 --- a/apps/cli/src/legacy/commands/branches/branches.command.ts +++ b/apps/cli/src/legacy/commands/branches/branches.command.ts @@ -1,4 +1,5 @@ import { Command } from "effect/unstable/cli"; +import { withHiddenSubcommands } from "../../../shared/cli/hidden-flag.ts"; import { legacyBranchesListCommand } from "./list/list.command.ts"; import { legacyBranchesCreateCommand } from "./create/create.command.ts"; import { legacyBranchesGetCommand } from "./get/get.command.ts"; @@ -11,6 +12,7 @@ import { legacyBranchesDisableCommand } from "./disable/disable.command.ts"; export const legacyBranchesCommand = Command.make("branches").pipe( Command.withDescription("Manage Supabase preview branches."), Command.withShortDescription("Manage preview branches"), + withHiddenSubcommands(["disable"]), Command.withSubcommands([ legacyBranchesListCommand, legacyBranchesCreateCommand, diff --git a/apps/cli/src/legacy/commands/db/db.command.ts b/apps/cli/src/legacy/commands/db/db.command.ts index 60c2b170f..21e637f9a 100644 --- a/apps/cli/src/legacy/commands/db/db.command.ts +++ b/apps/cli/src/legacy/commands/db/db.command.ts @@ -1,4 +1,5 @@ import { Command } from "effect/unstable/cli"; +import { withHiddenSubcommands } from "../../../shared/cli/hidden-flag.ts"; import { legacyDbDiffCommand } from "./diff/diff.command.ts"; import { legacyDbDumpCommand } from "./dump/dump.command.ts"; import { legacyDbPushCommand } from "./push/push.command.ts"; @@ -16,6 +17,7 @@ import { legacyDbSchemaCommand } from "./schema/schema.command.ts"; export const legacyDbCommand = Command.make("db").pipe( Command.withDescription("Manage Postgres databases."), Command.withShortDescription("Manage databases"), + withHiddenSubcommands(["branch", "remote", "test"]), Command.withSubcommands([ legacyDbDiffCommand, legacyDbDumpCommand, diff --git a/apps/cli/src/shared/cli/hidden-flag.ts b/apps/cli/src/shared/cli/hidden-flag.ts index f83c877c6..2641242f6 100644 --- a/apps/cli/src/shared/cli/hidden-flag.ts +++ b/apps/cli/src/shared/cli/hidden-flag.ts @@ -13,6 +13,12 @@ export const LegacyHiddenFlags: Context.Reference> = Context defaultValue: () => new Set(), }); +export const LegacyHiddenSubcommands: Context.Reference> = Context.Reference< + ReadonlySet +>("supabase/legacy/LegacyHiddenSubcommands", { + defaultValue: () => new Set(), +}); + const hiddenFlagNames = new WeakMap>(); const collectSingleNames = (param: Param.Param): Array => { @@ -70,14 +76,36 @@ export const withHiddenFromConfig = return Command.annotate(cmd, LegacyHiddenFlags, hidden); }; +export const withHiddenSubcommands = + (names: ReadonlyArray) => + ( + cmd: Command.Command, + ): Command.Command => + Command.annotate(cmd, LegacyHiddenSubcommands, new Set(names)); + export const stripHiddenFlagsFromHelpDoc = (doc: HelpDoc.HelpDoc): HelpDoc.HelpDoc => { - const hidden = Context.get(doc.annotations, LegacyHiddenFlags); - if (hidden.size === 0) return doc; - const filteredFlags = doc.flags.filter((flag) => !hidden.has(flag.name)); - const filteredGlobalFlags = doc.globalFlags?.filter((flag) => !hidden.has(flag.name)); + const hiddenFlags = Context.get(doc.annotations, LegacyHiddenFlags); + const hiddenSubcommands = Context.get(doc.annotations, LegacyHiddenSubcommands); + if (hiddenFlags.size === 0 && hiddenSubcommands.size === 0) return doc; + const filteredFlags = doc.flags.filter((flag) => !hiddenFlags.has(flag.name)); + const filteredGlobalFlags = doc.globalFlags?.filter((flag) => !hiddenFlags.has(flag.name)); + const filteredSubcommands = doc.subcommands?.flatMap((group) => { + const commands = group.commands.filter((command) => !hiddenSubcommands.has(command.name)); + if (commands.length === 0) return []; + return [ + { + ...group, + commands: commands as unknown as readonly [ + HelpDoc.SubcommandDoc, + ...Array, + ], + }, + ]; + }); return { ...doc, flags: filteredFlags, + ...(filteredSubcommands !== undefined && { subcommands: filteredSubcommands }), ...(filteredGlobalFlags !== undefined && { globalFlags: filteredGlobalFlags }), }; }; diff --git a/apps/cli/src/shared/cli/hidden-flag.unit.test.ts b/apps/cli/src/shared/cli/hidden-flag.unit.test.ts index 474293a2c..356cd980f 100644 --- a/apps/cli/src/shared/cli/hidden-flag.unit.test.ts +++ b/apps/cli/src/shared/cli/hidden-flag.unit.test.ts @@ -3,9 +3,11 @@ import { Command, Flag, type HelpDoc } from "effect/unstable/cli"; import { describe, expect, it } from "vitest"; import { LegacyHiddenFlags, + LegacyHiddenSubcommands, stripHiddenFlagsFromHelpDoc, withHidden, withHiddenFromConfig, + withHiddenSubcommands, } from "./hidden-flag.ts"; const flagDoc = (name: string): HelpDoc.FlagDoc => ({ @@ -33,6 +35,15 @@ const helpDocWithHidden = ( annotations: Context.make(LegacyHiddenFlags, new Set(hidden)), }); +const helpDocWithHiddenSubcommands = ( + hidden: ReadonlyArray, + overrides: Partial, +): HelpDoc.HelpDoc => + helpDoc({ + ...overrides, + annotations: Context.make(LegacyHiddenSubcommands, new Set(hidden)), + }); + // Reach into the internal command shape to obtain the help doc the formatter // would render. Effect builds this from `Command.annotations`, which is the // contract `withHiddenFromConfig` relies on. @@ -110,6 +121,15 @@ describe("withHiddenFromConfig", () => { }); }); +describe("withHiddenSubcommands", () => { + it("adds hidden subcommand annotations to the command help doc", () => { + const cmd = Command.make("demo").pipe(withHiddenSubcommands(["legacy"])); + const annotated = Context.get(buildHelpDoc(cmd).annotations, LegacyHiddenSubcommands); + + expect([...annotated]).toEqual(["legacy"]); + }); +}); + describe("stripHiddenFlagsFromHelpDoc", () => { it("returns the doc unchanged when annotations are empty", () => { const doc = helpDoc({ flags: [flagDoc("foo")] }); @@ -134,4 +154,26 @@ describe("stripHiddenFlagsFromHelpDoc", () => { expect(stripped.globalFlags).toBeUndefined(); expect(stripped.flags.map((f) => f.name)).toEqual(["bar"]); }); + + it("filters hidden subcommands by the doc's annotation", () => { + const doc = helpDocWithHiddenSubcommands(["legacy"], { + subcommands: [ + { + group: undefined, + commands: [ + { + name: "visible", + alias: undefined, + shortDescription: "visible", + description: "visible", + }, + { name: "legacy", alias: undefined, shortDescription: "legacy", description: "legacy" }, + ], + }, + ], + }); + + const stripped = stripHiddenFlagsFromHelpDoc(doc); + expect(stripped.subcommands?.[0]?.commands.map((command) => command.name)).toEqual(["visible"]); + }); });