From c36ac9742b2101c89df86b208b70eef23c56f215 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 6 Apr 2025 11:31:02 +0200 Subject: [PATCH] cli: repo start partial parsing of script options Signed-off-by: Patrik Oldsberg --- .../src/modules/build/lib/bundler/server.ts | 1 + packages/cli/src/modules/config/lib/config.ts | 8 +++-- .../commands/package/start/startFrontend.ts | 2 +- .../src/modules/start/commands/repo/start.ts | 36 ++++++++++++++++--- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/modules/build/lib/bundler/server.ts b/packages/cli/src/modules/build/lib/bundler/server.ts index 4541ecf12c..9d4af5c0fe 100644 --- a/packages/cli/src/modules/build/lib/bundler/server.ts +++ b/packages/cli/src/modules/build/lib/bundler/server.ts @@ -77,6 +77,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be const cliConfig = await loadCliConfig({ args: options.configPaths, + targetDir: options.targetDir, fromPackage: name, withFilteredKeys: true, watch(appConfigs) { diff --git a/packages/cli/src/modules/config/lib/config.ts b/packages/cli/src/modules/config/lib/config.ts index afed53af6f..a8d137c60a 100644 --- a/packages/cli/src/modules/config/lib/config.ts +++ b/packages/cli/src/modules/config/lib/config.ts @@ -19,9 +19,11 @@ import { AppConfig, ConfigReader } from '@backstage/config'; import { paths } from '../../../lib/paths'; import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from '@backstage/cli-node'; +import { resolve as resolvePath } from 'path'; type Options = { args: string[]; + targetDir?: string; fromPackage?: string; mockEnv?: boolean; withFilteredKeys?: boolean; @@ -32,8 +34,10 @@ type Options = { }; export async function loadCliConfig(options: Options) { + const targetDir = options.targetDir ?? paths.targetDir; + // Consider all packages in the monorepo when loading in config - const { packages } = await getPackages(paths.targetDir); + const { packages } = await getPackages(targetDir); let localPackageNames; if (options.fromPackage) { @@ -70,7 +74,7 @@ export async function loadCliConfig(options: Options) { : undefined, watch: Boolean(options.watch), rootDir: paths.targetRoot, - argv: options.args.flatMap(t => ['--config', paths.resolveTarget(t)]), + argv: options.args.flatMap(t => ['--config', resolvePath(targetDir, t)]), }); const appConfigs = await new Promise((resolve, reject) => { diff --git a/packages/cli/src/modules/start/commands/package/start/startFrontend.ts b/packages/cli/src/modules/start/commands/package/start/startFrontend.ts index 23aa46d7f7..d4b2f6a1cd 100644 --- a/packages/cli/src/modules/start/commands/package/start/startFrontend.ts +++ b/packages/cli/src/modules/start/commands/package/start/startFrontend.ts @@ -37,7 +37,7 @@ interface StartAppOptions { export async function startFrontend(options: StartAppOptions) { const packageJson = (await readJson( - paths.resolveTarget('package.json'), + resolvePath(options.targetDir ?? paths.targetDir, 'package.json'), )) as BackstagePackageJson; const waitForExit = await serveBundle({ diff --git a/packages/cli/src/modules/start/commands/repo/start.ts b/packages/cli/src/modules/start/commands/repo/start.ts index ef51a8e89d..6ca204e169 100644 --- a/packages/cli/src/modules/start/commands/repo/start.ts +++ b/packages/cli/src/modules/start/commands/repo/start.ts @@ -23,6 +23,7 @@ import { relative as relativePath } from 'path'; import { paths } from '../../../../lib/paths'; import { resolveLinkedWorkspace } from '../package/start/resolveLinkedWorkspace'; import { startPackage } from '../package/start/startPackage'; +import { parseArgs } from 'util'; const ACCEPTED_PACKAGE_ROLES: Array = [ 'frontend', @@ -40,19 +41,46 @@ export async function command( `Starting ${targetPackages.map(p => p.packageJson.name).join(', ')}`, ); - // Blocking + // Each of these block until interrupt by user await Promise.all( targetPackages.map(async pkg => { - const opts = { config: [], require: undefined }; + const startScript = pkg.packageJson.scripts?.start; + if (!startScript) { + console.log( + `No start script found for package ${pkg.packageJson.name}, skipping...`, + ); + return undefined; + } + + // Grab and parse --config and --require options from the start scripts, the rest are ignored + // TODO(Rugvip): Prolly switch over to completely different arg parsing to avoid this duplication + const { values: parsedOpts } = parseArgs({ + args: startScript.split(' '), + strict: false, + options: { + config: { + type: 'string', + multiple: true, + }, + require: { + type: 'string', + }, + }, + }); + const parsedRequire = + typeof parsedOpts.require === 'string' ? parsedOpts.require : undefined; + const parsedConfig = + parsedOpts.config?.filter(c => typeof c === 'string') ?? []; + return startPackage({ role: pkg.packageJson.backstage?.role!, targetDir: pkg.dir, - configPaths: opts.config as string[], + configPaths: options.config.length > 0 ? options.config : parsedConfig, checksEnabled: false, linkedWorkspace: await resolveLinkedWorkspace(options.link), inspectEnabled: false, inspectBrkEnabled: false, - require: opts.require, + require: parsedRequire, }); }), );