From 1d3647542351853139e6c149fc1c6ad97c3cee30 Mon Sep 17 00:00:00 2001 From: kiwigitops Date: Mon, 22 Jun 2026 01:37:18 -0400 Subject: [PATCH 1/2] fix: exit nonzero for invalid status filters --- .../commands/status/__tests__/command.test.ts | 67 +++++++++++++++++++ src/cli/commands/status/command.tsx | 2 + 2 files changed, 69 insertions(+) create mode 100644 src/cli/commands/status/__tests__/command.test.ts diff --git a/src/cli/commands/status/__tests__/command.test.ts b/src/cli/commands/status/__tests__/command.test.ts new file mode 100644 index 000000000..69616352b --- /dev/null +++ b/src/cli/commands/status/__tests__/command.test.ts @@ -0,0 +1,67 @@ +import { registerStatus } from '../command.js'; +import { Command } from '@commander-js/extra-typings'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +const { mockRender } = vi.hoisted(() => ({ + mockRender: vi.fn(), +})); + +vi.mock('../../../tui/guards', () => ({ + requireProject: vi.fn(), +})); + +vi.mock('../../../telemetry/cli-command-run.js', () => ({ + withCommandRunTelemetry: vi.fn((_command, _attrs, run) => run()), +})); + +vi.mock('../../../operations/dataset', () => ({ + getDatasetStatus: vi.fn(), +})); + +vi.mock('../action.js', () => ({ + handleProjectStatus: vi.fn(), + handleRuntimeLookup: vi.fn(), + loadStatusConfig: vi.fn(), +})); + +vi.mock('../../../feature-flags', () => ({ + isPreviewEnabled: () => false, +})); + +vi.mock('ink', () => ({ + Box: ({ children }: { children?: unknown }) => children, + Text: ({ children }: { children?: unknown }) => children, + render: mockRender, +})); + +describe('status command validation', () => { + let program: Command; + let originalExitCode: typeof process.exitCode; + + beforeEach(() => { + originalExitCode = process.exitCode; + process.exitCode = undefined; + program = new Command(); + program.exitOverride(); + registerStatus(program); + }); + + afterEach(() => { + process.exitCode = originalExitCode; + vi.clearAllMocks(); + }); + + it('sets a non-zero exit code for invalid resource type', async () => { + await program.parseAsync(['status', '--type', 'bogus'], { from: 'user' }); + + expect(process.exitCode).toBe(1); + expect(mockRender).toHaveBeenCalled(); + }); + + it('sets a non-zero exit code for invalid state', async () => { + await program.parseAsync(['status', '--state', 'bogus'], { from: 'user' }); + + expect(process.exitCode).toBe(1); + expect(mockRender).toHaveBeenCalled(); + }); +}); diff --git a/src/cli/commands/status/command.tsx b/src/cli/commands/status/command.tsx index 1d93e8162..97df088f0 100644 --- a/src/cli/commands/status/command.tsx +++ b/src/cli/commands/status/command.tsx @@ -97,6 +97,7 @@ export const registerStatus = (program: Command) => { error: new ValidationError(msg), })); render({msg}); + process.exitCode = 1; return; } @@ -108,6 +109,7 @@ export const registerStatus = (program: Command) => { error: new ValidationError(msg), })); render({msg}); + process.exitCode = 1; return; } From 17fb7ad6a868fa227c0d5e0f51c7e92db25d8714 Mon Sep 17 00:00:00 2001 From: kiwigitops Date: Mon, 29 Jun 2026 22:18:30 -0400 Subject: [PATCH 2/2] test: expect status validation failures --- integ-tests/status.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integ-tests/status.test.ts b/integ-tests/status.test.ts index 55890847f..5381ce5cd 100644 --- a/integ-tests/status.test.ts +++ b/integ-tests/status.test.ts @@ -69,7 +69,7 @@ describe('status command', () => { it('emits failure telemetry for invalid --type', async () => { const result = await runCLI(['status', '--type', 'bogus'], projectDir, { env: telemetry.env }); - expect(result.exitCode).toBe(0); + expect(result.exitCode).toBe(1); telemetry.assertMetricEmitted({ command: 'status', exit_reason: 'failure', @@ -80,7 +80,7 @@ describe('status command', () => { it('emits failure telemetry for invalid --state', async () => { const result = await runCLI(['status', '--state', 'bogus'], projectDir, { env: telemetry.env }); - expect(result.exitCode).toBe(0); + expect(result.exitCode).toBe(1); telemetry.assertMetricEmitted({ command: 'status', exit_reason: 'failure',