Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
d4e37d5
feat(cli): prompt for worker name if not provided
johnstonmatt Aug 29, 2026
edc7199
fix(cli): gate the workers new prompts on stdin too
johnstonmatt Aug 29, 2026
93c7aa6
feat(cli): prompt for worker name if not provided
johnstonmatt Aug 29, 2026
5c84df0
fix(cli): gate the workers new prompts on stdin too
johnstonmatt Aug 29, 2026
0af0f0a
chore(workers): describe behaviour rather than its history in comments
johnstonmatt Aug 31, 2026
a74e3f9
feat(workers): bring the command family's output onto one shape
johnstonmatt Aug 29, 2026
548a185
test(cli): guard every legacy boolean flag against a required default
johnstonmatt Aug 29, 2026
1d7e06b
chore(workers): describe behaviour rather than its history in comments
johnstonmatt Aug 31, 2026
1a2236d
feat(workers logs): add `supabase workers logs`
johnstonmatt Aug 31, 2026
c4080de
feat(workers logs): print timestamps in local time
johnstonmatt Aug 31, 2026
b7c9864
feat(workers logs): add `--follow` to keep printing new lines
johnstonmatt Aug 31, 2026
2f68ad6
feat: show stream tags in worker logs when multiple sources
johnstonmatt Aug 31, 2026
c66065d
chore(workers): describe behaviour rather than its history in comments
johnstonmatt Aug 31, 2026
acbd6ff
feat(workers push): make build wait opt-in with `--wait` flag
johnstonmatt Aug 29, 2026
88e4832
Merge branch 'FUNC-840/select-workers-new-name' of https://github.com…
johnstonmatt Sep 1, 2026
9ae1f38
fix(cli): point the workers new retry at the experimental path
johnstonmatt Sep 1, 2026
12c4d1c
fix(cli): stop telling users to run a command that does not exist
johnstonmatt Sep 1, 2026
94d1e89
Merge FUNC-840/select-workers-new-name into FUNC-851/general-output-p…
johnstonmatt Sep 1, 2026
4f05bc5
Merge FUNC-851/general-output-polish into FUNC-853/workers-logs-command
johnstonmatt Sep 1, 2026
0bfaca8
Merge FUNC-853/workers-logs-command into FUNC-848/workers-deploy-wait…
johnstonmatt Sep 1, 2026
e024627
test(cli): name the real push invocation in the flag-default guard
johnstonmatt Sep 1, 2026
1f103f9
fix(workers): restore the experimental segment in worker span names
johnstonmatt Sep 1, 2026
de59392
fix(workers): stop echoing an empty --project-ref into retry suggestions
johnstonmatt Sep 1, 2026
d99e6b5
fix(workers): keep push's per-worker progress out of structured formats
johnstonmatt Sep 1, 2026
71af01d
docs(workers): mark the status and delete trailers as text-only
johnstonmatt Sep 1, 2026
11395a3
refactor(workers): rename workers logs --source to --kind
johnstonmatt Sep 1, 2026
6f8770d
docs(workers): mark the logs no-logs hint as text-only
johnstonmatt Sep 1, 2026
46321b4
fix(workers logs): tie the --kind choices to the stream map
johnstonmatt Sep 1, 2026
396498b
fix(workers logs): give -o priority over --output-format
johnstonmatt Sep 1, 2026
d949afd
fix(workers logs): flush telemetry when the project ref cannot resolve
johnstonmatt Sep 1, 2026
335b62a
fix(workers logs): let a Ctrl+C'd tail run its finalizers
johnstonmatt Sep 1, 2026
2597a39
fix(workers logs): stop --tail capping the follow poll
johnstonmatt Sep 1, 2026
f8575ee
fix(workers logs): make --tail 0 --follow mean what it says
johnstonmatt Sep 1, 2026
a00a02c
fix(workers logs): sanitise every rendered field, not just the guest …
johnstonmatt Sep 1, 2026
d06c876
refactor(workers logs): prefix the exported log-level type
johnstonmatt Sep 1, 2026
7009bd6
docs(workers logs): document the SIGINT exit code
johnstonmatt Sep 1, 2026
af1f813
fix(workers logs): bound ts_ms to a representable instant
johnstonmatt Sep 1, 2026
fa318ee
fix(workers logs): retry only the poll failures worth another request
johnstonmatt Sep 1, 2026
468d9e2
fix(workers logs): carry the composed line into stream-json
johnstonmatt Sep 1, 2026
008f160
Merge branch 'develop' of https://github.com/supabase/cli into FUNC-8…
johnstonmatt Sep 1, 2026
b3ea7df
Merge branch 'FUNC-840/select-workers-new-name' of https://github.com…
johnstonmatt Sep 1, 2026
c8977d0
fix(workers logs): green the checks the logs command turned red
johnstonmatt Sep 1, 2026
e0cd17c
Merge branch 'FUNC-853/workers-logs-command' into FUNC-848/workers-de…
johnstonmatt Sep 1, 2026
993fa7e
Merge remote-tracking branch 'origin/FUNC-851/general-output-polish' …
johnstonmatt Sep 1, 2026
be45513
Merge branch 'FUNC-853/workers-logs-command' into FUNC-848/workers-de…
johnstonmatt Sep 1, 2026
b772491
test(config): stop a broken pipe preempting the exit-code diagnosis
johnstonmatt Sep 1, 2026
6a0bab9
Merge branch 'FUNC-853/workers-logs-command' into FUNC-848/workers-de…
johnstonmatt Sep 1, 2026
6c8acc0
refactor(workers): give the family one command scaffold
johnstonmatt Sep 2, 2026
f534abd
refactor(workers): emit every payload through one helper
johnstonmatt Sep 2, 2026
d57f81a
refactor(workers): build the family's command strings in one place
johnstonmatt Sep 2, 2026
cdb42bf
refactor(workers): build the not-deployed error once
johnstonmatt Sep 2, 2026
c89e62b
refactor(workers): name the "renders human text" condition
johnstonmatt Sep 2, 2026
0173b12
refactor(workers logs): make the follow loop one step at a time
johnstonmatt Sep 2, 2026
e4e0a3e
refactor(workers push): lift the source check out of deployOneWorker
johnstonmatt Sep 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { describe, expect, it } from "vitest";
import { Primitive, type Command } from "effect/unstable/cli";
import {
legacyCommandInternals,
legacyFlattenSubcommands,
legacyUserGlobalFlagParams,
} from "../docs/legacy-docs-introspection.ts";
import { legacyUnwrapParam } from "../shared/legacy-param-introspection.ts";
import { legacyRoot } from "./root.ts";

