Merge pull request #32999 from backstage/rugvip/cli-internalize-lib-into-modules

cli: internalize shared lib utilities into consuming modules
This commit is contained in:
Patrik Oldsberg
2026-02-25 18:58:17 +01:00
committed by GitHub
15 changed files with 97 additions and 24 deletions
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Internal refactor to move shared utilities into their consuming modules, reducing cross-module dependencies.
@@ -0,0 +1,5 @@
---
'@backstage/cli': minor
---
**BREAKING**: The `migrate package-exports` command has been removed. Use `repo fix` instead.
@@ -22,7 +22,7 @@ import { targetPaths } from '@backstage/cli-common';
import fs from 'fs-extra';
import { publishPreflightCheck } from '../../lib/publishing';
import { createTypeDistProject } from '../../../../lib/typeDistProject';
import { createTypeDistProject } from '../../lib/typeDistProject';
export const pre = async () => {
publishPreflightCheck({
@@ -28,7 +28,7 @@ import {
} from '@backstage/cli-node';
import { buildFrontend } from '../../lib/buildFrontend';
import { buildBackend } from '../../lib/buildBackend';
import { createScriptOptionsParser } from '../../../../lib/optionsParser';
import { createScriptOptionsParser } from '../../lib/optionsParser';
export async function command(opts: OptionValues, cmd: Command): Promise<void> {
let packages = await PackageGraph.listTargetPackages();
+7 -1
View File
@@ -17,7 +17,13 @@
import { Command, Option } from 'commander';
import { createCliPlugin } from '../../wiring/factory';
import { lazy } from '../../wiring/lazy';
import { configOption } from '../config';
const configOption = [
'--config <path>',
'Config files to load instead of app-config.yaml',
(opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]),
Array<string>(),
] as const;
export function registerPackageCommands(command: Command) {
command
@@ -20,7 +20,7 @@ import { readEntryPoints } from '../entryPoints';
import {
createTypeDistProject,
getEntryPointDefaultFeatureType,
} from '../../../../lib/typeDistProject';
} from '../typeDistProject';
import {
BACKSTAGE_RUNTIME_SHARED_DEPENDENCIES_GLOBAL,
defaultRemoteSharedDependencies,
@@ -62,8 +62,8 @@ export function createScriptOptionsParser(
// Triggers the writing of options to the result object
cmd.parseOptions(argsStr.split(' '));
(cmd as any)._storeOptionsAsProperties = currentOpts;
(cmd as any)._optionValues = currentStore;
(cmd as any)._optionValues = currentOpts;
(cmd as any)._storeOptionsAsProperties = currentStore;
return result;
};
@@ -44,7 +44,7 @@ import {
PackageGraphNode,
runConcurrentTasks,
} from '@backstage/cli-node';
import { createTypeDistProject } from '../../../../lib/typeDistProject';
import { createTypeDistProject } from '../typeDistProject';
// These packages aren't safe to pack in parallel since the CLI depends on them
const UNSAFE_PACKAGES = [
@@ -19,7 +19,7 @@ import npmPackList from 'npm-packlist';
import { resolve as resolvePath, posix as posixPath } from 'node:path';
import { BackstagePackageJson } from '@backstage/cli-node';
import { readEntryPoints } from '../entryPoints';
import { getEntryPointDefaultFeatureType } from '../../../../lib/typeDistProject';
import { getEntryPointDefaultFeatureType } from '../typeDistProject';
import { Project } from 'ts-morph';
const PKG_PATH = 'package.json';
@@ -27,7 +27,7 @@ import {
} from '@backstage/cli-node';
import { targetPaths } from '@backstage/cli-common';
import { createScriptOptionsParser } from '../../../../lib/optionsParser';
import { createScriptOptionsParser } from '../../lib/optionsParser';
import { SuccessCache } from '../../../../lib/cache/SuccessCache';
function depCount(pkg: BackstagePackageJson) {
@@ -0,0 +1,70 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Command } from 'commander';
export function createScriptOptionsParser(
anyCmd: Command,
commandPath: string[],
) {
// Regardless of what command instance is passed in we want to find
// the root command and resolve the path from there
let rootCmd = anyCmd;
while (rootCmd.parent) {
rootCmd = rootCmd.parent;
}
// Now find the command that was requested
let targetCmd = rootCmd as Command | undefined;
for (const name of commandPath) {
targetCmd = targetCmd?.commands.find(c => c.name() === name) as
| Command
| undefined;
}
if (!targetCmd) {
throw new Error(
`Could not find package command '${commandPath.join(' ')}'`,
);
}
const cmd = targetCmd;
const expectedScript = `backstage-cli ${commandPath.join(' ')}`;
return (scriptStr?: string) => {
if (!scriptStr || !scriptStr.startsWith(expectedScript)) {
return undefined;
}
const argsStr = scriptStr.slice(expectedScript.length).trim();
// Can't clone or copy or even use commands as prototype, so we mutate
// the necessary members instead, and then reset them once we're done
const currentOpts = (cmd as any)._optionValues;
const currentStore = (cmd as any)._storeOptionsAsProperties;
const result: Record<string, any> = {};
(cmd as any)._storeOptionsAsProperties = false;
(cmd as any)._optionValues = result;
// Triggers the writing of options to the result object
cmd.parseOptions(argsStr.split(' '));
(cmd as any)._optionValues = currentOpts;
(cmd as any)._storeOptionsAsProperties = currentStore;
return result;
};
}
@@ -14,21 +14,8 @@
* limitations under the License.
*/
import {
fixPackageExports,
readFixablePackages,
writeFixedPackages,
} from '../../maintenance/commands/repo/fix';
export async function command() {
console.log(
'The `migrate package-exports` command is deprecated, use `repo fix` instead.',
throw new Error(
'The `migrate package-exports` command has been removed, use `repo fix` instead.',
);
const packages = await readFixablePackages();
for (const pkg of packages) {
fixPackageExports(pkg);
}
await writeFixedPackages(packages);
}