diff --git a/src/core/cliArgs.ts b/src/core/cliArgs.ts new file mode 100644 index 0000000..4d908a7 --- /dev/null +++ b/src/core/cliArgs.ts @@ -0,0 +1,9 @@ +/** first top-level subcommand, ignoring global flags (e.g. --debug). */ +export function getTopLevelCommand(argv: string[]): string | undefined { + const args = argv.slice(2); + return args.find((arg) => !arg.startsWith('-')); +} + +export function isUpdateCommand(argv: string[] = process.argv): boolean { + return getTopLevelCommand(argv) === 'update'; +} diff --git a/src/index.ts b/src/index.ts index 324b7e4..b6a3d9d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ import { } from './commands/release.js'; import { updateCommand } from './commands/update.js'; import { enableCommand } from './commands/enable.js'; +import { isUpdateCommand } from './core/cliArgs.js'; import { printCliError, resolveDebugFlag } from './core/cliError.js'; import { ui } from './core/ui.js'; @@ -245,6 +246,11 @@ function checkForUpdates(): void { return; } + // user is already updating; don't suggest running `ensemble update` again. + if (isUpdateCommand()) { + return; + } + // IMPORTANT: This command string must remain a static literal and MUST NOT // interpolate user-controlled input to avoid shell injection risks. const child = exec( diff --git a/tests/core/cliArgs.test.ts b/tests/core/cliArgs.test.ts new file mode 100644 index 0000000..ebf5278 --- /dev/null +++ b/tests/core/cliArgs.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest'; + +import { getTopLevelCommand, isUpdateCommand } from '../../src/core/cliArgs.js'; + +describe('cliArgs', () => { + describe('getTopLevelCommand', () => { + it.each([ + [['node', 'ensemble', 'update'], 'update'], + [['node', 'ensemble', '--debug', 'update'], 'update'], + [['node', 'ensemble', 'push'], 'push'], + [['node', 'ensemble', '--debug', 'push', '--app', 'uat'], 'push'], + [['node', 'ensemble'], undefined], + ])('parses %j', (argv, expected) => { + expect(getTopLevelCommand(argv)).toBe(expected); + }); + }); + + describe('isUpdateCommand', () => { + it.each([ + [['node', 'ensemble', 'update'], true], + [['node', 'ensemble', '--debug', 'update'], true], + [['node', 'ensemble', 'push'], false], + [['node', 'ensemble', 'release', 'create'], false], + ])('detects update command in %j', (argv, expected) => { + expect(isUpdateCommand(argv)).toBe(expected); + }); + }); +});