/**
* `Flag.boolean(name)` builds a bare `Single` param, and a bare `Single` is
* *required* — omitting it fails the whole command with a missing-flag error
* before the handler ever runs. Every boolean flag therefore has to be closed
* off with `Flag.withDefault(false)` or `Flag.optional`.
*
* Nothing else catches this: handler integration tests build their flags record
* directly, so they never touch the parser, and the required-ness is invisible
* to the type checker because a required boolean flag still infers as
* `boolean`. The flag only misbehaves when a real invocation omits it, which is
* precisely the invocation no handler test makes — so the guard walks the
* command tree instead of waiting for a command to be exercised end to end.
*
* `experimental workers push --wait` is the flag that prompted it: it first
* shipped with neither closer, which made a plain
* `supabase experimental workers push` fail to parse at all.
*/

/**
* The published getter for a primitive's kind — `Primitive.getTypeName`, whose
* own doc example pins `Primitive.boolean` to `"boolean"`. Reading
* `primitiveType._tag` instead would couple this guard to effect's runtime
* representation, which this repo forbids in tests as well as in source.
*
* Derived from `Primitive.boolean` rather than written as the literal
* `"boolean"`: were that name to change upstream, a hardcoded literal would
* match nothing and leave the guard silently passing every command, which is
* the one failure mode a regression test must not have.
*/
const BOOLEAN_TYPE_NAME = Primitive.getTypeName(Primitive.boolean);

