diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 8a8296b574..f8d1db7019 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -131,7 +131,7 @@ Options: ### `backstage-cli create-github-app` ``` -Usage: backstage-cli create-github-app +Usage: backstage-cli create-github-app Options: -h, --help @@ -310,6 +310,8 @@ Options: --check --config --entrypoint + --inspect + --inspect-brk --link --require --role @@ -513,6 +515,8 @@ Usage: backstage-cli repo start Options: --config + --inspect + --inspect-brk --link --plugin --require @@ -522,114 +526,14 @@ Options: ### `backstage-cli repo test` ``` -Usage: +Usage: backstage-cli repo test Options: - --all - --automock - --cache - --cacheDirectory - --changedFilesWithAncestor - --changedSince - --ci - --clearCache - --clearMocks - --collectCoverage - --collectCoverageFrom - --color - --colors - --coverage - --coverageDirectory - --coveragePathIgnorePatterns - --coverageProvider - --coverageReporters - --coverageThreshold - --debug - --detectLeaks - --detectOpenHandles - --errorOnDeprecated - --filter - --findRelatedTests - --forceExit - --globalSetup - --globalTeardown - --globals - --haste - --help - --ignoreProjects - --injectGlobals - --json - --lastCommit - --listTests - --logHeapUsage - --maxConcurrency - --moduleDirectories - --moduleFileExtensions - --moduleNameMapper - --modulePathIgnorePatterns - --modulePaths - --noStackTrace - --notify - --notifyMode - --openHandlesTimeout - --outputFile - --passWithNoTests - --preset - --prettierPath - --projects - --randomize - --reporters - --resetMocks - --resetModules - --resolver - --restoreMocks - --rootDir - --roots - --runTestsByPath - --runner - --seed - --selectProjects - --setupFiles - --setupFilesAfterEnv - --shard - --showConfig - --showSeed - --silent - --skipFilter - --snapshotSerializers - --testEnvironment, --env - --testEnvironmentOptions - --testFailureExitCode - --testLocationInResults - --testMatch - --testPathIgnorePatterns - --testPathPatterns - --testRegex - --testResultsProcessor - --testRunner - --testSequencer - --testTimeout - --transform - --transformIgnorePatterns - --unmockedModulePathPatterns - --useStderr - --verbose - --version - --waitForUnhandledRejections - --watch - --watchAll - --watchPathIgnorePatterns - --watchman - --workerThreads - -b, --bail - -c, --config - -e, --expand - -f, --onlyFailures - -i, --runInBand - -o, --onlyChanged - -t, --testNamePattern - -u, --updateSnapshot - -w, --maxWorkers + --jest-help + --since + --success-cache + --success-cache-dir + -h, --help ``` ### `backstage-cli translations` diff --git a/packages/cli/src/modules/build/commands/package/start/command.ts b/packages/cli/src/modules/build/commands/package/start/command.ts index f0454f2d3d..0d169af5ef 100644 --- a/packages/cli/src/modules/build/commands/package/start/command.ts +++ b/packages/cli/src/modules/build/commands/package/start/command.ts @@ -22,11 +22,17 @@ import { targetPaths } from '@backstage/cli-common'; import type { CommandContext } from '../../../../../wiring/types'; export default async ({ args, info }: CommandContext) => { - const { inspectEnabled, inspectBrkEnabled, filteredArgs } = - extractInspectFlags(args); - const { - flags: { config, role, check, require: requirePath, link, entrypoint }, + flags: { + config, + role, + check, + require: requirePath, + link, + entrypoint, + inspect, + inspectBrk, + }, } = cli( { help: info, @@ -57,10 +63,20 @@ export default async ({ args, info }: CommandContext) => { description: 'The entrypoint to start from, relative to the package root. Can point to either a file (without extension) or a directory (in which case the index file in that directory is used). Defaults to "dev"', }, + inspect: { + type: String, + description: + 'Enable the Node.js inspector, optionally at a specific host:port', + }, + inspectBrk: { + type: String, + description: + 'Enable the Node.js inspector and break before user code starts', + }, }, }, undefined, - filteredArgs, + args, ); await startPackage({ @@ -70,38 +86,8 @@ export default async ({ args, info }: CommandContext) => { configPaths: config, checksEnabled: Boolean(check), linkedWorkspace: await resolveLinkedWorkspace(link), - inspectEnabled, - inspectBrkEnabled, + inspectEnabled: inspect, + inspectBrkEnabled: inspectBrk, require: requirePath, }); }; - -// --inspect and --inspect-brk accept an optional host value, which cleye -// can't express (it only supports required or no value). We extract them -// from the raw args before passing the rest to cleye. -function extractInspectFlags(args: string[]) { - let inspectEnabled: boolean | string | undefined; - let inspectBrkEnabled: boolean | string | undefined; - const filteredArgs: string[] = []; - - for (let i = 0; i < args.length; i++) { - const arg = args[i]; - if (arg === '--inspect' || arg === '--inspect-brk') { - const next = args[i + 1]; - const value = next && !next.startsWith('-') ? args[++i] : true; - if (arg === '--inspect') { - inspectEnabled = value; - } else { - inspectBrkEnabled = value; - } - } else if (arg.startsWith('--inspect=')) { - inspectEnabled = arg.slice('--inspect='.length); - } else if (arg.startsWith('--inspect-brk=')) { - inspectBrkEnabled = arg.slice('--inspect-brk='.length); - } else { - filteredArgs.push(arg); - } - } - - return { inspectEnabled, inspectBrkEnabled, filteredArgs }; -} diff --git a/packages/cli/src/modules/build/commands/package/start/startBackend.ts b/packages/cli/src/modules/build/commands/package/start/startBackend.ts index a36a93b8ff..b9eb8709f3 100644 --- a/packages/cli/src/modules/build/commands/package/start/startBackend.ts +++ b/packages/cli/src/modules/build/commands/package/start/startBackend.ts @@ -23,8 +23,8 @@ import { runBackend } from '../../../lib/runner'; interface StartBackendOptions { targetDir: string; checksEnabled: boolean; - inspectEnabled?: boolean | string; - inspectBrkEnabled?: boolean | string; + inspectEnabled?: string; + inspectBrkEnabled?: string; linkedWorkspace?: string; require?: string; } diff --git a/packages/cli/src/modules/build/commands/package/start/startPackage.ts b/packages/cli/src/modules/build/commands/package/start/startPackage.ts index e0ab13facc..084a4670b4 100644 --- a/packages/cli/src/modules/build/commands/package/start/startPackage.ts +++ b/packages/cli/src/modules/build/commands/package/start/startPackage.ts @@ -38,8 +38,8 @@ export async function startPackage(options: { targetDir: string; configPaths: string[]; checksEnabled: boolean; - inspectEnabled?: boolean | string; - inspectBrkEnabled?: boolean | string; + inspectEnabled?: string; + inspectBrkEnabled?: string; linkedWorkspace?: string; require?: string; }): Promise { diff --git a/packages/cli/src/modules/build/commands/repo/start.ts b/packages/cli/src/modules/build/commands/repo/start.ts index dd10197c4c..f2f6b7c412 100644 --- a/packages/cli/src/modules/build/commands/repo/start.ts +++ b/packages/cli/src/modules/build/commands/repo/start.ts @@ -36,11 +36,8 @@ const ACCEPTED_PACKAGE_ROLES: Array = [ ]; export default async ({ args, info }: CommandContext) => { - const { inspectEnabled, inspectBrkEnabled, filteredArgs } = - extractInspectFlags(args); - const { - flags: { plugin, config, require: requirePath, link }, + flags: { plugin, config, require: requirePath, link, inspect, inspectBrk }, _: namesOrPaths, } = cli( { @@ -66,10 +63,20 @@ export default async ({ args, info }: CommandContext) => { type: String, description: 'Link an external workspace for module resolution', }, + inspect: { + type: String, + description: + 'Enable the Node.js inspector, optionally at a specific host:port', + }, + inspectBrk: { + type: String, + description: + 'Enable the Node.js inspector and break before user code starts', + }, }, }, undefined, - filteredArgs, + args, ); const targetPackages = await findTargetPackages(namesOrPaths, plugin); @@ -77,8 +84,8 @@ export default async ({ args, info }: CommandContext) => { const packageOptions = await resolvePackageOptions(targetPackages, { plugin, config, - inspect: inspectEnabled, - inspectBrk: inspectBrkEnabled, + inspect, + inspectBrk, require: requirePath, link, }); @@ -204,8 +211,8 @@ export async function findTargetPackages( type CommandOptions = { plugin: string[]; config: string[]; - inspect?: boolean | string; - inspectBrk?: boolean | string; + inspect?: string; + inspectBrk?: string; require?: string; link?: string; }; @@ -263,33 +270,3 @@ async function resolvePackageOptions( ]; }); } - -// --inspect and --inspect-brk accept an optional host value, which cleye -// can't express (it only supports required or no value). We extract them -// from the raw args before passing the rest to cleye. -function extractInspectFlags(args: string[]) { - let inspectEnabled: boolean | string | undefined; - let inspectBrkEnabled: boolean | string | undefined; - const filteredArgs: string[] = []; - - for (let i = 0; i < args.length; i++) { - const arg = args[i]; - if (arg === '--inspect' || arg === '--inspect-brk') { - const next = args[i + 1]; - const value = next && !next.startsWith('-') ? args[++i] : true; - if (arg === '--inspect') { - inspectEnabled = value; - } else { - inspectBrkEnabled = value; - } - } else if (arg.startsWith('--inspect=')) { - inspectEnabled = arg.slice('--inspect='.length); - } else if (arg.startsWith('--inspect-brk=')) { - inspectBrkEnabled = arg.slice('--inspect-brk='.length); - } else { - filteredArgs.push(arg); - } - } - - return { inspectEnabled, inspectBrkEnabled, filteredArgs }; -} diff --git a/packages/cli/src/modules/build/lib/runner/runBackend.test.ts b/packages/cli/src/modules/build/lib/runner/runBackend.test.ts index 2b97ae352c..5fc3f448c9 100644 --- a/packages/cli/src/modules/build/lib/runner/runBackend.test.ts +++ b/packages/cli/src/modules/build/lib/runner/runBackend.test.ts @@ -163,7 +163,7 @@ describe('runBackend', () => { runBackend({ entry: 'src/index', - inspectEnabled: true, + inspectEnabled: '', }); // Fast-forward past the debounce delay (100ms) diff --git a/packages/cli/src/modules/build/lib/runner/runBackend.ts b/packages/cli/src/modules/build/lib/runner/runBackend.ts index 22fd50b3f4..adaa9ca58f 100644 --- a/packages/cli/src/modules/build/lib/runner/runBackend.ts +++ b/packages/cli/src/modules/build/lib/runner/runBackend.ts @@ -38,9 +38,9 @@ export type RunBackendOptions = { /** relative entry point path without extension, e.g. 'src/index' */ entry: string; /** Whether to forward the --inspect flag to the node process */ - inspectEnabled?: boolean | string; + inspectEnabled?: string; /** Whether to forward the --inspect-brk flag to the node process */ - inspectBrkEnabled?: boolean | string; + inspectBrkEnabled?: string; /** Additional module to require via the --require flag to the node process */ require?: string | string[]; /** An external linked workspace to override module resolution towards */ @@ -96,18 +96,18 @@ export async function runBackend(options: RunBackendOptions) { } const optionArgs = new Array(); - if (options.inspectEnabled) { - const inspect = - typeof options.inspectEnabled === 'string' + if (options.inspectEnabled !== undefined) { + optionArgs.push( + options.inspectEnabled ? `--inspect=${options.inspectEnabled}` - : '--inspect'; - optionArgs.push(inspect); - } else if (options.inspectBrkEnabled) { - const inspect = - typeof options.inspectBrkEnabled === 'string' + : '--inspect', + ); + } else if (options.inspectBrkEnabled !== undefined) { + optionArgs.push( + options.inspectBrkEnabled ? `--inspect-brk=${options.inspectBrkEnabled}` - : '--inspect-brk'; - optionArgs.push(inspect); + : '--inspect-brk', + ); } if (options.require) { const requires = [options.require].flat(); diff --git a/packages/cli/src/modules/create-github-app/commands/create-github-app/index.ts b/packages/cli/src/modules/create-github-app/commands/create-github-app/index.ts index 998f8eb7ae..1cd51e541b 100644 --- a/packages/cli/src/modules/create-github-app/commands/create-github-app/index.ts +++ b/packages/cli/src/modules/create-github-app/commands/create-github-app/index.ts @@ -31,7 +31,7 @@ import type { CommandContext } from '../../../../wiring/types'; export default async ({ args, info }: CommandContext) => { const { _: positionals } = cli( { - help: info, + help: { ...info, usage: `${info.usage} ` }, parameters: [''], }, undefined, diff --git a/packages/cli/src/modules/test/commands/repo/test.ts b/packages/cli/src/modules/test/commands/repo/test.ts index ececc5940c..743aa87c3d 100644 --- a/packages/cli/src/modules/test/commands/repo/test.ts +++ b/packages/cli/src/modules/test/commands/repo/test.ts @@ -16,7 +16,7 @@ import os from 'node:os'; import crypto from 'node:crypto'; -import { parseArgs } from 'node:util'; +import { cli } from 'cleye'; import yargs from 'yargs'; // 'jest-cli' is included with jest and should be kept in sync with the installed jest version // eslint-disable-next-line @backstage/no-undeclared-imports @@ -131,41 +131,41 @@ export function createFlagFinder(args: string[]) { }; } -function removeOptionArg(args: string[], option: string, size: number = 2) { - let changed = false; - do { - changed = false; - - const index = args.indexOf(option); - if (index >= 0) { - changed = true; - args.splice(index, size); - } - const indexEq = args.findIndex(arg => arg.startsWith(`${option}=`)); - if (indexEq >= 0) { - changed = true; - args.splice(indexEq, 1); - } - } while (changed); -} - -export default async ({ args }: CommandContext) => { +export default async ({ args, info }: CommandContext) => { const testGlobal = global as TestGlobal; - // Parse our own flags from the raw args using strict: false to allow Jest flags through - const { values: opts } = parseArgs({ - args, - strict: false, - options: { - since: { type: 'string' }, - successCache: { type: 'boolean' }, - successCacheDir: { type: 'string' }, - 'jest-help': { type: 'boolean' }, + // Parse Backstage-specific flags; unknown flags and arguments are left in + // args so they can be forwarded to Jest. + const { flags: opts } = cli( + { + help: info, + flags: { + since: { + type: String, + description: + 'Only include test packages changed since the specified ref', + }, + successCache: { + type: Boolean, + description: 'Cache and skip tests for unchanged packages', + }, + successCacheDir: { + type: String, + description: 'Directory for the success cache', + }, + jestHelp: { + type: Boolean, + description: "Show Jest's own help output", + }, + }, + ignoreArgv: type => type === 'unknown-flag' || type === 'argument', }, - }); + undefined, + args, + ); const hasFlags = createFlagFinder(args); - const sinceRef = typeof opts.since === 'string' ? opts.since : undefined; + const sinceRef = opts.since || undefined; // Parse the args to ensure that no file filters are provided, in which case we refuse to run const { _: parsedArgs } = await yargs(args).options(jestYargsOptions).argv; @@ -252,10 +252,6 @@ export default async ({ args }: CommandContext) => { args.push('--maxWorkers=2'); } - if (opts.since) { - removeOptionArg(args, '--since'); - } - let packageGraph: PackageGraph | undefined; async function getPackageGraph() { if (packageGraph) { @@ -310,17 +306,13 @@ export default async ({ args }: CommandContext) => { }--no-node-snapshot`; } - if (opts['jest-help']) { - removeOptionArg(args, '--jest-help'); + if (opts.jestHelp) { args.push('--help'); } // This code path is enabled by the --successCache flag, which is specific to // the `repo test` command in the Backstage CLI. if (opts.successCache) { - removeOptionArg(args, '--successCache', 1); - removeOptionArg(args, '--successCacheDir'); - // Refuse to run if file filters are provided if (parsedArgs.length > 0) { throw new Error( @@ -338,7 +330,7 @@ export default async ({ args }: CommandContext) => { const cache = SuccessCache.create({ name: 'test', - basePath: opts.successCacheDir as string | undefined, + basePath: opts.successCacheDir, }); const graph = await getPackageGraph();