feat: promote backstage-cli-alpha to the main entrypoint (#29943)

* feat: promote backstage-cli-alpha to the main entrypoint

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

* add changeset

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

* fix api report

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

* fix repo lint command

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

* strict is not required

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

* weird quirk for the repo-wide linting command

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

* fix repo start command

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

* fix api report

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

* fix dynamic import

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>

---------

Signed-off-by: aramissennyeydd <aramis.sennyey@doordash.com>
This commit is contained in:
Aramis Sennyey
2025-06-10 10:23:02 -04:00
committed by GitHub
parent 5445a859fc
commit eef0e83a0d
26 changed files with 770 additions and 2012 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': minor
---
Internal update to promote the modular CLI entrypoint to stable.
-521
View File
@@ -1,521 +0,0 @@
## CLI Report file for "@backstage/cli"
> Do not edit this file. It is a report generated by `yarn build:api-reports`
### `backstage-cli`
```
Usage: backstage-cli [options] [command]
Options:
-V, --version
-h, --help
Commands:
build-workspace [options] <workspace-dir> [packages...]
config:check [options]
config:docs [options]
config:print [options]
config:schema [options]
create-github-app <github-org>
help [command]
info
migrate [command]
new [options]
package [command]
repo [command]
versions:bump [options]
versions:migrate [options]
```
### `backstage-cli build-workspace`
```
Usage: backstage-cli build-workspace [options] <workspace-dir> [packages...]
Options:
--alwaysPack
-h, --help
```
### `backstage-cli config:check`
```
Usage: backstage-cli config:check [options]
Options:
--config <path>
--deprecated
--frontend
--lax
--package <name>
--strict
-h, --help
```
### `backstage-cli config:docs`
```
Usage: backstage-cli config:docs [options]
Options:
--package <name>
-h, --help
```
### `backstage-cli config:print`
```
Usage: backstage-cli config:print [options]
Options:
--config <path>
--format <format>
--frontend
--lax
--package <name>
--with-secrets
-h, --help
```
### `backstage-cli config:schema`
```
Usage: backstage-cli config:schema [options]
Options:
--format <format>
--merge
--no-merge
--package <name>
-h, --help
```
### `backstage-cli create-github-app`
```
Usage: backstage-cli create-github-app [options] <github-org>
Options:
-h, --help
```
### `backstage-cli info`
```
Usage: backstage-cli info [options]
Options:
-h, --help
```
### `backstage-cli migrate`
```
Usage: backstage-cli migrate [options] [command] [command]
Options:
-h, --help
Commands:
help [command]
package-exports
package-lint-configs
package-roles
package-scripts
react-router-deps
```
### `backstage-cli migrate package-exports`
```
Usage: backstage-cli migrate package-exports [options]
Options:
-h, --help
```
### `backstage-cli migrate package-lint-configs`
```
Usage: backstage-cli migrate package-lint-configs [options]
Options:
-h, --help
```
### `backstage-cli migrate package-roles`
```
Usage: backstage-cli migrate package-roles [options]
Options:
-h, --help
```
### `backstage-cli migrate package-scripts`
```
Usage: backstage-cli migrate package-scripts [options]
Options:
-h, --help
```
### `backstage-cli migrate react-router-deps`
```
Usage: backstage-cli migrate react-router-deps [options]
Options:
-h, --help
```
### `backstage-cli new`
```
Usage: backstage-cli new [options]
Options:
--baseVersion <version>
--license <license>
--no-private
--npm-registry <URL>
--option <name>=<value>
--scope <scope>
--select <name>
--skip-install
-h, --help
```
### `backstage-cli package`
```
Usage: backstage-cli package [options] [command] [command]
Options:
-h, --help
Commands:
build [options]
clean
help [command]
lint [options] [directories...]
postpack
prepack
start [options]
test
```
### `backstage-cli package build`
```
Usage: backstage-cli package build [options]
Options:
--config <path>
--minify
--role <name>
--skip-build-dependencies
--stats
-h, --help
```
### `backstage-cli package clean`
```
Usage: backstage-cli package clean [options]
Options:
-h, --help
```
### `backstage-cli package lint`
```
Usage: backstage-cli package lint [options] [directories...]
Options:
--fix
--format <format>
--max-warnings <number>
--output-file <path>
-h, --help
```
### `backstage-cli package postpack`
```
Usage: backstage-cli package postpack [options]
Options:
-h, --help
```
### `backstage-cli package prepack`
```
Usage: backstage-cli package prepack [options]
Options:
-h, --help
```
### `backstage-cli package start`
```
Usage: backstage-cli package start [options]
Options:
--check
--config <path>
--inspect [host]
--inspect-brk [host]
--link <path>
--require <path...>
--role <name>
-h, --help
```
### `backstage-cli package test`
```
Usage: backstage-cli [--config=<pathToConfigFile>] [TestPathPattern]
Options:
--all
--automock
--cache
--cacheDirectory
--changedFilesWithAncestor
--changedSince
--ci
--clearCache
--clearMocks
--collectCoverage
--collectCoverageFrom
--color
--colors
--coverage
--coverageDirectory
--coveragePathIgnorePatterns
--coverageProvider
--coverageReporters
--coverageThreshold
--debug
--detectLeaks
--detectOpenHandles
--env
--errorOnDeprecated
--filter
--findRelatedTests
--forceExit
--globalSetup
--globalTeardown
--globals
--haste
--ignoreProjects
--init
--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
--testEnvironmentOptions
--testFailureExitCode
--testLocationInResults
--testMatch
--testPathIgnorePatterns
--testPathPattern
--testRegex
--testResultsProcessor
--testRunner
--testSequencer
--testTimeout
--transform
--transformIgnorePatterns
--unmockedModulePathPatterns
--useStderr
--verbose
--version
--watch
--watchAll
--watchPathIgnorePatterns
--watchman
--workerThreads
-b, --bail
-c, --config
-e, --expand
-f, --onlyFailures
-h, --help
-i, --runInBand
-o, --onlyChanged
-t, --testNamePattern
-u, --updateSnapshot
-w, --maxWorkers
```
### `backstage-cli repo`
```
Usage: backstage-cli repo [options] [command] [command]
Options:
-h, --help
Commands:
build [options]
clean
fix [options]
help [command]
lint [options]
list-deprecations [options]
start [options] [packageNameOrPath...]
test [options]
```
### `backstage-cli repo build`
```
Usage: backstage-cli repo build [options]
Options:
--all
--minify
--since <ref>
-h, --help
```
### `backstage-cli repo clean`
```
Usage: backstage-cli repo clean [options]
Options:
-h, --help
```
### `backstage-cli repo fix`
```
Usage: backstage-cli repo fix [options]
Options:
--check
--publish
-h, --help
```
### `backstage-cli repo lint`
```
Usage: backstage-cli repo lint [options]
Options:
--fix
--format <format>
--max-warnings <number>
--output-file <path>
--since <ref>
--successCache
--successCacheDir <path>
-h, --help
```
### `backstage-cli repo list-deprecations`
```
Usage: backstage-cli repo list-deprecations [options]
Options:
--json
-h, --help
```
### `backstage-cli repo start`
```
Usage: backstage-cli repo start [options] [packageNameOrPath...]
Options:
--config <path>
--inspect [host]
--inspect-brk [host]
--link <path>
--plugin <pluginId>
--require <path...>
-h, --help
```
### `backstage-cli repo test`
```
Usage: backstage-cli repo test [options]
Options:
--jest-help
--since <ref>
--successCache
--successCacheDir <path>
-h, --help
```
### `backstage-cli versions:bump`
```
Usage: backstage-cli versions:bump [options]
Options:
--pattern <glob>
--release <version|next|main>
--skip-install
--skip-migrate
-h, --help
```
### `backstage-cli versions:migrate`
```
Usage: backstage-cli versions:migrate [options]
Options:
--pattern <glob>
--skip-code-changes
-h, --help
```
@@ -2,7 +2,7 @@
> Do not edit this file. It is a report generated by `yarn build:api-reports`
### `backstage-cli-alpha`
### `backstage-cli`
```
Usage: backstage-cli [options] [command]
@@ -29,7 +29,7 @@ Commands:
versions:migrate
```
### `backstage-cli-alpha build-workspace`
### `backstage-cli build-workspace`
```
Usage: program [options] <workspace-dir> [packages...]
@@ -39,7 +39,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha config`
### `backstage-cli config`
```
Usage: backstage-cli config [options] [command] [command]
@@ -53,7 +53,7 @@ Commands:
schema
```
### `backstage-cli-alpha config docs`
### `backstage-cli config docs`
```
Usage: backstage-cli config docs [options]
@@ -63,7 +63,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha config schema`
### `backstage-cli config schema`
```
Usage: <none>
@@ -77,7 +77,7 @@ Options:
--version
```
### `backstage-cli-alpha config:check`
### `backstage-cli config:check`
```
Usage: <none>
@@ -93,7 +93,7 @@ Options:
--version
```
### `backstage-cli-alpha config:docs`
### `backstage-cli config:docs`
```
Usage: program [options]
@@ -103,7 +103,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha config:print`
### `backstage-cli config:print`
```
Usage: <none>
@@ -119,7 +119,7 @@ Options:
--with-secrets
```
### `backstage-cli-alpha config:schema`
### `backstage-cli config:schema`
```
Usage: <none>
@@ -133,7 +133,7 @@ Options:
--version
```
### `backstage-cli-alpha create-github-app`
### `backstage-cli create-github-app`
```
Usage: program [options] <github-org>
@@ -142,7 +142,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha info`
### `backstage-cli info`
```
Usage: <none>
@@ -152,7 +152,7 @@ Options:
--version
```
### `backstage-cli-alpha migrate`
### `backstage-cli migrate`
```
Usage: backstage-cli migrate [options] [command] [command]
@@ -169,7 +169,7 @@ Commands:
react-router-deps
```
### `backstage-cli-alpha migrate package-exports`
### `backstage-cli migrate package-exports`
```
Usage: program [options]
@@ -178,7 +178,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha migrate package-lint-configs`
### `backstage-cli migrate package-lint-configs`
```
Usage: program [options]
@@ -187,7 +187,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha migrate package-roles`
### `backstage-cli migrate package-roles`
```
Usage: program [options]
@@ -196,7 +196,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha migrate package-scripts`
### `backstage-cli migrate package-scripts`
```
Usage: program [options]
@@ -205,7 +205,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha migrate react-router-deps`
### `backstage-cli migrate react-router-deps`
```
Usage: program [options]
@@ -214,7 +214,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha new`
### `backstage-cli new`
```
Usage: program [options]
@@ -231,7 +231,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha package`
### `backstage-cli package`
```
Usage: backstage-cli package [options] [command] [command]
@@ -250,7 +250,7 @@ Commands:
test
```
### `backstage-cli-alpha package build`
### `backstage-cli package build`
```
Usage: program [options]
@@ -264,7 +264,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha package clean`
### `backstage-cli package clean`
```
Usage: program [options]
@@ -273,7 +273,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha package lint`
### `backstage-cli package lint`
```
Usage: program [options] [directories...]
@@ -286,7 +286,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha package postpack`
### `backstage-cli package postpack`
```
Usage: program [options]
@@ -295,7 +295,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha package prepack`
### `backstage-cli package prepack`
```
Usage: program [options]
@@ -304,7 +304,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha package start`
### `backstage-cli package start`
```
Usage: program [options]
@@ -320,10 +320,10 @@ Options:
-h, --help
```
### `backstage-cli-alpha package test`
### `backstage-cli package test`
```
Usage: backstage-cli-alpha [--config=<pathToConfigFile>] [TestPathPattern]
Usage: backstage-cli [--config=<pathToConfigFile>] [TestPathPattern]
Options:
--all
@@ -434,7 +434,7 @@ Options:
-w, --maxWorkers
```
### `backstage-cli-alpha repo`
### `backstage-cli repo`
```
Usage: backstage-cli repo [options] [command] [command]
@@ -453,7 +453,7 @@ Commands:
test
```
### `backstage-cli-alpha repo build`
### `backstage-cli repo build`
```
Usage: program [options] [command]
@@ -465,7 +465,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha repo clean`
### `backstage-cli repo clean`
```
Usage: program [options]
@@ -474,7 +474,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha repo fix`
### `backstage-cli repo fix`
```
Usage: program [options]
@@ -485,10 +485,10 @@ Options:
-h, --help
```
### `backstage-cli-alpha repo lint`
### `backstage-cli repo lint`
```
Usage: program [options]
Usage: program [options] [command]
Options:
--fix
@@ -501,7 +501,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha repo list-deprecations`
### `backstage-cli repo list-deprecations`
```
Usage: program [options]
@@ -511,10 +511,10 @@ Options:
-h, --help
```
### `backstage-cli-alpha repo start`
### `backstage-cli repo start`
```
Usage: program [options] [...packageNameOrPath]
Usage: program [options] [packageNameOrPath...]
Options:
--config <path>
@@ -526,7 +526,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha repo test`
### `backstage-cli repo test`
```
Usage: program [options]
@@ -539,7 +539,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha versions:bump`
### `backstage-cli versions:bump`
```
Usage: program [options]
@@ -552,7 +552,7 @@ Options:
-h, --help
```
### `backstage-cli-alpha versions:migrate`
### `backstage-cli versions:migrate`
```
Usage: program [options]
+1 -2
View File
@@ -20,8 +20,7 @@
"license": "Apache-2.0",
"main": "dist/index.cjs.js",
"bin": {
"backstage-cli": "bin/backstage-cli",
"backstage-cli-alpha": "bin/backstage-cli-alpha"
"backstage-cli": "bin/backstage-cli"
},
"files": [
"asset-types",
-38
View File
@@ -1,38 +0,0 @@
/*
* 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 { CliInitializer } from './wiring/CliInitializer';
import chalk from 'chalk';
(async () => {
// Logging as stdout to prevent failures from stderr during api-report generation.
console.log(
chalk.yellow(
'THIS ENTRYPOINT IS IN ALPHA AND MAY CHANGE IN THE FUTURE - DO NOT USE THIS FOR NORMAL DEVELOPMENT',
),
);
const initializer = new CliInitializer();
initializer.add(import('./modules/build/alpha'));
initializer.add(import('./modules/config/alpha'));
initializer.add(import('./modules/create-github-app/alpha'));
initializer.add(import('./modules/info/alpha'));
initializer.add(import('./modules/lint/alpha'));
initializer.add(import('./modules/maintenance/alpha'));
initializer.add(import('./modules/migrate/alpha'));
initializer.add(import('./modules/new/alpha'));
initializer.add(import('./modules/test/alpha'));
await initializer.run();
})();
-97
View File
@@ -1,97 +0,0 @@
/*
* Copyright 2020 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';
import { registerCommands as registerConfigCommands } from '../modules/config';
import {
registerPackageCommands as registerPackageBuildCommands,
registerRepoCommands as registerRepoBuildCommands,
registerCommands as registerBuildCommands,
} from '../modules/build';
import { registerCommands as registerInfoCommands } from '../modules/info';
import { registerCommands as registerMigrateCommand } from '../modules/migrate';
import {
registerRepoCommands as registerRepoTestCommands,
registerPackageCommands as registerPackageTestCommands,
} from '../modules/test';
import {
registerPackageCommands as registerPackageLintCommands,
registerRepoCommands as registerRepoLintCommands,
} from '../modules/lint';
import {
registerPackageCommands as registerMaintenancePackageCommands,
registerRepoCommands as registerMaintenanceRepoCommands,
} from '../modules/maintenance';
import { removed } from '../lib/removed';
import { registerCommands as registerNewCommands } from '../modules/new';
import { registerCommands as registerCreateGithubAppCommands } from '../modules/create-github-app';
export function registerRepoCommand(program: Command) {
const command = program
.command('repo [command]')
.description('Command that run across an entire Backstage project');
registerRepoBuildCommands(command);
registerRepoTestCommands(command);
registerRepoLintCommands(command);
registerMaintenanceRepoCommands(command);
}
export function registerScriptCommand(program: Command) {
const command = program
.command('package [command]')
.description('Lifecycle scripts for individual packages');
registerPackageBuildCommands(command);
registerPackageTestCommands(command);
registerMaintenancePackageCommands(command);
registerPackageLintCommands(command);
}
export function registerCommands(program: Command) {
registerConfigCommands(program);
registerRepoCommand(program);
registerScriptCommand(program);
registerMigrateCommand(program);
registerBuildCommands(program);
registerInfoCommands(program);
registerNewCommands(program);
registerCreateGithubAppCommands(program);
// Notifications for removed commands
program
.command('plugin:diff')
.allowUnknownOption(true)
.action(removed("use 'backstage-cli fix' instead"));
program
.command('test')
.allowUnknownOption(true)
.action(
removed(
"use 'backstage-cli repo test' or 'backstage-cli package test' instead",
),
);
program
.command('clean')
.allowUnknownOption(true)
.action(removed("use 'backstage-cli package clean' instead"));
program
.command('versions:check')
.allowUnknownOption(true)
.action(removed("use 'yarn dedupe' or 'yarn-deduplicate' instead"));
program.command('install').allowUnknownOption(true).action(removed());
program.command('onboard').allowUnknownOption(true).action(removed());
}
+15 -37
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* 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.
@@ -14,40 +14,18 @@
* limitations under the License.
*/
/**
* CLI for developing Backstage plugins and apps
*
* @packageDocumentation
*/
import { CliInitializer } from './wiring/CliInitializer';
import { program } from 'commander';
import chalk from 'chalk';
import { exitWithError } from './lib/errors';
import { version } from './lib/version';
import { registerCommands } from './commands';
const main = (argv: string[]) => {
program.name('backstage-cli').version(version);
registerCommands(program);
program.on('command:*', () => {
console.log();
console.log(chalk.red(`Invalid command: ${program.args.join(' ')}`));
console.log();
program.outputHelp();
process.exit(1);
});
program.parse(argv);
};
process.on('unhandledRejection', rejection => {
if (rejection instanceof Error) {
exitWithError(rejection);
} else {
exitWithError(new Error(`Unknown rejection: '${rejection}'`));
}
});
main(process.argv);
(async () => {
const initializer = new CliInitializer();
initializer.add(import('./modules/build'));
initializer.add(import('./modules/config'));
initializer.add(import('./modules/create-github-app'));
initializer.add(import('./modules/info'));
initializer.add(import('./modules/lint'));
initializer.add(import('./modules/maintenance'));
initializer.add(import('./modules/migrate'));
initializer.add(import('./modules/new'));
initializer.add(import('./modules/test'));
await initializer.run();
})();
-190
View File
@@ -1,190 +0,0 @@
/*
* 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, Option } from 'commander';
import { createCliPlugin } from '../../wiring/factory';
import { lazy } from '../../lib/lazy';
import { registerPackageCommands } from '.';
import { configOption } from '../config';
export const buildPlugin = createCliPlugin({
pluginId: 'build',
init: async reg => {
reg.addCommand({
path: ['package', 'build'],
description: 'Build a package for production deployment or publishing',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--role <name>',
'Run the command with an explicit package role',
)
.option(
'--minify',
'Minify the generated code. Does not apply to app package (app is minified by default).',
)
.option(
'--skip-build-dependencies',
'Skip the automatic building of local dependencies. Applies to backend packages only.',
)
.option(
'--stats',
'If bundle stats are available, write them to the output directory. Applies to app packages only.',
)
.option(
'--config <path>',
'Config files to load instead of app-config.yaml. Applies to app packages only.',
(opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]),
Array<string>(),
)
.action(lazy(() => import('./commands/package/build'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'build'],
description:
'Build packages in the project, excluding bundled app and backend packages.',
execute: async ({ args }) => {
const command = new Command();
// This command expect `package build` to be registered, as its used to parse
// individual plugins' package build scripts.
registerPackageCommands(command.command('package'));
const defaultCommand = command
.option(
'--all',
'Build all packages, including bundled app and backend packages.',
)
.option(
'--since <ref>',
'Only build packages and their dev dependents that changed since the specified ref',
)
.option(
'--minify',
'Minify the generated code. Does not apply to app package (app is minified by default).',
)
.action(lazy(() => import('./commands/repo/build'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['package', 'start'],
description: 'Start a package for local development',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(...configOption)
.option(
'--role <name>',
'Run the command with an explicit package role',
)
.option('--check', 'Enable type checking and linting if available')
.option('--inspect [host]', 'Enable debugger in Node.js environments')
.option(
'--inspect-brk [host]',
'Enable debugger in Node.js environments, breaking before code starts',
)
.option(
'--require <path...>',
'Add a --require argument to the node process',
)
.option(
'--link <path>',
'Link an external workspace for module resolution',
)
.action(lazy(() => import('./commands/package/start'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'start'],
description: 'Starts packages in the repo for local development',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.argument(
'[...packageNameOrPath]',
'Run the specified package instead of the defaults.',
)
.option(
'--plugin <pluginId>',
'Start the dev entry-point for any matching plugin package in the repo',
(opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]),
Array<string>(),
)
.option(...configOption)
.option(
'--inspect [host]',
'Enable debugger in Node.js environments. Applies to backend package only',
)
.option(
'--inspect-brk [host]',
'Enable debugger in Node.js environments, breaking before code starts. Applies to backend package only',
)
.option(
'--require <path...>',
'Add a --require argument to the node process. Applies to backend package only',
)
.option(
'--link <path>',
'Link an external workspace for module resolution',
)
.action(
lazy(() => import('../build/commands/repo/start'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['build-workspace'],
description:
'Builds a temporary dist workspace from the provided packages',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.arguments('<workspace-dir> [packages...]')
.addOption(
new Option(
'--alwaysYarnPack',
'Alias for --alwaysPack for backwards compatibility.',
)
.implies({ alwaysPack: true })
.hideHelp(true),
)
.option(
'--alwaysPack',
'Force workspace output to be a result of running `yarn pack` on each package (warning: very slow)',
)
.action(lazy(() => import('./commands/buildWorkspace'), 'default'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
},
});
export default buildPlugin;
+170 -86
View File
@@ -13,60 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Command, Option } from 'commander';
import { createCliPlugin } from '../../wiring/factory';
import { lazy } from '../../lib/lazy';
import { configOption } from '../config';
export function registerRepoCommands(command: Command) {
command
.command('build')
.description(
'Build packages in the project, excluding bundled app and backend packages.',
)
.option(
'--all',
'Build all packages, including bundled app and backend packages.',
)
.option(
'--since <ref>',
'Only build packages and their dev dependents that changed since the specified ref',
)
.option(
'--minify',
'Minify the generated code. Does not apply to app package (app is minified by default).',
)
.action(lazy(() => import('./commands/repo/build'), 'command'));
command
.command('start')
.description('Starts packages in the repo for local development')
.argument(
'[packageNameOrPath...]',
'Run the specified package instead of the defaults.',
)
.option(
'--plugin <pluginId>',
'Start the dev entry-point for any matching plugin package in the repo',
(opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]),
Array<string>(),
)
.option(...configOption)
.option(
'--inspect [host]',
'Enable debugger in Node.js environments. Applies to backend package only',
)
.option(
'--inspect-brk [host]',
'Enable debugger in Node.js environments, breaking before code starts. Applies to backend package only',
)
.option(
'--require <path...>',
'Add a --require argument to the node process. Applies to backend package only',
)
.option('--link <path>', 'Link an external workspace for module resolution')
.action(lazy(() => import('../build/commands/repo/start'), 'command'));
}
export function registerPackageCommands(command: Command) {
command
.command('build')
@@ -91,41 +43,173 @@ export function registerPackageCommands(command: Command) {
Array<string>(),
)
.action(lazy(() => import('./commands/package/build'), 'command'));
command
.command('start')
.description('Start a package for local development')
.option(...configOption)
.option('--role <name>', 'Run the command with an explicit package role')
.option('--check', 'Enable type checking and linting if available')
.option('--inspect [host]', 'Enable debugger in Node.js environments')
.option(
'--inspect-brk [host]',
'Enable debugger in Node.js environments, breaking before code starts',
)
.option(
'--require <path...>',
'Add a --require argument to the node process',
)
.option('--link <path>', 'Link an external workspace for module resolution')
.action(lazy(() => import('./commands/package/start'), 'command'));
}
export function registerCommands(program: Command) {
program
.command('build-workspace <workspace-dir> [packages...]')
.addOption(
new Option(
'--alwaysYarnPack',
'Alias for --alwaysPack for backwards compatibility.',
)
.implies({ alwaysPack: true })
.hideHelp(true),
)
.option(
'--alwaysPack',
'Force workspace output to be a result of running `yarn pack` on each package (warning: very slow)',
)
.description('Builds a temporary dist workspace from the provided packages')
.action(lazy(() => import('./commands/buildWorkspace'), 'default'));
}
export const buildPlugin = createCliPlugin({
pluginId: 'build',
init: async reg => {
reg.addCommand({
path: ['package', 'build'],
description: 'Build a package for production deployment or publishing',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--role <name>',
'Run the command with an explicit package role',
)
.option(
'--minify',
'Minify the generated code. Does not apply to app package (app is minified by default).',
)
.option(
'--skip-build-dependencies',
'Skip the automatic building of local dependencies. Applies to backend packages only.',
)
.option(
'--stats',
'If bundle stats are available, write them to the output directory. Applies to app packages only.',
)
.option(
'--config <path>',
'Config files to load instead of app-config.yaml. Applies to app packages only.',
(opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]),
Array<string>(),
)
.action(lazy(() => import('./commands/package/build'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'build'],
description:
'Build packages in the project, excluding bundled app and backend packages.',
execute: async ({ args }) => {
const command = new Command();
// This command expect `package build` to be registered, as its used to parse
// individual plugins' package build scripts.
registerPackageCommands(command.command('package'));
const defaultCommand = command
.option(
'--all',
'Build all packages, including bundled app and backend packages.',
)
.option(
'--since <ref>',
'Only build packages and their dev dependents that changed since the specified ref',
)
.option(
'--minify',
'Minify the generated code. Does not apply to app package (app is minified by default).',
)
.action(lazy(() => import('./commands/repo/build'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['package', 'start'],
description: 'Start a package for local development',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(...configOption)
.option(
'--role <name>',
'Run the command with an explicit package role',
)
.option('--check', 'Enable type checking and linting if available')
.option('--inspect [host]', 'Enable debugger in Node.js environments')
.option(
'--inspect-brk [host]',
'Enable debugger in Node.js environments, breaking before code starts',
)
.option(
'--require <path...>',
'Add a --require argument to the node process',
)
.option(
'--link <path>',
'Link an external workspace for module resolution',
)
.action(lazy(() => import('./commands/package/start'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'start'],
description: 'Starts packages in the repo for local development',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.argument(
'[packageNameOrPath...]',
'Run the specified package instead of the defaults.',
)
.option(
'--plugin <pluginId>',
'Start the dev entry-point for any matching plugin package in the repo',
(opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]),
Array<string>(),
)
.option(...configOption)
.option(
'--inspect [host]',
'Enable debugger in Node.js environments. Applies to backend package only',
)
.option(
'--inspect-brk [host]',
'Enable debugger in Node.js environments, breaking before code starts. Applies to backend package only',
)
.option(
'--require <path...>',
'Add a --require argument to the node process. Applies to backend package only',
)
.option(
'--link <path>',
'Link an external workspace for module resolution',
)
.action(
lazy(() => import('../build/commands/repo/start'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['build-workspace'],
description:
'Builds a temporary dist workspace from the provided packages',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.arguments('<workspace-dir> [packages...]')
.addOption(
new Option(
'--alwaysYarnPack',
'Alias for --alwaysPack for backwards compatibility.',
)
.implies({ alwaysPack: true })
.hideHelp(true),
)
.option(
'--alwaysPack',
'Force workspace output to be a result of running `yarn pack` on each package (warning: very slow)',
)
.action(lazy(() => import('./commands/buildWorkspace'), 'default'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
},
});
export default buildPlugin;
-137
View File
@@ -1,137 +0,0 @@
/*
* 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 { createCliPlugin } from '../../wiring/factory';
import yargs from 'yargs';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export default createCliPlugin({
pluginId: 'config',
init: async reg => {
reg.addCommand({
path: ['config:docs'],
description: 'Browse the configuration reference documentation',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--package <name>',
'Only include the schema that applies to the given package',
)
.description('Browse the configuration reference documentation')
.action(lazy(() => import('./commands/docs'), 'default'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['config', 'docs'],
description: 'Browse the configuration reference documentation',
execute: async ({ args, info }) => {
await new Command(info.usage)
.option(
'--package <name>',
'Only include the schema that applies to the given package',
)
.description(info.description)
.action(lazy(() => import('./commands/docs'), 'default'))
.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['config:print'],
description: 'Print the app configuration for the current package',
execute: async ({ args, info }) => {
const argv = await yargs
.options({
package: { type: 'string' },
lax: { type: 'boolean' },
frontend: { type: 'boolean' },
'with-secrets': { type: 'boolean' },
format: { type: 'string' },
config: { type: 'string', array: true, default: [] },
})
.usage('$0', info.description)
.help()
.parse(args);
const m =
(await require('./commands/print')) as typeof import('./commands/print');
await m.default(argv);
},
});
reg.addCommand({
path: ['config:check'],
description:
'Validate that the given configuration loads and matches schema',
execute: async ({ args }) => {
const argv = await yargs
.options({
package: { type: 'string' },
lax: { type: 'boolean' },
frontend: { type: 'boolean' },
deprecated: { type: 'boolean' },
strict: { type: 'boolean', required: true },
config: {
type: 'string',
array: true,
default: [],
},
})
.help()
.parse(args);
const m =
(await require('./commands/validate')) as typeof import('./commands/validate');
await m.default(argv);
},
});
reg.addCommand({
path: ['config:schema'],
description: 'Print the JSON schema for the given configuration',
execute: async ({ args }) => {
const argv = await yargs
.options({
package: { type: 'string' },
format: { type: 'string' },
merge: { type: 'boolean' },
'no-merge': { type: 'boolean' },
})
.help()
.parse(args);
const m = await import('./commands/schema');
await m.default(argv);
},
});
reg.addCommand({
path: ['config', 'schema'],
description: 'Print the JSON schema for the given configuration',
execute: async ({ args }) => {
const argv = await yargs
.options({
package: { type: 'string' },
format: { type: 'string' },
merge: { type: 'boolean' },
'no-merge': { type: 'boolean' },
})
.help()
.parse(args);
const m = await import('./commands/schema');
await m.default(argv);
},
});
},
});
+116 -59
View File
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createCliPlugin } from '../../wiring/factory';
import yargs from 'yargs';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
@@ -24,64 +25,120 @@ export const configOption = [
Array<string>(),
] as const;
export function registerCommands(program: Command) {
program
.command('config:docs')
.option(
'--package <name>',
'Only include the schema that applies to the given package',
)
.description('Browse the configuration reference documentation')
.action(lazy(() => import('./commands/docs'), 'default'));
export default createCliPlugin({
pluginId: 'config',
init: async reg => {
reg.addCommand({
path: ['config:docs'],
description: 'Browse the configuration reference documentation',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--package <name>',
'Only include the schema that applies to the given package',
)
.description('Browse the configuration reference documentation')
.action(lazy(() => import('./commands/docs'), 'default'));
program
.command('config:print')
.option(
'--package <name>',
'Only load config schema that applies to the given package',
)
.option('--lax', 'Do not require environment variables to be set')
.option('--frontend', 'Print only the frontend configuration')
.option('--with-secrets', 'Include secrets in the printed configuration')
.option(
'--format <format>',
'Format to print the configuration in, either json or yaml [yaml]',
)
.option(...configOption)
.description('Print the app configuration for the current package')
.action(lazy(() => import('./commands/print'), 'default'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['config', 'docs'],
description: 'Browse the configuration reference documentation',
execute: async ({ args, info }) => {
await new Command(info.usage)
.option(
'--package <name>',
'Only include the schema that applies to the given package',
)
.description(info.description)
.action(lazy(() => import('./commands/docs'), 'default'))
.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['config:print'],
description: 'Print the app configuration for the current package',
execute: async ({ args, info }) => {
const argv = await yargs
.options({
package: { type: 'string' },
lax: { type: 'boolean' },
frontend: { type: 'boolean' },
'with-secrets': { type: 'boolean' },
format: { type: 'string' },
config: { type: 'string', array: true, default: [] },
})
.usage('$0', info.description)
.help()
.parse(args);
const m =
(await require('./commands/print')) as typeof import('./commands/print');
await m.default(argv);
},
});
reg.addCommand({
path: ['config:check'],
description:
'Validate that the given configuration loads and matches schema',
execute: async ({ args }) => {
const argv = await yargs
.options({
package: { type: 'string' },
lax: { type: 'boolean' },
frontend: { type: 'boolean' },
deprecated: { type: 'boolean' },
strict: { type: 'boolean' },
config: {
type: 'string',
array: true,
default: [],
},
})
.help()
.parse(args);
const m =
(await require('./commands/validate')) as typeof import('./commands/validate');
await m.default(argv);
},
});
program
.command('config:check')
.option(
'--package <name>',
'Only load config schema that applies to the given package',
)
.option('--lax', 'Do not require environment variables to be set')
.option('--frontend', 'Only validate the frontend configuration')
.option('--deprecated', 'Output deprecated configuration settings')
.option(
'--strict',
'Enable strict config validation, forbidding errors and unknown keys',
)
.option(...configOption)
.description(
'Validate that the given configuration loads and matches schema',
)
.action(lazy(() => import('./commands/validate'), 'default'));
reg.addCommand({
path: ['config:schema'],
description: 'Print the JSON schema for the given configuration',
execute: async ({ args }) => {
const argv = await yargs
.options({
package: { type: 'string' },
format: { type: 'string' },
merge: { type: 'boolean' },
'no-merge': { type: 'boolean' },
})
.help()
.parse(args);
const m = await import('./commands/schema');
await m.default(argv);
},
});
program
.command('config:schema')
.option(
'--package <name>',
'Only output config schema that applies to the given package',
)
.option(
'--format <format>',
'Format to print the schema in, either json or yaml [yaml]',
)
.option('--merge', 'Print the config schemas merged', true)
.option('--no-merge', 'Print the config schemas not merged')
.description('Print configuration schema')
.action(lazy(() => import('./commands/schema'), 'default'));
}
reg.addCommand({
path: ['config', 'schema'],
description: 'Print the JSON schema for the given configuration',
execute: async ({ args }) => {
const argv = await yargs
.options({
package: { type: 'string' },
format: { type: 'string' },
merge: { type: 'boolean' },
'no-merge': { type: 'boolean' },
})
.help()
.parse(args);
const m = await import('./commands/schema');
await m.default(argv);
},
});
},
});
@@ -1,38 +0,0 @@
/*
* Copyright 2025 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 { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export default createCliPlugin({
pluginId: 'new',
init: async reg => {
reg.addCommand({
path: ['create-github-app'],
description: 'Create new GitHub App in your organization.',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.argument('<github-org>')
.action(
lazy(() => import('./commands/create-github-app'), 'default'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
},
});
@@ -13,17 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export function registerCommands(program: Command) {
program
.command('create-github-app <github-org>')
.description('Create new GitHub App in your organization.')
.action(
lazy(
() => import('../create-github-app/commands/create-github-app'),
'default',
),
);
}
export default createCliPlugin({
pluginId: 'new',
init: async reg => {
reg.addCommand({
path: ['create-github-app'],
description: 'Create new GitHub App in your organization.',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.argument('<github-org>')
.action(
lazy(() => import('./commands/create-github-app'), 'default'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
},
});
-33
View File
@@ -1,33 +0,0 @@
/*
* 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 yargs from 'yargs';
import { createCliPlugin } from '../../wiring/factory';
export default createCliPlugin({
pluginId: 'info',
init: async reg => {
reg.addCommand({
path: ['info'],
description: 'Show helpful information for debugging and reporting bugs',
execute: async ({ args }) => {
yargs().parse(args);
const { default: command } =
require('./commands/info') as typeof import('./commands/info');
await command();
},
});
},
});
+18 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* 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.
@@ -13,13 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import yargs from 'yargs';
import { createCliPlugin } from '../../wiring/factory';
import { lazy } from '../../lib/lazy';
import { Command } from 'commander';
export function registerCommands(program: Command) {
program
.command('info')
.description('Show helpful information for debugging and reporting bugs')
.action(lazy(() => import('./commands/info'), 'default'));
}
export default createCliPlugin({
pluginId: 'info',
init: async reg => {
reg.addCommand({
path: ['info'],
description: 'Show helpful information for debugging and reporting bugs',
execute: async ({ args }) => {
yargs().parse(args);
const { default: command } =
require('./commands/info') as typeof import('./commands/info');
await command();
},
});
},
});
-90
View File
@@ -1,90 +0,0 @@
/*
* Copyright 2025 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 { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export default createCliPlugin({
pluginId: 'lint',
init: async reg => {
reg.addCommand({
path: ['package', 'lint'],
description: 'Lint a package',
execute: async ({ args }) => {
const command = new Command();
command.arguments('[directories...]');
command.option('--fix', 'Attempt to automatically fix violations');
command.option(
'--format <format>',
'Lint report output format',
'eslint-formatter-friendly',
);
command.option(
'--output-file <path>',
'Write the lint report to a file instead of stdout',
);
command.option(
'--max-warnings <number>',
'Fail if more than this number of warnings. -1 allows warnings. (default: -1)',
);
command.description('Lint a package');
command.action(
lazy(() => import('./commands/package/lint'), 'default'),
);
await command.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'lint'],
description: 'Lint a repository',
execute: async ({ args }) => {
const command = new Command();
command.option('--fix', 'Attempt to automatically fix violations');
command.option(
'--format <format>',
'Lint report output format',
'eslint-formatter-friendly',
);
command.option(
'--output-file <path>',
'Write the lint report to a file instead of stdout',
);
command.option(
'--successCache',
'Enable success caching, which skips running tests for unchanged packages that were successful in the previous run',
);
command.option(
'--successCacheDir <path>',
'Set the success cache location, (default: node_modules/.cache/backstage-cli)',
);
command.option(
'--since <ref>',
'Only lint packages that changed since the specified ref',
);
command.option(
'--max-warnings <number>',
'Fail if more than this number of warnings. -1 allows warnings. (default: -1)',
);
command.description('Lint a repository');
command.action(lazy(() => import('./commands/repo/lint'), 'command'));
await command.parseAsync(args, { from: 'user' });
},
});
},
});
+75 -51
View File
@@ -13,59 +13,83 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export function registerPackageCommands(command: Command) {
command
.command('lint [directories...]')
.option(
'--format <format>',
'Lint report output format',
'eslint-formatter-friendly',
)
.option(
'--output-file <path>',
'Write the lint report to a file instead of stdout',
)
.option('--fix', 'Attempt to automatically fix violations')
.option(
'--max-warnings <number>',
'Fail if more than this number of warnings. -1 allows warnings. (default: -1)',
)
.description('Lint a package')
.action(lazy(() => import('./commands/package/lint'), 'default'));
export function registerPackageLintCommand(command: Command) {
command.arguments('[directories...]');
command.option('--fix', 'Attempt to automatically fix violations');
command.option(
'--format <format>',
'Lint report output format',
'eslint-formatter-friendly',
);
command.option(
'--output-file <path>',
'Write the lint report to a file instead of stdout',
);
command.option(
'--max-warnings <number>',
'Fail if more than this number of warnings. -1 allows warnings. (default: -1)',
);
command.description('Lint a package');
command.action(lazy(() => import('./commands/package/lint'), 'default'));
}
export function registerRepoCommands(command: Command) {
command
.command('lint')
.description('Lint all packages in the project')
.option(
'--format <format>',
'Lint report output format',
'eslint-formatter-friendly',
)
.option(
'--output-file <path>',
'Write the lint report to a file instead of stdout',
)
.option(
'--since <ref>',
'Only lint packages that changed since the specified ref',
)
.option(
'--successCache',
'Enable success caching, which skips running tests for unchanged packages that were successful in the previous run',
)
.option(
'--successCacheDir <path>',
'Set the success cache location, (default: node_modules/.cache/backstage-cli)',
)
.option(
'--max-warnings <number>',
'Fail if more than this number of warnings. -1 allows warnings. (default: -1)',
)
.option('--fix', 'Attempt to automatically fix violations')
.action(lazy(() => import('./commands/repo/lint'), 'command'));
}
export default createCliPlugin({
pluginId: 'lint',
init: async reg => {
reg.addCommand({
path: ['package', 'lint'],
description: 'Lint a package',
execute: async ({ args }) => {
const command = new Command();
registerPackageLintCommand(command);
await command.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'lint'],
description: 'Lint a repository',
execute: async ({ args }) => {
const command = new Command();
registerPackageLintCommand(command.command('package').command('lint'));
command.option('--fix', 'Attempt to automatically fix violations');
command.option(
'--format <format>',
'Lint report output format',
'eslint-formatter-friendly',
);
command.option(
'--output-file <path>',
'Write the lint report to a file instead of stdout',
);
command.option(
'--successCache',
'Enable success caching, which skips running tests for unchanged packages that were successful in the previous run',
);
command.option(
'--successCacheDir <path>',
'Set the success cache location, (default: node_modules/.cache/backstage-cli)',
);
command.option(
'--since <ref>',
'Only lint packages that changed since the specified ref',
);
command.option(
'--max-warnings <number>',
'Fail if more than this number of warnings. -1 allows warnings. (default: -1)',
);
command.description('Lint a repository');
command.action(lazy(() => import('./commands/repo/lint'), 'command'));
await command.parseAsync(args, { from: 'user' });
},
});
},
});
@@ -1,110 +0,0 @@
/*
* Copyright 2025 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';
import { createCliPlugin } from '../../wiring/factory';
import { lazy } from '../../lib/lazy';
export default createCliPlugin({
pluginId: 'maintenance',
init: async reg => {
reg.addCommand({
path: ['package', 'clean'],
description: 'Delete cache directories',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/package/clean'), 'default'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['package', 'prepack'],
description: 'Prepares a package for packaging before publishing',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/package/pack'), 'pre'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['package', 'postpack'],
description: 'Restores the changes made by the prepack command',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/package/pack'), 'post'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'fix'],
description: 'Automatically fix packages in the project',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--publish',
'Enable additional fixes that only apply when publishing packages',
)
.option(
'--check',
'Fail if any packages would have been changed by the command',
)
.action(lazy(() => import('./commands/repo/fix'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'clean'],
description: 'Delete cache and output directories',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/repo/clean'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'list-deprecations'],
description: 'List deprecations',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option('--json', 'Output as JSON')
.action(
lazy(() => import('./commands/repo/list-deprecations'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
},
});
+87 -38
View File
@@ -13,49 +13,98 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Command } from 'commander';
import { createCliPlugin } from '../../wiring/factory';
import { lazy } from '../../lib/lazy';
export function registerPackageCommands(command: Command) {
command
.command('clean')
.description('Delete cache directories')
.action(lazy(() => import('./commands/package/clean'), 'default'));
export default createCliPlugin({
pluginId: 'maintenance',
init: async reg => {
reg.addCommand({
path: ['package', 'clean'],
description: 'Delete cache directories',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/package/clean'), 'default'),
);
command
.command('prepack')
.description('Prepares a package for packaging before publishing')
.action(lazy(() => import('./commands/package/pack'), 'pre'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
command
.command('postpack')
.description('Restores the changes made by the prepack command')
.action(lazy(() => import('./commands/package/pack'), 'post'));
}
reg.addCommand({
path: ['package', 'prepack'],
description: 'Prepares a package for packaging before publishing',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/package/pack'), 'pre'),
);
export function registerRepoCommands(command: Command) {
command
.command('fix')
.description('Automatically fix packages in the project')
.option(
'--publish',
'Enable additional fixes that only apply when publishing packages',
)
.option(
'--check',
'Fail if any packages would have been changed by the command',
)
.action(lazy(() => import('./commands/repo/fix'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
command
.command('clean')
.description('Delete cache and output directories')
.action(lazy(() => import('./commands/repo/clean'), 'command'));
reg.addCommand({
path: ['package', 'postpack'],
description: 'Restores the changes made by the prepack command',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/package/pack'), 'post'),
);
command
.command('list-deprecations')
.description('List deprecations')
.option('--json', 'Output as JSON')
.action(lazy(() => import('./commands/repo/list-deprecations'), 'command'));
}
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'fix'],
description: 'Automatically fix packages in the project',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--publish',
'Enable additional fixes that only apply when publishing packages',
)
.option(
'--check',
'Fail if any packages would have been changed by the command',
)
.action(lazy(() => import('./commands/repo/fix'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'clean'],
description: 'Delete cache and output directories',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/repo/clean'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['repo', 'list-deprecations'],
description: 'List deprecations',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option('--json', 'Output as JSON')
.action(
lazy(() => import('./commands/repo/list-deprecations'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
},
});
-135
View File
@@ -1,135 +0,0 @@
/*
* 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 { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export default createCliPlugin({
pluginId: 'migrate',
init: async reg => {
reg.addCommand({
path: ['versions:migrate'],
description:
'Migrate any plugins that have been moved to the @backstage-community namespace automatically',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--pattern <glob>',
'Override glob for matching packages to upgrade',
)
.option(
'--skip-code-changes',
'Skip code changes and only update package.json files',
)
.action(lazy(() => import('./commands/versions/migrate'), 'default'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['versions:bump'],
description: 'Bump Backstage packages to the latest versions',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--pattern <glob>',
'Override glob for matching packages to upgrade',
)
.option(
'--release <version|next|main>',
'Bump to a specific Backstage release line or version',
'main',
)
.option('--skip-install', 'Skips yarn install step')
.option('--skip-migrate', 'Skips migration of any moved packages')
.action(lazy(() => import('./commands/versions/bump'), 'default'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['migrate', 'package-roles'],
description: `Add package role field to packages that don't have it`,
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/packageRole'), 'default'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['migrate', 'package-scripts'],
description: 'Set package scripts according to each package role',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/packageScripts'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['migrate', 'package-exports'],
description: 'Synchronize package subpath export definitions',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/packageExports'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['migrate', 'package-lint-configs'],
description:
'Migrates all packages to use @backstage/cli/config/eslint-factory',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/packageLintConfigs'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['migrate', 'react-router-deps'],
description:
'Migrates the react-router dependencies for all packages to be peer dependencies',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/reactRouterDeps'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
},
});
+112 -61
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2025 The Backstage Authors
* 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.
@@ -13,72 +13,123 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { lazy } from '../../lib/lazy';
import { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export function registerCommands(program: Command) {
program
.command('versions:bump')
.option(
'--pattern <glob>',
'Override glob for matching packages to upgrade',
)
.option(
'--release <version|next|main>',
'Bump to a specific Backstage release line or version',
'main',
)
.option('--skip-install', 'Skips yarn install step')
.option('--skip-migrate', 'Skips migration of any moved packages')
.description('Bump Backstage packages to the latest versions')
.action(lazy(() => import('./commands/versions/bump'), 'default'));
export default createCliPlugin({
pluginId: 'migrate',
init: async reg => {
reg.addCommand({
path: ['versions:migrate'],
description:
'Migrate any plugins that have been moved to the @backstage-community namespace automatically',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.option(
'--pattern <glob>',
'Override glob for matching packages to upgrade',
)
.option(
'--skip-code-changes',
'Skip code changes and only update package.json files',
)
.action(lazy(() => import('./commands/versions/migrate'), 'default'));
program
.command('versions:migrate')
.option(
'--pattern <glob>',
'Override glob for matching packages to upgrade',
)
.option(
'--skip-code-changes',
'Skip code changes and only update package.json files',
)
.description(
'Migrate any plugins that have been moved to the @backstage-community namespace automatically',
)
.action(lazy(() => import('./commands/versions/migrate'), 'default'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
const command = program
.command('migrate [command]')
.description('Migration utilities');
reg.addCommand({
path: ['versions:bump'],
description: 'Bump Backstage packages to the latest versions',
execute: async ({ args }) => {
const command = new Command();
command
.command('package-roles')
.description(`Add package role field to packages that don't have it`)
.action(lazy(() => import('./commands/packageRole'), 'default'));
const defaultCommand = command
.option(
'--pattern <glob>',
'Override glob for matching packages to upgrade',
)
.option(
'--release <version|next|main>',
'Bump to a specific Backstage release line or version',
'main',
)
.option('--skip-install', 'Skips yarn install step')
.option('--skip-migrate', 'Skips migration of any moved packages')
.action(lazy(() => import('./commands/versions/bump'), 'default'));
command
.command('package-scripts')
.description('Set package scripts according to each package role')
.action(lazy(() => import('./commands/packageScripts'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
command
.command('package-exports')
.description('Synchronize package subpath export definitions')
.action(lazy(() => import('./commands/packageExports'), 'command'));
reg.addCommand({
path: ['migrate', 'package-roles'],
description: `Add package role field to packages that don't have it`,
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/packageRole'), 'default'),
);
command
.command('package-lint-configs')
.description(
'Migrates all packages to use @backstage/cli/config/eslint-factory',
)
.action(lazy(() => import('./commands/packageLintConfigs'), 'command'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
command
.command('react-router-deps')
.description(
'Migrates the react-router dependencies for all packages to be peer dependencies',
)
.action(lazy(() => import('./commands/reactRouterDeps'), 'command'));
}
reg.addCommand({
path: ['migrate', 'package-scripts'],
description: 'Set package scripts according to each package role',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/packageScripts'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['migrate', 'package-exports'],
description: 'Synchronize package subpath export definitions',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/packageExports'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['migrate', 'package-lint-configs'],
description:
'Migrates all packages to use @backstage/cli/config/eslint-factory',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/packageLintConfigs'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['migrate', 'react-router-deps'],
description:
'Migrates the react-router dependencies for all packages to be peer dependencies',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command.action(
lazy(() => import('./commands/reactRouterDeps'), 'command'),
);
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
},
});
-86
View File
@@ -1,86 +0,0 @@
/*
* Copyright 2025 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 { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
import { removed } from '../../lib/removed';
export default createCliPlugin({
pluginId: 'new',
init: async reg => {
reg.addCommand({
path: ['new'],
description:
'Open up an interactive guide to creating new things in your app',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.storeOptionsAsProperties(false)
.description(
'Open up an interactive guide to creating new things in your app',
)
.option(
'--select <name>',
'Select the thing you want to be creating upfront',
)
.option(
'--option <name>=<value>',
'Pre-fill options for the creation process',
(opt, arr: string[]) => [...arr, opt],
[],
)
.option(
'--skip-install',
`Skips running 'yarn install' and 'yarn lint --fix'`,
)
.option('--scope <scope>', 'The scope to use for new packages')
.option(
'--npm-registry <URL>',
'The package registry to use for new packages',
)
.option(
'--baseVersion <version>',
'The version to use for any new packages (default: 0.1.0)',
)
.option(
'--license <license>',
'The license to use for any new packages (default: Apache-2.0)',
)
.option('--no-private', 'Do not mark new packages as private')
.action(lazy(() => import('./commands/new'), 'default'));
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['create'],
description: 'Create a new Backstage app',
deprecated: true,
execute: async () => {
removed("use 'backstage-cli new' instead")();
},
});
reg.addCommand({
path: ['create-plugin'],
description: 'Create a new Backstage plugin',
deprecated: true,
execute: async () => {
removed("use 'backstage-cli new' instead")();
},
});
},
});
+66 -45
View File
@@ -13,53 +13,74 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
import { removed } from '../../lib/removed';
export function registerCommands(program: Command) {
program
.command('new')
.storeOptionsAsProperties(false)
.description(
'Open up an interactive guide to creating new things in your app',
)
.option(
'--select <name>',
'Select the thing you want to be creating upfront',
)
.option(
'--option <name>=<value>',
'Pre-fill options for the creation process',
(opt, arr: string[]) => [...arr, opt],
[],
)
.option(
'--skip-install',
`Skips running 'yarn install' and 'yarn lint --fix'`,
)
.option('--scope <scope>', 'The scope to use for new packages')
.option(
'--npm-registry <URL>',
'The package registry to use for new packages',
)
.option(
'--baseVersion <version>',
'The version to use for any new packages (default: 0.1.0)',
)
.option(
'--license <license>',
'The license to use for any new packages (default: Apache-2.0)',
)
.option('--no-private', 'Do not mark new packages as private')
.action(lazy(() => import('./commands/new'), 'default'));
export default createCliPlugin({
pluginId: 'new',
init: async reg => {
reg.addCommand({
path: ['new'],
description:
'Open up an interactive guide to creating new things in your app',
execute: async ({ args }) => {
const command = new Command();
const defaultCommand = command
.storeOptionsAsProperties(false)
.description(
'Open up an interactive guide to creating new things in your app',
)
.option(
'--select <name>',
'Select the thing you want to be creating upfront',
)
.option(
'--option <name>=<value>',
'Pre-fill options for the creation process',
(opt, arr: string[]) => [...arr, opt],
[],
)
.option(
'--skip-install',
`Skips running 'yarn install' and 'yarn lint --fix'`,
)
.option('--scope <scope>', 'The scope to use for new packages')
.option(
'--npm-registry <URL>',
'The package registry to use for new packages',
)
.option(
'--baseVersion <version>',
'The version to use for any new packages (default: 0.1.0)',
)
.option(
'--license <license>',
'The license to use for any new packages (default: Apache-2.0)',
)
.option('--no-private', 'Do not mark new packages as private')
.action(lazy(() => import('./commands/new'), 'default'));
program
.command('create')
.allowUnknownOption(true)
.action(removed("use 'backstage-cli new' instead"));
program
.command('create-plugin')
.allowUnknownOption(true)
.action(removed("use 'backstage-cli new' instead"));
}
await defaultCommand.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['create'],
description: 'Create a new Backstage app',
deprecated: true,
execute: async () => {
removed("use 'backstage-cli new' instead")();
},
});
reg.addCommand({
path: ['create-plugin'],
description: 'Create a new Backstage plugin',
deprecated: true,
execute: async () => {
removed("use 'backstage-cli new' instead")();
},
});
},
});
-64
View File
@@ -1,64 +0,0 @@
/*
* 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 { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export default createCliPlugin({
pluginId: 'test',
init: async reg => {
reg.addCommand({
path: ['repo', 'test'],
description:
'Run tests, forwarding args to Jest, defaulting to watch mode',
execute: async ({ args }) => {
const command = new Command();
command.allowUnknownOption(true);
command.option(
'--since <ref>',
'Only test packages that changed since the specified ref',
);
command.option('--successCache', 'Enable success caching');
command.option(
'--successCacheDir <path>',
'Set the success cache location, (default: node_modules/.cache/backstage-cli)',
);
command.option(
'--jest-help',
'Show help for Jest CLI options, which are passed through',
);
command.action(lazy(() => import('./commands/repo/test'), 'command'));
await command.parseAsync(args, { from: 'user' });
},
});
reg.addCommand({
path: ['package', 'test'],
description:
'Run tests, forwarding args to Jest, defaulting to watch mode',
execute: async ({ args }) => {
const command = new Command();
command.allowUnknownOption(true);
command.helpOption(', --backstage-cli-help');
command.action(
lazy(() => import('./commands/package/test'), 'default'),
);
await command.parseAsync(args, { from: 'user' });
},
});
},
});
+46 -33
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2025 The Backstage Authors
* 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.
@@ -13,39 +13,52 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createCliPlugin } from '../../wiring/factory';
import { Command } from 'commander';
import { lazy } from '../../lib/lazy';
export function registerRepoCommands(command: Command) {
command
.command('test')
.allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args
.option(
'--since <ref>',
'Only test packages that changed since the specified ref',
)
.option(
'--successCache',
'Enable success caching, which skips running tests for unchanged packages that were successful in the previous run',
)
.option(
'--successCacheDir <path>',
'Set the success cache location, (default: node_modules/.cache/backstage-cli)',
)
.option(
'--jest-help',
'Show help for Jest CLI options, which are passed through',
)
.description('Run tests, forwarding args to Jest, defaulting to watch mode')
.action(lazy(() => import('./commands/repo/test'), 'command'));
}
export default createCliPlugin({
pluginId: 'test',
init: async reg => {
reg.addCommand({
path: ['repo', 'test'],
description:
'Run tests, forwarding args to Jest, defaulting to watch mode',
execute: async ({ args }) => {
const command = new Command();
command.allowUnknownOption(true);
command.option(
'--since <ref>',
'Only test packages that changed since the specified ref',
);
command.option('--successCache', 'Enable success caching');
command.option(
'--successCacheDir <path>',
'Set the success cache location, (default: node_modules/.cache/backstage-cli)',
);
command.option(
'--jest-help',
'Show help for Jest CLI options, which are passed through',
);
command.action(lazy(() => import('./commands/repo/test'), 'command'));
await command.parseAsync(args, { from: 'user' });
},
});
export function registerPackageCommands(command: Command) {
command
.command('test')
.allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args
.helpOption(', --backstage-cli-help') // Let Jest handle help
.description('Run tests, forwarding args to Jest, defaulting to watch mode')
.action(lazy(() => import('./commands/package/test'), 'default'));
}
reg.addCommand({
path: ['package', 'test'],
description:
'Run tests, forwarding args to Jest, defaulting to watch mode',
execute: async ({ args }) => {
const command = new Command();
command.allowUnknownOption(true);
command.helpOption(', --backstage-cli-help');
command.action(
lazy(() => import('./commands/package/test'), 'default'),
);
await command.parseAsync(args, { from: 'user' });
},
});
},
});
-1
View File
@@ -4078,7 +4078,6 @@ __metadata:
optional: true
bin:
backstage-cli: bin/backstage-cli
backstage-cli-alpha: bin/backstage-cli-alpha
languageName: unknown
linkType: soft