Split CLI modules into separate packages

Extract each CLI module from packages/cli/src/modules/ into its own
package under packages/cli-module-*. This enables independent versioning
and clearer dependency boundaries for each CLI capability.

Module mapping:
- auth → @backstage/cli-module-auth
- build → @backstage/cli-module-build
- config → @backstage/cli-module-config
- create-github-app → @backstage/cli-module-create-github-app
- info → @backstage/cli-module-info
- lint → @backstage/cli-module-lint
- maintenance → @backstage/cli-module-maintenance
- migrate → @backstage/cli-module-migrate
- new → @backstage/cli-module-new
- test → @backstage/cli-module-test-jest
- translations → @backstage/cli-module-translations

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
This commit is contained in:
Patrik Oldsberg
2026-03-13 13:43:02 +01:00
parent 18012b5802
commit a151ad0814
251 changed files with 1327 additions and 339 deletions
+1
View File
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -0,0 +1,10 @@
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: backstage-cli-module-auth
title: '@backstage/cli-module-auth'
description: CLI module for Backstage CLI
spec:
lifecycle: experimental
type: backstage-cli-module
owner: tooling-maintainers
+51
View File
@@ -0,0 +1,51 @@
{
"name": "@backstage/cli-module-auth",
"version": "0.1.0",
"description": "CLI module for Backstage CLI",
"backstage": {
"role": "cli-module"
},
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"homepage": "https://backstage.io",
"repository": {
"type": "git",
"url": "https://github.com/backstage/backstage",
"directory": "packages/cli-module-auth"
},
"license": "Apache-2.0",
"main": "src/index.ts",
"types": "src/index.ts",
"files": [
"dist"
],
"scripts": {
"build": "backstage-cli package build",
"clean": "backstage-cli package clean",
"lint": "backstage-cli package lint",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack",
"test": "backstage-cli package test"
},
"dependencies": {
"@backstage/cli-node": "workspace:^",
"@backstage/errors": "workspace:^",
"cleye": "^2.3.0",
"fs-extra": "^11.2.0",
"glob": "^7.1.7",
"inquirer": "^8.2.0",
"proper-lockfile": "^4.1.2",
"yaml": "^2.0.0",
"zod": "^3.25.76"
},
"devDependencies": {
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"@types/fs-extra": "^11.0.0",
"@types/proper-lockfile": "^4",
"cross-fetch": "^4.0.0"
}
}
@@ -15,7 +15,7 @@
*/
import { cli } from 'cleye';
import type { CliCommandContext } from '../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
import { getAllInstances } from '../lib/storage';
export default async ({ args, info }: CliCommandContext) => {
@@ -15,7 +15,7 @@
*/
import { cli } from 'cleye';
import type { CliCommandContext } from '../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
import { startCallbackServer } from '../lib/localServer';
import { spawn } from 'node:child_process';
import { challengeFromVerifier, generateVerifier } from '../lib/pkce';
@@ -15,7 +15,7 @@
*/
import { cli } from 'cleye';
import type { CliCommandContext } from '../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
import { getSecretStore } from '../lib/secretStore';
import {
removeInstance,
@@ -15,7 +15,7 @@
*/
import { cli } from 'cleye';
import type { CliCommandContext } from '../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
import { accessTokenNeedsRefresh, refreshAccessToken } from '../lib/auth';
import { getSelectedInstance } from '../lib/storage';
import { getSecretStore } from '../lib/secretStore';
@@ -15,7 +15,7 @@
*/
import { cli } from 'cleye';
import type { CliCommandContext } from '../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
import { setSelectedInstance } from '../lib/storage';
import { pickInstance } from '../lib/prompt';
@@ -15,7 +15,7 @@
*/
import { cli } from 'cleye';
import type { CliCommandContext } from '../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
import { httpJson } from '../lib/http';
import { getSelectedInstance } from '../lib/storage';
import { accessTokenNeedsRefresh, refreshAccessToken } from '../lib/auth';
@@ -14,8 +14,8 @@
* limitations under the License.
*/
import { createCliModule } from '../../wiring/factory';
import packageJson from '../../../package.json';
import { createCliModule } from '@backstage/cli-node';
import packageJson from '../package.json';
export default createCliModule({
packageJson,
+1
View File
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -0,0 +1,10 @@
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: backstage-cli-module-build
title: '@backstage/cli-module-build'
description: CLI module for Backstage CLI
spec:
lifecycle: experimental
type: backstage-cli-module
owner: tooling-maintainers
+92
View File
@@ -0,0 +1,92 @@
{
"name": "@backstage/cli-module-build",
"version": "0.1.0",
"description": "CLI module for Backstage CLI",
"backstage": {
"role": "cli-module"
},
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"homepage": "https://backstage.io",
"repository": {
"type": "git",
"url": "https://github.com/backstage/backstage",
"directory": "packages/cli-module-build"
},
"license": "Apache-2.0",
"main": "src/index.ts",
"types": "src/index.ts",
"files": [
"dist"
],
"scripts": {
"build": "backstage-cli package build",
"clean": "backstage-cli package clean",
"lint": "backstage-cli package lint",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack",
"test": "backstage-cli package test"
},
"dependencies": {
"@backstage/cli-common": "workspace:^",
"@backstage/cli-node": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/config-loader": "workspace:^",
"@backstage/errors": "workspace:^",
"@manypkg/get-packages": "^1.1.3",
"@module-federation/enhanced": "^0.21.6",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.2",
"@rollup/plugin-commonjs": "^26.0.0",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-yaml": "^4.0.0",
"@rspack/core": "^1.4.11",
"@rspack/dev-server": "^1.1.4",
"@rspack/plugin-react-refresh": "^1.4.3",
"bfj": "^9.0.2",
"chalk": "^4.0.0",
"chokidar": "^3.5.3",
"cleye": "^2.3.0",
"ctrlc-windows": "^2.1.0",
"esbuild-loader": "^4.4.2",
"eslint-rspack-plugin": "^4.2.1",
"eslint-webpack-plugin": "^5.0.3",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"fs-extra": "^11.2.0",
"glob": "^7.1.7",
"html-webpack-plugin": "^5.6.3",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^2.10.1",
"node-stdlib-browser": "^1.3.1",
"npm-packlist": "^5.0.0",
"p-queue": "^6.6.2",
"postcss": "^8.1.0",
"postcss-import": "^16.1.0",
"react-dev-utils": "^12.0.0-next.60",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-esbuild": "^6.1.1",
"rollup-plugin-postcss": "^4.0.0",
"rollup-pluginutils": "^2.8.2",
"shell-quote": "^1.8.1",
"tar": "^7.5.6",
"ts-checker-rspack-plugin": "^1.1.5",
"webpack": "^5.105.4",
"webpack-dev-server": "^5.2.3",
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"@backstage/module-federation-common": "workspace:^",
"@types/fs-extra": "^11.0.0",
"@types/lodash": "^4.14.151",
"@types/npm-packlist": "^3.0.0",
"@types/shell-quote": "^1.7.5",
"cross-spawn": "^7.0.6",
"rollup": "^4.59.0",
"ts-morph": "^24.0.0"
}
}
@@ -17,7 +17,7 @@
import fs from 'fs-extra';
import { cli } from 'cleye';
import { createDistWorkspace } from '../lib/packager';
import type { CliCommandContext } from '../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
export default async ({ args, info }: CliCommandContext) => {
// Normalize legacy --alwaysYarnPack alias (a genuinely different name, not
@@ -29,7 +29,7 @@ import { buildFrontend } from '../../../lib/buildFrontend';
import { buildBackend } from '../../../lib/buildBackend';
import { isValidUrl } from '../../../lib/urls';
import chalk from 'chalk';
import type { CliCommandContext } from '../../../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
export default async ({ args, info }: CliCommandContext) => {
const {
@@ -17,7 +17,7 @@
import { cli } from 'cleye';
import fs from 'fs-extra';
import { targetPaths } from '@backstage/cli-common';
import type { CliCommandContext } from '../../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
export default async ({ args, info }: CliCommandContext) => {
cli({ help: info, booleanFlagNegation: true }, undefined, args);
@@ -17,7 +17,7 @@
import { cli } from 'cleye';
import { targetPaths } from '@backstage/cli-common';
import { revertProductionPack } from '../../lib/packager/productionPack';
import type { CliCommandContext } from '../../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
export default async ({ args, info }: CliCommandContext) => {
cli({ help: info, booleanFlagNegation: true }, undefined, args);
@@ -20,7 +20,7 @@ import { targetPaths } from '@backstage/cli-common';
import { productionPack } from '../../lib/packager/productionPack';
import { publishPreflightCheck } from '../../lib/publishing';
import { createTypeDistProject } from '../../lib/typeDistProject';
import type { CliCommandContext } from '../../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
export default async ({ args, info }: CliCommandContext) => {
cli({ help: info, booleanFlagNegation: true }, undefined, args);
@@ -19,7 +19,7 @@ import { startPackage } from './startPackage';
import { resolveLinkedWorkspace } from './resolveLinkedWorkspace';
import { findRoleFromCommand } from '../../../lib/role';
import { targetPaths } from '@backstage/cli-common';
import type { CliCommandContext } from '../../../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
export default async ({ args, info }: CliCommandContext) => {
const {
@@ -29,7 +29,7 @@ import {
import { buildFrontend } from '../../lib/buildFrontend';
import { buildBackend } from '../../lib/buildBackend';
import { createScriptOptionsParser } from '../../lib/optionsParser';
import type { CliCommandContext } from '../../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
export default async ({ args, info }: CliCommandContext) => {
const {
@@ -19,7 +19,7 @@ import fs from 'fs-extra';
import { resolve as resolvePath } from 'node:path';
import { PackageGraph } from '@backstage/cli-node';
import { run, targetPaths } from '@backstage/cli-common';
import type { CliCommandContext } from '../../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
export default async ({ args, info }: CliCommandContext) => {
cli({ help: info, booleanFlagNegation: true }, undefined, args);
@@ -26,7 +26,7 @@ import { cli } from 'cleye';
import { resolveLinkedWorkspace } from '../package/start/resolveLinkedWorkspace';
import { startPackage } from '../package/start/startPackage';
import { parseArgs } from 'node:util';
import type { CliCommandContext } from '../../../../wiring/types';
import type { CliCommandContext } from '@backstage/cli-node';
const ACCEPTED_PACKAGE_ROLES: Array<PackageRole | undefined> = [
'frontend',
@@ -15,7 +15,7 @@
*/
import { createCliModule } from '@backstage/cli-node';
import packageJson from '../../../package.json';
import packageJson from '../package.json';
export const buildPlugin = createCliModule({
packageJson,
@@ -32,7 +32,7 @@ import pickBy from 'lodash/pickBy';
import { runOutput, targetPaths } from '@backstage/cli-common';
import { transforms } from './transforms';
import { version } from '../../../../wiring/version';
const { version } = require('../../../../package.json') as { version: string };
import yn from 'yn';
import { hasReactDomClient } from './hasReactDomClient';
import { createWorkspaceLinkingPlugins } from './linkWorkspaces';
@@ -16,7 +16,7 @@
import fs from 'fs-extra';
import { resolve as resolvePath } from 'node:path';
import { targetPaths, findOwnPaths } from '@backstage/cli-common';
import { targetPaths } from '@backstage/cli-common';
export type BundlingPathsOptions = {
// bundle entrypoint, e.g. 'src/index'
@@ -50,8 +50,8 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) {
targetHtml = resolvePath(targetDir, `${entry}.html`);
if (!fs.pathExistsSync(targetHtml)) {
/* eslint-disable-next-line no-restricted-syntax */
targetHtml = findOwnPaths(__dirname).resolve(
'templates/serve_index.html',
targetHtml = require.resolve(
'@backstage/cli/templates/serve_index.html',
);
}
}
@@ -27,10 +27,13 @@ import partition from 'lodash/partition';
import { run, targetPaths } from '@backstage/cli-common';
import {
dependencies as cliDependencies,
devDependencies as cliDevDependencies,
} from '../../../../../package.json';
const {
dependencies: cliDependencies,
devDependencies: cliDevDependencies,
} = require('../../../../package.json') as {
dependencies: Record<string, string>;
devDependencies: Record<string, string>;
};
import {
BuildOptions,
buildPackages,

Some files were not shown because too many files have changed in this diff Show More