Skip to content

Commit ccc5014

Browse files
committed
fix(showcase): verify-deploy arg-parse symmetry + non-bare releaseBody catch
1 parent 48bb0a5 commit ccc5014

3 files changed

Lines changed: 64 additions & 5 deletions

File tree

showcase/scripts/__tests__/verify-deploy.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,30 @@ describe("verify-deploy argv parsing", () => {
3030
parseArgs(["--env", "staging", "--services="]),
3131
).toThrow(/--services/);
3232
});
33+
34+
it("rejects --services space-form whose CSV is all empty entries (symmetry with equals-form)", () => {
35+
// Bug: space-form previously only guarded `!v` on the raw next-arg,
36+
// so `--services ,,` produced an empty list that fell through to a
37+
// less-precise zero-targets error. Both forms must throw the same
38+
// precise `--services requires a CSV value` here.
39+
expect(() =>
40+
parseArgs(["--env=staging", "--services", ",,"]),
41+
).toThrow(/--services requires a CSV value/);
42+
});
43+
44+
it("rejects bare trailing --env (no following value)", () => {
45+
// Bug: `argv[++i]` was undefined and we deferred to a vague
46+
// `resolveEnv` error. Must throw the precise message here.
47+
expect(() => parseArgs(["--env"])).toThrow(
48+
/--env requires a value \(staging\|prod\)/,
49+
);
50+
});
51+
52+
it("rejects --env= with empty value (symmetry with bare trailing --env)", () => {
53+
expect(() => parseArgs(["--env="])).toThrow(
54+
/--env requires a value \(staging\|prod\)/,
55+
);
56+
});
3357
});
3458

3559
describe("resolveProbeTargets", () => {

showcase/scripts/verify-deploy.drivers.baseline.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,22 @@ async function releaseBody(
9191
): Promise<void> {
9292
try {
9393
await res.body?.cancel?.();
94-
} catch {
95-
// Cancelling a body that was already consumed throws on some
96-
// runtimes; that's harmless — the socket is already released.
94+
} catch (e: unknown) {
95+
// Expected benign case: undici throws when the body is already
96+
// "locked" (a reader is attached, or it was fully read by an
97+
// earlier `res.json()` / `res.text()`). In every such case the
98+
// socket is already released, so this is a no-op — swallow it.
99+
// Anything else is unexpected; surface it on stderr so we don't
100+
// hide a real bug, but keep `releaseBody` best-effort (never
101+
// propagate — undici socket release is an optimization, not a
102+
// correctness invariant).
103+
const msg = e instanceof Error ? e.message : String(e);
104+
const locked = /lock/i.test(msg);
105+
if (!locked) {
106+
process.stderr.write(
107+
`[verify-deploy] releaseBody: unexpected cancel error: ${msg}\n`,
108+
);
109+
}
97110
}
98111
}
99112

showcase/scripts/verify-deploy.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,35 @@ export function parseArgs(argv: string[]): ParsedArgs {
4040
for (let i = 0; i < argv.length; i++) {
4141
const a = argv[i];
4242
if (a === "--env") {
43-
envRaw = argv[++i];
43+
const v = argv[++i];
44+
// Guard a bare trailing `--env` (undefined) here so the
45+
// operator gets a precise, flag-named diagnostic instead of
46+
// the downstream `resolveEnv` "Unknown env" / "--env required"
47+
// surface. Mirrors the same guard on `--services`.
48+
if (v === undefined) {
49+
throw new Error("--env requires a value (staging|prod)");
50+
}
51+
envRaw = v;
4452
} else if (a.startsWith("--env=")) {
45-
envRaw = a.slice("--env=".length);
53+
const v = a.slice("--env=".length);
54+
// `--env=` (empty post-equals) is the equals-form twin of the
55+
// bare-trailing case above; collapse both to the same precise
56+
// error rather than deferring to `resolveEnv`.
57+
if (v === "") {
58+
throw new Error("--env requires a value (staging|prod)");
59+
}
60+
envRaw = v;
4661
} else if (a === "--services") {
4762
const v = argv[++i];
4863
if (!v) throw new Error("--services requires a CSV value");
4964
services = v.split(",").map((s) => s.trim()).filter(Boolean);
65+
// Symmetry with the equals-form below: a raw value like `,,`
66+
// or `" "` survives the `!v` guard but produces an empty
67+
// post-filter list. Throw the same precise error here so both
68+
// forms behave identically.
69+
if (services.length === 0) {
70+
throw new Error("--services requires a CSV value");
71+
}
5072
} else if (a.startsWith("--services=")) {
5173
const v = a.slice("--services=".length);
5274
if (!v) throw new Error("--services requires a CSV value");

0 commit comments

Comments
 (0)