cli: only load config schema that applies to the target package

This commit is contained in:
Patrik Oldsberg
2020-11-26 22:18:47 +01:00
parent 8697dea5b4
commit 2942954535
8 changed files with 85 additions and 8 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Only load config that applies to the target package for frontend build and serve tasks. Also added `--package <name>` flag to scope the config schema used by the `config:print` and `config:check` commands.
+7 -1
View File
@@ -14,16 +14,22 @@
* limitations under the License.
*/
import fs from 'fs-extra';
import { Command } from 'commander';
import { buildBundle } from '../../lib/bundler';
import { parseParallel, PARALLEL_ENV_VAR } from '../../lib/parallel';
import { loadCliConfig } from '../../lib/config';
import { paths } from '../../lib/paths';
export default async (cmd: Command) => {
const { name } = await fs.readJson(paths.resolveTarget('package.json'));
await buildBundle({
entry: 'src/index',
parallel: parseParallel(process.env[PARALLEL_ENV_VAR]),
statsJsonEnabled: cmd.stats,
...(await loadCliConfig(cmd.config)),
...(await loadCliConfig({
args: cmd.config,
fromPackage: name,
})),
});
};
+7 -1
View File
@@ -14,15 +14,21 @@
* limitations under the License.
*/
import fs from 'fs-extra';
import { Command } from 'commander';
import { serveBundle } from '../../lib/bundler';
import { loadCliConfig } from '../../lib/config';
import { paths } from '../../lib/paths';
export default async (cmd: Command) => {
const { name } = await fs.readJson(paths.resolveTarget('package.json'));
const waitForExit = await serveBundle({
entry: 'src/index',
checksEnabled: cmd.check,
...(await loadCliConfig(cmd.config)),
...(await loadCliConfig({
args: cmd.config,
fromPackage: name,
})),
});
await waitForExit();
+4 -1
View File
@@ -21,7 +21,10 @@ import { loadCliConfig } from '../../lib/config';
import { ConfigSchema, ConfigVisibility } from '@backstage/config-loader';
export default async (cmd: Command) => {
const { schema, appConfigs } = await loadCliConfig(cmd.config);
const { schema, appConfigs } = await loadCliConfig({
args: cmd.config,
fromPackage: cmd.package,
});
const visibility = getVisiblityOption(cmd);
const data = serializeConfigData(appConfigs, schema, visibility);
+4 -1
View File
@@ -18,5 +18,8 @@ import { Command } from 'commander';
import { loadCliConfig } from '../../lib/config';
export default async (cmd: Command) => {
await loadCliConfig(cmd.config);
await loadCliConfig({
args: cmd.config,
fromPackage: cmd.package,
});
};
+8
View File
@@ -141,6 +141,10 @@ export function registerCommands(program: CommanderStatic) {
program
.command('config:print')
.option(
'--package <name>',
'Only load config schema that applies to the given package',
)
.option('--frontend', 'Print only the frontend configuration')
.option('--with-secrets', 'Include secrets in the printed configuration')
.option(
@@ -153,6 +157,10 @@ export function registerCommands(program: CommanderStatic) {
program
.command('config:check')
.option(
'--package <name>',
'Only load config schema that applies to the given package',
)
.option(...configOption)
.description(
'Validate that the given configuration loads and matches schema',
+7 -1
View File
@@ -14,15 +14,21 @@
* limitations under the License.
*/
import fs from 'fs-extra';
import { Command } from 'commander';
import { serveBundle } from '../../lib/bundler';
import { loadCliConfig } from '../../lib/config';
import { paths } from '../../lib/paths';
export default async (cmd: Command) => {
const { name } = await fs.readJson(paths.resolveTarget('package.json'));
const waitForExit = await serveBundle({
entry: 'dev/index',
checksEnabled: cmd.check,
...(await loadCliConfig(cmd.config)),
...(await loadCliConfig({
args: cmd.config,
fromPackage: name,
})),
});
await waitForExit();
+43 -3
View File
@@ -18,14 +18,23 @@ import { loadConfig, loadConfigSchema } from '@backstage/config-loader';
import { ConfigReader } from '@backstage/config';
import { paths } from './paths';
export async function loadCliConfig(configArgs: string[]) {
const configPaths = configArgs.map(arg => paths.resolveTarget(arg));
type Options = {
args: string[];
fromPackage?: string;
};
export async function loadCliConfig(options: Options) {
const configPaths = options.args.map(arg => paths.resolveTarget(arg));
// Consider all packages in the monorepo when loading in config
const LernaProject = require('@lerna/project');
const project = new LernaProject(paths.targetDir);
const packages = await project.getPackages();
const localPackageNames = packages.map((p: any) => p.name);
const localPackageNames = options.fromPackage
? findPackages(packages, options.fromPackage)
: packages.map((p: any) => p.name);
const schema = await loadConfigSchema({
dependencies: localPackageNames,
});
@@ -61,3 +70,34 @@ export async function loadCliConfig(configArgs: string[]) {
throw error;
}
}
function findPackages(packages: any[], fromPackage: string): string[] {
const PackageGraph = require('@lerna/package-graph');
const graph = new PackageGraph(packages);
const targets = new Set<string>();
const searchNames = [fromPackage];
while (searchNames.length) {
const name = searchNames.pop()!;
if (targets.has(name)) {
continue;
}
const node = graph.get(name);
if (!node) {
throw new Error(`Package '${name}' not found`);
}
targets.add(name);
// Workaround for Backstage main repo only, since the CLI has some artificial devDependencies
if (name !== '@backstage/cli') {
searchNames.push(...node.localDependencies.keys());
}
}
return Array.from(targets);
}