cli: load config schema and use to filter config + add --frontend flag to print

This commit is contained in:
Patrik Oldsberg
2020-11-08 16:10:39 +01:00
parent 7298f8b265
commit 564f438edd
8 changed files with 64 additions and 19 deletions
+1
View File
@@ -76,6 +76,7 @@
"jest": "^26.0.1",
"jest-css-modules": "^2.1.0",
"jest-esm-transformer": "^1.0.0",
"lodash": "^4.17.19",
"mini-css-extract-plugin": "^0.9.0",
"ora": "^4.0.3",
"raw-loader": "^4.0.1",
+31 -4
View File
@@ -16,16 +16,43 @@
import { Command } from 'commander';
import { stringify as stringifyYaml } from 'yaml';
import { ConfigReader } from '@backstage/config';
import { loadCliConfig } from '../../lib/config';
import cloneDeepWith from 'lodash/cloneDeepWith';
export default async (cmd: Command) => {
const { config } = await loadCliConfig(cmd.config, cmd.withSecrets ?? false);
const { schema, appConfigs } = await loadCliConfig(cmd.config);
let data;
const flatConfig = config.get();
if (cmd.frontend) {
const frontendConfigs = schema.process(appConfigs, {
visibilities: ['frontend'],
});
data = ConfigReader.fromConfigs(frontendConfigs).get();
} else if (cmd.withSecrets) {
data = ConfigReader.fromConfigs(appConfigs).get();
} else {
let secretConfigs = schema.process(appConfigs, {
visibilities: ['secret'],
});
secretConfigs = secretConfigs.map(entry => ({
context: entry.context,
data: cloneDeepWith(entry.data, value => {
console.log('DEBUG: value =', value);
if (typeof value !== 'object') {
return '<secret>';
}
return undefined;
}),
}));
data = ConfigReader.fromConfigs(appConfigs.concat(secretConfigs)).get();
}
if (cmd.format === 'json') {
process.stdout.write(`${JSON.stringify(flatConfig, null, 2)}\n`);
process.stdout.write(`${JSON.stringify(data, null, 2)}\n`);
} else {
process.stdout.write(`${stringifyYaml(flatConfig)}\n`);
process.stdout.write(`${stringifyYaml(data)}\n`);
}
};
+1
View File
@@ -136,6 +136,7 @@ export function registerCommands(program: CommanderStatic) {
program
.command('config:print')
.option('--frontend', 'Print only the frontend configuration')
.option('--with-secrets', 'Include secrets in the printed configuration')
.option(
'--format <format>',
+1 -1
View File
@@ -40,7 +40,7 @@ export async function buildBundle(options: BuildOptions) {
...options,
checksEnabled: false,
isDev: false,
baseUrl: resolveBaseUrl(options.config),
baseUrl: resolveBaseUrl(options.frontendConfig),
});
const compiler = webpack(config);
+5 -5
View File
@@ -74,11 +74,11 @@ export async function createConfig(
paths: BundlingPaths,
options: BundlingOptions,
): Promise<webpack.Configuration> {
const { checksEnabled, isDev } = options;
const { checksEnabled, isDev, frontendConfig } = options;
const { plugins, loaders } = transforms(options);
const baseUrl = options.config.getString('app.baseUrl');
const baseUrl = frontendConfig.getString('app.baseUrl');
const validBaseUrl = new URL(baseUrl);
if (checksEnabled) {
@@ -99,7 +99,7 @@ export async function createConfig(
plugins.push(
new webpack.EnvironmentPlugin({
APP_CONFIG: options.appConfigs,
APP_CONFIG: options.frontendAppConfigs,
}),
);
@@ -109,9 +109,9 @@ export async function createConfig(
templateParameters: {
publicPath: validBaseUrl.pathname.replace(/\/$/, ''),
app: {
title: options.config.getString('app.title'),
title: frontendConfig.getString('app.title'),
baseUrl: validBaseUrl.href,
googleAnalyticsTrackingId: options.config.getOptionalString(
googleAnalyticsTrackingId: frontendConfig.getOptionalString(
'app.googleAnalyticsTrackingId',
),
},
+1 -1
View File
@@ -23,7 +23,7 @@ import { ServeOptions } from './types';
import { resolveBundlingPaths } from './paths';
export async function serveBundle(options: ServeOptions) {
const url = resolveBaseUrl(options.config);
const url = resolveBaseUrl(options.frontendConfig);
const host =
options.config.getOptionalString('app.listen.host') || url.hostname;
+6 -6
View File
@@ -21,23 +21,23 @@ import { ParallelOption } from '../parallel';
export type BundlingOptions = {
checksEnabled: boolean;
isDev: boolean;
config: Config;
appConfigs: AppConfig[];
frontendConfig: Config;
frontendAppConfigs: AppConfig[];
baseUrl: URL;
parallel?: ParallelOption;
};
export type ServeOptions = BundlingPathsOptions & {
checksEnabled: boolean;
config: Config;
appConfigs: AppConfig[];
frontendConfig: Config;
frontendAppConfigs: AppConfig[];
};
export type BuildOptions = BundlingPathsOptions & {
statsJsonEnabled: boolean;
parallel?: ParallelOption;
config: Config;
appConfigs: AppConfig[];
frontendConfig: Config;
frontendAppConfigs: AppConfig[];
};
export type BackendBundlingOptions = {
+18 -2
View File
@@ -14,13 +14,22 @@
* limitations under the License.
*/
import { loadConfig } from '@backstage/config-loader';
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));
// 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 schema = await loadConfigSchema({
dependencies: localPackageNames,
});
const appConfigs = await loadConfig({
env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'production',
configRoot: paths.targetRoot,
@@ -31,8 +40,15 @@ export async function loadCliConfig(configArgs: string[]) {
`Loaded config from ${appConfigs.map(c => c.context).join(', ')}`,
);
const frontendAppConfigs = schema.process(appConfigs, {
visibilities: ['frontend'],
});
const frontendConfig = ConfigReader.fromConfigs(frontendAppConfigs);
return {
schema,
appConfigs,
config: ConfigReader.fromConfigs(appConfigs),
frontendConfig,
frontendAppConfigs,
};
}