diff --git a/lib/renovate.spec.ts b/lib/renovate.spec.ts index 8df4490309a..21829a2f75d 100644 --- a/lib/renovate.spec.ts +++ b/lib/renovate.spec.ts @@ -4,6 +4,7 @@ import * as renovateWorker from './workers/global/index.ts'; vi.mock('./instrumentation/index.ts'); vi.mock('./proxy.ts'); vi.mock('./workers/global/index.ts'); +vi.mock('./workers/global/config/parse/cli.ts'); describe('renovate', () => { it('starts', async () => { diff --git a/lib/renovate.ts b/lib/renovate.ts index c6e929c8962..f7bed3cf460 100644 --- a/lib/renovate.ts +++ b/lib/renovate.ts @@ -4,6 +4,11 @@ import 'source-map-support/register.js'; import './punycode.cjs'; void (async (): Promise => { + // prints and exits the process if --version or --help is passed + const { parseEarlyFlags } = + await import('./workers/global/config/parse/cli.ts'); + parseEarlyFlags(); + // has to be imported before logger and other libraries which are instrumentalised const otel = await import('./instrumentation/index.ts'); otel.init(); diff --git a/lib/workers/global/config/parse/cli.spec.ts b/lib/workers/global/config/parse/cli.spec.ts index d66e447f2ff..9cb9e9602b5 100644 --- a/lib/workers/global/config/parse/cli.spec.ts +++ b/lib/workers/global/config/parse/cli.spec.ts @@ -1,3 +1,4 @@ +import { pkg } from '../../../../expose.ts'; import { DockerDatasource } from '../../../../modules/datasource/docker/index.ts'; import getArgv from './__fixtures__/argv.ts'; import * as cli from './cli.ts'; @@ -206,4 +207,23 @@ describe('workers/global/config/parse/cli', () => { expect(cli.getConfig(argv)).toEqual({ requireConfig: 'optional' }); }); }); + + describe('.parseEarlyFlags(argv)', () => { + it('prints version and exits when --version is passed', () => { + const exitSpy = vi + .spyOn(process, 'exit') + .mockImplementation((() => undefined) as never); + const stdoutSpy = vi.spyOn(process.stdout, 'write').mockReturnValue(true); + + cli.parseEarlyFlags([...argv, '--version']); + + expect(stdoutSpy).toHaveBeenCalledExactlyOnceWith( + expect.stringContaining(pkg.version), + ); + expect(exitSpy).toHaveBeenCalledExactlyOnceWith(0); + + stdoutSpy.mockRestore(); + exitSpy.mockRestore(); + }); + }); }); diff --git a/lib/workers/global/config/parse/cli.ts b/lib/workers/global/config/parse/cli.ts index a02c574b506..fbc2651360f 100644 --- a/lib/workers/global/config/parse/cli.ts +++ b/lib/workers/global/config/parse/cli.ts @@ -15,39 +15,9 @@ export function getCliName(option: ParseConfigOptions): string { return `--${nameWithHyphens.toLowerCase()}`; } -export function getConfig(input: string[]): AllConfig { - // massage migrated configuration keys - const argv = input - .map((a) => - a - .replace( - '--allow-post-upgrade-command-templating', - '--allow-command-templating', - ) - .replace('--allowed-post-upgrade-commands', '--allowed-commands') - .replace('--endpoints=', '--host-rules=') - .replace('--expose-env=true', '--trust-level=high') - .replace('--expose-env', '--trust-level=high') - .replace('--renovate-fork', '--include-forks') - .replace('"platform":"', '"hostType":"') - .replace('"endpoint":"', '"matchHost":"') - .replace('"host":"', '"matchHost":"') - .replace('--azure-auto-complete', '--platform-automerge') // migrate: azureAutoComplete - .replace('--git-lab-automerge', '--platform-automerge') // migrate: gitLabAutomerge - .replace(/^--dry-run$/, '--dry-run=true') - .replace(/^--require-config$/, '--require-config=true') - .replace('--aliases', '--registry-aliases') - .replace('--include-forks=true', '--fork-processing=enabled') - .replace('--include-forks', '--fork-processing=enabled') - .replace('--recreate-closed=false', '--recreate-when=auto') - .replace('--recreate-closed=true', '--recreate-when=always') - .replace('--recreate-closed', '--recreate-when=always'), - ) - .filter((a) => !a.startsWith('--git-fs')); +function createProgram(): Command<[string[]]> { const options = getOptions(); - const config: Record = {}; - let program = new Command().arguments('[repositories...]'); options.forEach((option) => { @@ -78,9 +48,49 @@ export function getConfig(input: string[]): AllConfig { /* oxlint-enable no-console */ } - program = program + return program .version(pkg.version, '-v, --version') - .on('--help', helpConsole) + .on('--help', helpConsole); +} + +export function parseEarlyFlags(input: string[] = process.argv): void { + createProgram().allowUnknownOption().allowExcessArguments().parse(input); +} + +export function getConfig(input: string[]): AllConfig { + // massage migrated configuration keys + const argv = input + .map((a) => + a + .replace( + '--allow-post-upgrade-command-templating', + '--allow-command-templating', + ) + .replace('--allowed-post-upgrade-commands', '--allowed-commands') + .replace('--endpoints=', '--host-rules=') + .replace('--expose-env=true', '--trust-level=high') + .replace('--expose-env', '--trust-level=high') + .replace('--renovate-fork', '--include-forks') + .replace('"platform":"', '"hostType":"') + .replace('"endpoint":"', '"matchHost":"') + .replace('"host":"', '"matchHost":"') + .replace('--azure-auto-complete', '--platform-automerge') // migrate: azureAutoComplete + .replace('--git-lab-automerge', '--platform-automerge') // migrate: gitLabAutomerge + .replace(/^--dry-run$/, '--dry-run=true') + .replace(/^--require-config$/, '--require-config=true') + .replace('--aliases', '--registry-aliases') + .replace('--include-forks=true', '--fork-processing=enabled') + .replace('--include-forks', '--fork-processing=enabled') + .replace('--recreate-closed=false', '--recreate-when=auto') + .replace('--recreate-closed=true', '--recreate-when=always') + .replace('--recreate-closed', '--recreate-when=always'), + ) + .filter((a) => !a.startsWith('--git-fs')); + const options = getOptions(); + + const config: Record = {}; + + createProgram() .action((repositories: string[], opts: Record) => { if (repositories?.length) { config.repositories = repositories;