function booleanFlagsRequiringAValue(command: Command.Command.Any): ReadonlyArray<string> {
const internals = legacyCommandInternals(command);
// All three parameter sets a command can be parsed with, not just its own:
// `Command.withSharedFlags` puts inherited flags on `contextConfig`, and the
// root's persistent flags arrive as `globalFlags`. A bare boolean introduced
// through either would break every command that inherits it while a guard
// reading only `config.flags` stayed green.
const params = [
...internals.config.flags,
...internals.contextConfig.flags,
...legacyUserGlobalFlagParams(command),
];

// Throws rather than skipping if effect's internal shape moves, so this
// cannot quietly degrade into a test that inspects nothing.
const own = params.flatMap((flag) => {
const unwrapped = legacyUnwrapParam(flag);
if (unwrapped === undefined) {
throw new Error(`Unrecognizable flag param on "${command.name}".`);
}
const { single, isOptional } = unwrapped;
return Primitive.getTypeName(single.primitiveType) === BOOLEAN_TYPE_NAME && !isOptional
? [`${command.name} --${single.name}`]
: [];
});

return [...own, ...legacyFlattenSubcommands(command).flatMap(booleanFlagsRequiringAValue)];
}

describe("legacy boolean flag wiring", () => {
it("gives every boolean flag a default, so omitting it is not a parse error", () => {
expect(booleanFlagsRequiringAValue(legacyRoot)).toEqual([]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,17 @@ wrapper emits for every command.

## Output Formats

| Mode | stdout | stderr |
| ----------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------- |
| text (default) | the confirmation prompt, then what was deleted and kept | that nothing local was kept, when nothing was |
| `--output-format json` | one structured result carrying `worker_name`, `project_ref`, `kept_*` | as above |
| `--output-format stream-json` | the same result as a single terminal event | as above |
| `-o json` / `yaml` / `toml` | the same payload in that encoding, and nothing else | as above |
| `-o pretty` / `table` / `csv` | the text rendering — these fall through rather than encoding | as above |
| `-o env` | refused **before** the DELETE; discovering it at emit time deleted the worker and then failed | the error |
| Mode | stdout | stderr |
| ----------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| text (default) | the confirmation prompt, then what was deleted and kept | that nothing local was kept when nothing was, and the redeploy hint |
| `--output-format json` | one structured result carrying `worker_name`, `project_ref`, `kept_*` | neither — both are text-only |
| `--output-format stream-json` | the same result as a single terminal event | neither — both are text-only |
| `-o json` / `yaml` / `toml` | the same payload in that encoding, and nothing else | neither — both are text-only |
| `-o pretty` / `table` / `csv` | the text rendering — these fall through rather than encoding | both, as in text |
| `-o env` | refused **before** the DELETE; discovering it at emit time deleted the worker and then failed | the error |

A structured emission is the end of the run: the handler returns at
`legacyEmitWorkersMachineOutput` or at `output.success`, so nothing in the text
branch below it — the kept-nothing notice and the redeploy trailer — is reached.
`-o pretty`, `table` and `csv` are the exception, since they encode nothing and
fall through to that same text branch.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Argument, Command, Flag } from "effect/unstable/cli";
import type * as CliCommand from "effect/unstable/cli/Command";
import { legacyWorkersCommand } from "../workers.commands.ts";
import { withJsonErrorHandling } from "../../../../../shared/output/json-error-handling.ts";
import { legacyManagementApiRuntimeLayer } from "../../../../shared/legacy-management-api-runtime.layer.ts";
import { withLegacyCommandInstrumentation } from "../../../../telemetry/legacy-command-instrumentation.ts";
Expand All @@ -25,11 +26,11 @@ export const legacyWorkersDeleteCommand = Command.make("delete", config).pipe(
Command.withShortDescription("Delete a worker from Supabase"),
Command.withExamples([
{
command: "supabase experimental workers delete api",
command: legacyWorkersCommand("delete api"),
description: "Delete a worker, confirming by typing its name",
},
{
command: "supabase experimental workers delete api --yes",
command: legacyWorkersCommand("delete api --yes"),
description: "Skip the confirmation prompt (scripts and CI)",
},
]),
Expand Down
Loading