From 8e0b1de5ebc50bd88912ddd22a1a0e17cb748613 Mon Sep 17 00:00:00 2001 From: "sentry[bot]" <39604003+sentry[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 22:42:54 +0000 Subject: [PATCH] fix(cli): Support list alias for sentry cli defaults --- packages/cli/src/commands/cli/defaults.ts | 22 +++++++- .../cli/test/commands/cli/defaults.test.ts | 55 ++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/cli/defaults.ts b/packages/cli/src/commands/cli/defaults.ts index 990323d20..acffce630 100644 --- a/packages/cli/src/commands/cli/defaults.ts +++ b/packages/cli/src/commands/cli/defaults.ts @@ -194,6 +194,14 @@ const KEY_ALIASES: Partial> = { "ca-certs": "ca-cert", }; +/** + * Words that mean "show all defaults" when passed as the only positional. + * + * Other commands use `list` subcommands, so users and agents often try + * `sentry cli defaults list`. Treat these like running with no arguments. + */ +const SHOW_ALL_VERBS = new Set(["list", "ls", "show"]); + /** Resolve a user-provided key string to a canonical key, or null if unknown */ function normalizeKey(key: string): DefaultKey | null { const lower = key.toLowerCase(); @@ -243,6 +251,7 @@ export const defaultsCommand = buildCommand({ "## Examples\n\n" + "```\n" + "sentry cli defaults # Show all defaults\n" + + "sentry cli defaults list # Same as above (alias: ls, show)\n" + "sentry cli defaults org my-org # Set default organization\n" + "sentry cli defaults project my-proj # Set default project\n" + "sentry cli defaults telemetry off # Disable telemetry\n" + @@ -303,7 +312,7 @@ export const defaultsCommand = buildCommand({ }, ...args: string[] ) { - const [keyArg, valueArg, ...rest] = args; + const [rawKeyArg, valueArg, ...rest] = args; // Too many arguments if (rest.length > 0) { @@ -313,6 +322,17 @@ export const defaultsCommand = buildCommand({ ); } + // `list` / `ls` / `show` are aliases for showing all defaults + const isShowVerb = + rawKeyArg !== undefined && SHOW_ALL_VERBS.has(rawKeyArg.toLowerCase()); + if (isShowVerb && (valueArg !== undefined || flags.clear)) { + throw new ValidationError( + `'${rawKeyArg}' shows all defaults and takes no value or --clear. Use 'sentry cli defaults' to show all, or 'sentry cli defaults --clear' to clear all.`, + "args", + ); + } + const keyArg = isShowVerb ? undefined : rawKeyArg; + // No key specified — show all or clear all if (!keyArg) { if (flags.clear) { diff --git a/packages/cli/test/commands/cli/defaults.test.ts b/packages/cli/test/commands/cli/defaults.test.ts index 7595a7903..a7ce59976 100644 --- a/packages/cli/test/commands/cli/defaults.test.ts +++ b/packages/cli/test/commands/cli/defaults.test.ts @@ -6,7 +6,8 @@ */ import chalk from "chalk"; -import { describe, expect, test } from "vitest"; +import { describe, expect, test, vi } from "vitest"; +import { defaultsCommand } from "../../../src/commands/cli/defaults.js"; import { clearAllDefaults, getAllDefaults, @@ -530,3 +531,55 @@ describe("formatDefaultsResult", () => { expect(plain).toContain("set to"); }); }); + +// --------------------------------------------------------------------------- +// Command func: show-all verb aliases +// --------------------------------------------------------------------------- + +describe("defaultsCommand.func show-all aliases", () => { + const FLAGS = { clear: false, yes: false, force: false, json: true }; + + async function run( + flags: Record, + ...args: string[] + ): Promise { + const stdoutWrite = vi.fn(() => true); + const context = { + stdout: { write: stdoutWrite }, + stderr: { write: vi.fn(() => true) }, + cwd: "/tmp", + }; + const func = await defaultsCommand.loader(); + await (func as any).call(context, flags, ...args); + return stdoutWrite.mock.calls.map((c) => String(c[0])).join(""); + } + + test.each(["list", "ls", "show", "LIST"])( + "'%s' shows all defaults like no arguments", + async (verb) => { + setDefaultOrganization("alias-org"); + const expected = JSON.parse(await run(FLAGS)); + const actual = JSON.parse(await run(FLAGS, verb)); + expect(actual).toEqual(expected); + expect(actual.defaults.organization).toBe("alias-org"); + }, + ); + + test("show verb with a value is rejected", async () => { + await expect(run(FLAGS, "list", "foo")).rejects.toThrow( + /shows all defaults/, + ); + }); + + test("show verb with --clear is rejected and clears nothing", async () => { + setDefaultOrganization("keep-org"); + await expect(run({ ...FLAGS, clear: true }, "list")).rejects.toThrow( + /shows all defaults/, + ); + expect(getDefaultOrganization()).toBe("keep-org"); + }); + + test("unknown key still throws", async () => { + await expect(run(FLAGS, "nope")).rejects.toThrow(/Unknown default 'nope'/); + }); +});