From 8c2b76e45fd930d755e3c4a48f31be237c14e77b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 20 Oct 2020 13:08:05 +0200 Subject: [PATCH 1/8] config-loader: switch to using --config options to load in config --- .changeset/dull-icons-share.md | 21 ++++ packages/backend-common/package.json | 2 + packages/backend-common/src/config.ts | 12 +- packages/backend/src/index.ts | 5 +- packages/cli/src/commands/app/build.ts | 16 +-- packages/cli/src/commands/app/serve.ts | 16 +-- packages/cli/src/commands/backend/dev.ts | 14 --- packages/cli/src/commands/config/print.ts | 17 +-- packages/cli/src/commands/index.ts | 18 ++- packages/cli/src/commands/plugin/export.ts | 16 +-- packages/cli/src/commands/plugin/serve.ts | 16 +-- packages/cli/src/lib/bundler/backend.ts | 8 +- packages/cli/src/lib/bundler/types.ts | 16 ++- packages/cli/src/lib/config.ts | 42 +++++++ packages/config-loader/src/lib/index.ts | 1 - .../config-loader/src/lib/resolver.test.ts | 119 ------------------ packages/config-loader/src/lib/resolver.ts | 59 --------- packages/config-loader/src/loader.test.ts | 38 +++++- packages/config-loader/src/loader.ts | 44 +++++-- .../default-app/packages/backend/src/index.ts | 2 +- .../src/service/standaloneServer.ts | 2 +- .../src/service/standaloneServer.ts | 2 +- .../proxy-backend/src/service/router.test.ts | 2 +- .../src/service/standaloneServer.ts | 2 +- .../src/service/standaloneServer.ts | 2 +- .../techdocs-backend/src/default-branch.ts | 5 +- yarn.lock | 5 + 27 files changed, 200 insertions(+), 302 deletions(-) create mode 100644 .changeset/dull-icons-share.md create mode 100644 packages/cli/src/lib/config.ts delete mode 100644 packages/config-loader/src/lib/resolver.test.ts delete mode 100644 packages/config-loader/src/lib/resolver.ts diff --git a/.changeset/dull-icons-share.md b/.changeset/dull-icons-share.md new file mode 100644 index 0000000000..aa4c01e422 --- /dev/null +++ b/.changeset/dull-icons-share.md @@ -0,0 +1,21 @@ +--- +'@backstage/backend-common': minor +'@backstage/cli': minor +'@backstage/config-loader': minor +'example-backend': patch +'@backstage/create-app': patch +--- + +**BREAKING CHANGE** + +The existing loading of additional config files like `app-config.development.yaml` using APP_ENV or NODE_ENV has been removed. +Instead, the CLI and backend process now accept one or more `--config` flags to load config files. + +Without passing any flags, `app-config.yaml` and, if it exists, `app-config.local.yaml` will be loaded. +If passing any `--config ` flags, only those files will be loaded, **NOT** the default `app-config.yaml` one. + +The old behaviour of for example `APP_ENV=development` can be replicated using the following flags: + +```bash +--config ../../app-config.yaml --config ../../app-config.development.yaml +``` diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 249fa9e72c..50880a1228 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -44,6 +44,7 @@ "knex": "^0.21.1", "lodash": "^4.17.15", "logform": "^2.1.1", + "minimist": "^1.2.5", "morgan": "^1.10.0", "node-fetch": "^2.6.0", "prom-client": "^12.0.0", @@ -63,6 +64,7 @@ "@backstage/cli": "^0.1.1-alpha.25", "@types/compression": "^1.7.0", "@types/http-errors": "^1.6.3", + "@types/minimist": "^1.2.0", "@types/morgan": "^1.9.0", "@types/node-fetch": "^2.5.7", "@types/stoppable": "^1.1.0", diff --git a/packages/backend-common/src/config.ts b/packages/backend-common/src/config.ts index c86793fc08..6223d3150b 100644 --- a/packages/backend-common/src/config.ts +++ b/packages/backend-common/src/config.ts @@ -14,24 +14,32 @@ * limitations under the License. */ +import { resolve as resolvePath } from 'path'; +import parseArgs from 'minimist'; +import { Logger } from 'winston'; import { findPaths } from '@backstage/cli-common'; import { Config, ConfigReader } from '@backstage/config'; import { loadConfig } from '@backstage/config-loader'; -import { Logger } from 'winston'; type Options = { logger: Logger; + // process.argv or any other overrides + argv: string[]; }; /** * Load configuration for a Backend */ export async function loadBackendConfig(options: Options): Promise { + const args = parseArgs(options.argv); + const configOpts: string[] = args.config ?? []; + /* eslint-disable-next-line no-restricted-syntax */ const paths = findPaths(__dirname); const configs = await loadConfig({ env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development', - rootPaths: [paths.targetRoot, paths.targetDir], + configRoot: paths.targetRoot, + configPaths: configOpts.map(opt => resolvePath(opt)), shouldReadSecrets: true, }); diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index cbeaf4315c..b74954ecc5 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -64,7 +64,10 @@ function makeCreateEnv(config: Config) { } async function main() { - const config = await loadBackendConfig({ logger: getRootLogger() }); + const config = await loadBackendConfig({ + argv: process.argv, + logger: getRootLogger(), + }); const createEnv = makeCreateEnv(config); const healthcheckEnv = useHotMemoize(module, () => createEnv('healthcheck')); diff --git a/packages/cli/src/commands/app/build.ts b/packages/cli/src/commands/app/build.ts index 5a9d2cdf3a..c5f5f5aa2f 100644 --- a/packages/cli/src/commands/app/build.ts +++ b/packages/cli/src/commands/app/build.ts @@ -15,27 +15,15 @@ */ import { Command } from 'commander'; -import { loadConfig } from '@backstage/config-loader'; -import { ConfigReader } from '@backstage/config'; -import { paths } from '../../lib/paths'; import { buildBundle } from '../../lib/bundler'; import { parseParallel, PARALLEL_ENV_VAR } from '../../lib/parallel'; +import { loadCliConfig } from '../../lib/config'; export default async (cmd: Command) => { - const appConfigs = await loadConfig({ - env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'production', - rootPaths: [paths.targetRoot, paths.targetDir], - }); - - console.log( - `Loaded config from ${appConfigs.map(c => c.context).join(', ')}`, - ); - await buildBundle({ entry: 'src/index', parallel: parseParallel(process.env[PARALLEL_ENV_VAR]), statsJsonEnabled: cmd.stats, - config: ConfigReader.fromConfigs(appConfigs), - appConfigs, + ...(await loadCliConfig(cmd.config)), }); }; diff --git a/packages/cli/src/commands/app/serve.ts b/packages/cli/src/commands/app/serve.ts index 6524eb3acf..c3f58774b5 100644 --- a/packages/cli/src/commands/app/serve.ts +++ b/packages/cli/src/commands/app/serve.ts @@ -15,26 +15,14 @@ */ import { Command } from 'commander'; -import { loadConfig } from '@backstage/config-loader'; -import { ConfigReader } from '@backstage/config'; -import { paths } from '../../lib/paths'; import { serveBundle } from '../../lib/bundler'; +import { loadCliConfig } from '../../lib/config'; export default async (cmd: Command) => { - const appConfigs = await loadConfig({ - env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development', - rootPaths: [paths.targetRoot, paths.targetDir], - }); - - console.log( - `Loaded config from ${appConfigs.map(c => c.context).join(', ')}`, - ); - const waitForExit = await serveBundle({ entry: 'src/index', checksEnabled: cmd.check, - config: ConfigReader.fromConfigs(appConfigs), - appConfigs, + ...(await loadCliConfig(cmd.config)), }); await waitForExit(); diff --git a/packages/cli/src/commands/backend/dev.ts b/packages/cli/src/commands/backend/dev.ts index d7b5ca2924..88c069a92b 100644 --- a/packages/cli/src/commands/backend/dev.ts +++ b/packages/cli/src/commands/backend/dev.ts @@ -14,28 +14,14 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/config'; -import { loadConfig } from '@backstage/config-loader'; import { Command } from 'commander'; -import { paths } from '../../lib/paths'; import { serveBackend } from '../../lib/bundler/backend'; export default async (cmd: Command) => { - const appConfigs = await loadConfig({ - env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development', - rootPaths: [paths.targetRoot, paths.targetDir], - }); - - console.log( - `Loaded config from ${appConfigs.map(c => c.context).join(', ')}`, - ); - const waitForExit = await serveBackend({ entry: 'src/index', checksEnabled: cmd.check, inspectEnabled: cmd.inspect, - config: ConfigReader.fromConfigs(appConfigs), - appConfigs, }); await waitForExit(); diff --git a/packages/cli/src/commands/config/print.ts b/packages/cli/src/commands/config/print.ts index 693724e4d9..eb814a5bee 100644 --- a/packages/cli/src/commands/config/print.ts +++ b/packages/cli/src/commands/config/print.ts @@ -15,24 +15,13 @@ */ import { Command } from 'commander'; -import { loadConfig } from '@backstage/config-loader'; -import { ConfigReader } from '@backstage/config'; -import { paths } from '../../lib/paths'; import { stringify as stringifyYaml } from 'yaml'; +import { loadCliConfig } from '../../lib/config'; export default async (cmd: Command) => { - const appConfigs = await loadConfig({ - env: - cmd.env ?? process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development', - shouldReadSecrets: cmd.withSecrets ?? false, - rootPaths: [paths.targetRoot, paths.targetDir], - }); + const { config } = await loadCliConfig(cmd.config, cmd.withSecrets ?? false); - console.log( - `Loaded config from ${appConfigs.map(c => c.context).join(', ')}`, - ); - - const flatConfig = ConfigReader.fromConfigs(appConfigs).get(); + const flatConfig = config.get(); if (cmd.format === 'json') { process.stdout.write(`${JSON.stringify(flatConfig, null, 2)}\n`); diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index e5017b829a..7f028919f7 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -18,16 +18,25 @@ import { CommanderStatic } from 'commander'; import { exitWithError } from '../lib/errors'; export function registerCommands(program: CommanderStatic) { + const configOption = [ + '--config ', + 'Config files to load instead of app-config.yaml', + (opt: string, opts: string[]) => [...opts, opt], + Array(), + ] as const; + program .command('app:build') .description('Build an app for a production release') .option('--stats', 'Write bundle stats to output directory') + .option(...configOption) .action(lazy(() => import('./app/build').then(m => m.default))); program .command('app:serve') .description('Serve an app for local development') .option('--check', 'Enable type checking and linting') + .option(...configOption) .action(lazy(() => import('./app/serve').then(m => m.default))); program @@ -50,6 +59,8 @@ export function registerCommands(program: CommanderStatic) { .description('Start local development server with HMR for the backend') .option('--check', 'Enable type checking and linting') .option('--inspect', 'Enable debugger') + // We don't actually use the config in the CLI, just pass them on to the NodeJS process + .option(...configOption) .action(lazy(() => import('./backend/dev').then(m => m.default))); program @@ -89,12 +100,14 @@ export function registerCommands(program: CommanderStatic) { .command('plugin:serve') .description('Serves the dev/ folder of a plugin') .option('--check', 'Enable type checking and linting') + .option(...configOption) .action(lazy(() => import('./plugin/serve').then(m => m.default))); program .command('plugin:export') .description('Exports the dev/ folder of a plugin') .option('--stats', 'Write bundle stats to output directory') + .option(...configOption) .action(lazy(() => import('./plugin/export').then(m => m.default))); program @@ -131,14 +144,11 @@ export function registerCommands(program: CommanderStatic) { program .command('config:print') .option('--with-secrets', 'Include secrets in the printed configuration') - .option( - '--env ', - 'The environment to print configuration for [APP_ENV or NODE_ENV or development]', - ) .option( '--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('./config/print').then(m => m.default))); diff --git a/packages/cli/src/commands/plugin/export.ts b/packages/cli/src/commands/plugin/export.ts index 39865f3d32..69955a2e5f 100644 --- a/packages/cli/src/commands/plugin/export.ts +++ b/packages/cli/src/commands/plugin/export.ts @@ -15,25 +15,13 @@ */ import { Command } from 'commander'; -import { loadConfig } from '@backstage/config-loader'; -import { ConfigReader } from '@backstage/config'; -import { paths } from '../../lib/paths'; import { buildBundle } from '../../lib/bundler'; +import { loadCliConfig } from '../../lib/config'; export default async (cmd: Command) => { - const appConfigs = await loadConfig({ - env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'production', - rootPaths: [paths.targetRoot, paths.targetDir], - }); - - console.log( - `Loaded config from ${appConfigs.map(c => c.context).join(', ')}`, - ); - await buildBundle({ entry: 'dev/index', statsJsonEnabled: cmd.stats, - config: ConfigReader.fromConfigs(appConfigs), - appConfigs, + ...(await loadCliConfig(cmd.config)), }); }; diff --git a/packages/cli/src/commands/plugin/serve.ts b/packages/cli/src/commands/plugin/serve.ts index 7c92c8f312..cb9def3158 100644 --- a/packages/cli/src/commands/plugin/serve.ts +++ b/packages/cli/src/commands/plugin/serve.ts @@ -15,26 +15,14 @@ */ import { Command } from 'commander'; -import { loadConfig } from '@backstage/config-loader'; -import { ConfigReader } from '@backstage/config'; -import { paths } from '../../lib/paths'; import { serveBundle } from '../../lib/bundler'; +import { loadCliConfig } from '../../lib/config'; export default async (cmd: Command) => { - const appConfigs = await loadConfig({ - env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development', - rootPaths: [paths.targetRoot, paths.targetDir], - }); - - console.log( - `Loaded config from ${appConfigs.map(c => c.context).join(', ')}`, - ); - const waitForExit = await serveBundle({ entry: 'dev/index', checksEnabled: cmd.check, - config: ConfigReader.fromConfigs(appConfigs), - appConfigs, + ...(await loadCliConfig(cmd.config)), }); await waitForExit(); diff --git a/packages/cli/src/lib/bundler/backend.ts b/packages/cli/src/lib/bundler/backend.ts index e3cc8af8d1..9633c1b963 100644 --- a/packages/cli/src/lib/bundler/backend.ts +++ b/packages/cli/src/lib/bundler/backend.ts @@ -17,13 +17,9 @@ import webpack from 'webpack'; import { createBackendConfig } from './config'; import { resolveBundlingPaths } from './paths'; -import { ServeOptions } from './types'; +import { BackendServeOptions } from './types'; -export async function serveBackend( - options: ServeOptions & { - inspectEnabled: boolean; - }, -) { +export async function serveBackend(options: BackendServeOptions) { const paths = resolveBundlingPaths(options); const config = await createBackendConfig(paths, { ...options, diff --git a/packages/cli/src/lib/bundler/types.ts b/packages/cli/src/lib/bundler/types.ts index 827d517fef..00f1895725 100644 --- a/packages/cli/src/lib/bundler/types.ts +++ b/packages/cli/src/lib/bundler/types.ts @@ -27,10 +27,6 @@ export type BundlingOptions = { parallel?: ParallelOption; }; -export type BackendBundlingOptions = Omit & { - inspectEnabled: boolean; -}; - export type ServeOptions = BundlingPathsOptions & { checksEnabled: boolean; config: Config; @@ -43,3 +39,15 @@ export type BuildOptions = BundlingPathsOptions & { config: Config; appConfigs: AppConfig[]; }; + +export type BackendBundlingOptions = { + checksEnabled: boolean; + isDev: boolean; + parallel?: ParallelOption; + inspectEnabled: boolean; +}; + +export type BackendServeOptions = BundlingPathsOptions & { + checksEnabled: boolean; + inspectEnabled: boolean; +}; diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts new file mode 100644 index 0000000000..5801632ea5 --- /dev/null +++ b/packages/cli/src/lib/config.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Spotify AB + * + * 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 { loadConfig } from '@backstage/config-loader'; +import { ConfigReader } from '@backstage/config'; +import { paths } from './paths'; + +export async function loadCliConfig( + configArgs: string[], + shouldReadSecrets: boolean = false, +) { + const configPaths = configArgs.map(arg => paths.resolveTarget(arg)); + + const appConfigs = await loadConfig({ + shouldReadSecrets, + env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'production', + configRoot: paths.targetRoot, + configPaths, + }); + + console.log( + `Loaded config from ${appConfigs.map(c => c.context).join(', ')}`, + ); + + return { + appConfigs, + config: ConfigReader.fromConfigs(appConfigs), + }; +} diff --git a/packages/config-loader/src/lib/index.ts b/packages/config-loader/src/lib/index.ts index 40252b9cec..1b5ad2ef50 100644 --- a/packages/config-loader/src/lib/index.ts +++ b/packages/config-loader/src/lib/index.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -export { resolveStaticConfig } from './resolver'; export { readConfigFile } from './reader'; export { readEnvConfig } from './env'; export { readSecret } from './secrets'; diff --git a/packages/config-loader/src/lib/resolver.test.ts b/packages/config-loader/src/lib/resolver.test.ts deleted file mode 100644 index 9fd71f2486..0000000000 --- a/packages/config-loader/src/lib/resolver.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * 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 mockFs from 'mock-fs'; -import { resolveStaticConfig } from './resolver'; - -function normalizePaths(paths: string[]) { - return paths.map(p => - p - .replace(/^[a-z]:/i, '') - .split('\\') - .join('/'), - ); -} - -describe('resolveStaticConfig', () => { - afterEach(() => { - mockFs.restore(); - }); - - it('should resolve no files for empty roots', async () => { - mockFs({}); - const resolved = await resolveStaticConfig({ - env: 'development', - rootPaths: [], - }); - - expect(normalizePaths(resolved)).toEqual([]); - }); - - it('should resolve a single app-config', async () => { - mockFs({ '/repo/app-config.yaml': '' }); - const resolved = await resolveStaticConfig({ - env: 'development', - rootPaths: ['/repo'], - }); - - expect(normalizePaths(resolved)).toEqual(['/repo/app-config.yaml']); - }); - - it('should resolve a app-configs in different directories', async () => { - mockFs({ - '/repo/app-config.yaml': '', - '/repo/packages/a/app-config.yaml': '', - }); - const resolved = await resolveStaticConfig({ - env: 'development', - rootPaths: [ - '/repo', - '/other-repo', - '/repo/packages/a', - '/repo/packages/b', - ], - }); - - expect(normalizePaths(resolved)).toEqual([ - '/repo/app-config.yaml', - '/repo/packages/a/app-config.yaml', - ]); - }); - - it('should resolve env and local configs', async () => { - mockFs({ - '/repo/app-config.yaml': '', - '/repo/app-config.local.yaml': '', - '/repo/app-config.production.yaml': '', - '/repo/app-config.production.local.yaml': '', - '/repo/app-config.development.local.yaml': '', - '/repo/packages/a/app-config.development.yaml': '', - '/repo/packages/a/app-config.local.yaml': '', - }); - const resolved = await resolveStaticConfig({ - env: 'development', - rootPaths: ['/repo', '/repo/packages/a'], - }); - - expect(normalizePaths(resolved)).toEqual([ - '/repo/app-config.yaml', - '/repo/app-config.local.yaml', - '/repo/app-config.development.local.yaml', - '/repo/packages/a/app-config.local.yaml', - '/repo/packages/a/app-config.development.yaml', - ]); - }); - - it('resolves suffixed configs in the correct order', async () => { - mockFs({ - '/repo/app-config.yaml': '', - '/repo/app-config.local.yaml': '', - '/repo/app-config.production.yaml': '', - '/repo/app-config.production.local.yaml': '', - }); - - const resolved = await resolveStaticConfig({ - env: 'production', - rootPaths: ['/repo'], - }); - - expect(normalizePaths(resolved)).toEqual([ - '/repo/app-config.yaml', - '/repo/app-config.local.yaml', - '/repo/app-config.production.yaml', - '/repo/app-config.production.local.yaml', - ]); - }); -}); diff --git a/packages/config-loader/src/lib/resolver.ts b/packages/config-loader/src/lib/resolver.ts deleted file mode 100644 index 3856598331..0000000000 --- a/packages/config-loader/src/lib/resolver.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * 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 { resolve as resolvePath } from 'path'; -import { pathExists } from 'fs-extra'; - -type ResolveOptions = { - // Root paths to search for config files. Config from earlier paths has lower priority. - rootPaths: string[]; - // The environment that we're loading config for, e.g. 'development', 'production'. - env: string; -}; - -/** - * Resolves all configuration files that should be loaded in the given environment. - * - * For each root directory, search for the default app-config.yaml, along with suffixed - * APP_ENV and local variants, e.g. app-config.production.yaml or app-config.development.local.yaml - * - * The priority order of config loaded through suffixes is `env > local > none`, meaning that - * for example app-config.development.yaml has higher priority than `app-config.local.yaml`. - * - */ -export async function resolveStaticConfig( - options: ResolveOptions, -): Promise { - const filePaths = [ - `app-config.yaml`, - `app-config.local.yaml`, - `app-config.${options.env}.yaml`, - `app-config.${options.env}.local.yaml`, - ]; - - const resolvedPaths = []; - - for (const rootPath of options.rootPaths) { - for (const filePath of filePaths) { - const path = resolvePath(rootPath, filePath); - if (await pathExists(path)) { - resolvedPaths.push(path); - } - } - } - - return resolvedPaths; -} diff --git a/packages/config-loader/src/loader.test.ts b/packages/config-loader/src/loader.test.ts index 087e2309c0..3b0d8e6e92 100644 --- a/packages/config-loader/src/loader.test.ts +++ b/packages/config-loader/src/loader.test.ts @@ -38,10 +38,31 @@ describe('loadConfig', () => { mockFs.restore(); }); + it('load config from default path', async () => { + await expect( + loadConfig({ + configRoot: '/root', + configPaths: [], + env: 'production', + shouldReadSecrets: false, + }), + ).resolves.toEqual([ + { + context: 'app-config.yaml', + data: { + app: { + title: 'Example App', + }, + }, + }, + ]); + }); + it('loads config without secrets', async () => { await expect( loadConfig({ - rootPaths: ['/root'], + configRoot: '/root', + configPaths: ['/root/app-config.yaml'], env: 'production', shouldReadSecrets: false, }), @@ -60,7 +81,8 @@ describe('loadConfig', () => { it('loads config with secrets', async () => { await expect( loadConfig({ - rootPaths: ['/root'], + configRoot: '/root', + configPaths: ['/root/app-config.yaml'], env: 'production', shouldReadSecrets: true, }), @@ -80,7 +102,11 @@ describe('loadConfig', () => { it('loads development config without secrets', async () => { await expect( loadConfig({ - rootPaths: ['/root'], + configRoot: '/root', + configPaths: [ + '/root/app-config.yaml', + '/root/app-config.development.yaml', + ], env: 'development', shouldReadSecrets: false, }), @@ -105,7 +131,11 @@ describe('loadConfig', () => { it('loads development config with secrets', async () => { await expect( loadConfig({ - rootPaths: ['/root'], + configRoot: '/root', + configPaths: [ + '/root/app-config.yaml', + '/root/app-config.development.yaml', + ], env: 'development', shouldReadSecrets: true, }), diff --git a/packages/config-loader/src/loader.ts b/packages/config-loader/src/loader.ts index cf5edd3ce3..e7eb2a38fa 100644 --- a/packages/config-loader/src/loader.ts +++ b/packages/config-loader/src/loader.ts @@ -15,20 +15,18 @@ */ import fs from 'fs-extra'; -import { resolve as resolvePath, dirname } from 'path'; +import { resolve as resolvePath, dirname, isAbsolute } from 'path'; import { AppConfig, JsonObject } from '@backstage/config'; -import { - resolveStaticConfig, - readConfigFile, - readEnvConfig, - readSecret, -} from './lib'; +import { readConfigFile, readEnvConfig, readSecret } from './lib'; export type LoadConfigOptions = { - // Root paths to search for config files. Config from earlier paths has lower priority. - rootPaths: string[]; + // The root directory of the config loading context. Used to find default configs. + configRoot: string; - // The environment that we're loading config for, e.g. 'development', 'production'. + // Absolute paths to load config files from. Configs from earlier paths have lower priority. + configPaths: string[]; + + // TODO(Rugvip): This will be removed in the future, but for now we use it to warn about possible mistakes. env: string; // Whether to read secrets or omit them, defaults to false. @@ -77,13 +75,37 @@ export async function loadConfig( options: LoadConfigOptions, ): Promise { const configs = []; + const { configRoot } = options; + const configPaths = options.configPaths.slice(); - const configPaths = await resolveStaticConfig(options); + // If no paths are provided, we default to reading + // `app-config.yaml` and, if it exists, `app-config.local.yaml` + if (configPaths.length === 0) { + configPaths.push(resolvePath(configRoot, 'app-config.yaml')); + + const localConfig = resolvePath(configRoot, 'app-config.local.yaml'); + if (await fs.pathExists(localConfig)) { + configPaths.push(localConfig); + } + + const envFile = `app-config.${options.env}.yaml`; + if (await fs.pathExists(resolvePath(configRoot, envFile))) { + console.error( + `Env config file '${envFile}' is not loaded as APP_ENV and NODE_ENV-based config loading has been removed`, + ); + console.error( + `To load the config file, use --config , listing every config file that you want to load`, + ); + } + } try { const secretPaths = new Set(); for (const configPath of configPaths) { + if (!isAbsolute(configPath)) { + throw new Error(`Config load path is not absolute: '${configPath}'`); + } const config = await readConfigFile( configPath, new Context({ diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 18b6cfa647..e5cfc31576 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -42,7 +42,7 @@ function makeCreateEnv(config: Config) { } async function main() { - const config = await loadBackendConfig({logger: getRootLogger()}); + const config = await loadBackendConfig({logger: getRootLogger(), configPaths: []}); const createEnv = makeCreateEnv(config); const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); diff --git a/plugins/auth-backend/src/service/standaloneServer.ts b/plugins/auth-backend/src/service/standaloneServer.ts index a3c64c6e8e..a4f2377507 100644 --- a/plugins/auth-backend/src/service/standaloneServer.ts +++ b/plugins/auth-backend/src/service/standaloneServer.ts @@ -33,7 +33,7 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'auth-backend' }); - const config = await loadBackendConfig({ logger }); + const config = await loadBackendConfig({ logger, argv: process.argv }); const discovery = SingleHostDiscovery.fromConfig(config); const database = useHotMemoize(module, () => { diff --git a/plugins/catalog-backend/src/service/standaloneServer.ts b/plugins/catalog-backend/src/service/standaloneServer.ts index 23f9795036..73a33c8c8e 100644 --- a/plugins/catalog-backend/src/service/standaloneServer.ts +++ b/plugins/catalog-backend/src/service/standaloneServer.ts @@ -36,7 +36,7 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'catalog-backend' }); - const config = await loadBackendConfig({ logger }); + const config = await loadBackendConfig({ logger, argv: process.argv }); const reader = UrlReaders.default({ logger, config }); const db = useHotMemoize(module, () => DatabaseManager.createInMemoryDatabaseConnection(), diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts index 42e723e54a..77db35c917 100644 --- a/plugins/proxy-backend/src/service/router.test.ts +++ b/plugins/proxy-backend/src/service/router.test.ts @@ -41,7 +41,7 @@ const mockCreateProxyMiddleware = createProxyMiddleware as jest.MockedFunction< describe('createRouter', () => { it('works', async () => { const logger = winston.createLogger(); - const config = await loadBackendConfig({ logger }); + const config = await loadBackendConfig({ logger, argv: [] }); const discovery = SingleHostDiscovery.fromConfig(config); const router = await createRouter({ config, diff --git a/plugins/proxy-backend/src/service/standaloneServer.ts b/plugins/proxy-backend/src/service/standaloneServer.ts index 160ed1db86..c64d69e2a4 100644 --- a/plugins/proxy-backend/src/service/standaloneServer.ts +++ b/plugins/proxy-backend/src/service/standaloneServer.ts @@ -36,7 +36,7 @@ export async function startStandaloneServer( logger.debug('Creating application...'); - const config = await loadBackendConfig({ logger }); + const config = await loadBackendConfig({ logger, argv: process.argv }); const discovery = SingleHostDiscovery.fromConfig(config); const router = await createRouter({ config, diff --git a/plugins/rollbar-backend/src/service/standaloneServer.ts b/plugins/rollbar-backend/src/service/standaloneServer.ts index 1be2599724..b30bf6fc6b 100644 --- a/plugins/rollbar-backend/src/service/standaloneServer.ts +++ b/plugins/rollbar-backend/src/service/standaloneServer.ts @@ -32,7 +32,7 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'rollbar-backend' }); - const config = await loadBackendConfig({ logger }); + const config = await loadBackendConfig({ logger, argv: process.argv }); logger.debug('Creating application...'); diff --git a/plugins/techdocs-backend/src/default-branch.ts b/plugins/techdocs-backend/src/default-branch.ts index e9164c5175..52b8b008f9 100644 --- a/plugins/techdocs-backend/src/default-branch.ts +++ b/plugins/techdocs-backend/src/default-branch.ts @@ -231,7 +231,10 @@ export const getDefaultBranch = async ( repositoryUrl: string, ): Promise => { // TODO(Rugvip): Config should not be loaded here, pass it in instead - const config = await loadBackendConfig({ logger: getRootLogger() }); + const config = await loadBackendConfig({ + logger: getRootLogger(), + argv: process.argv, + }); const type = getGitRepoType(repositoryUrl); try { diff --git a/yarn.lock b/yarn.lock index 0c7c8635c2..144b3c6827 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5351,6 +5351,11 @@ resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/minimist@^1.2.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" + integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= + "@types/minipass@*": version "2.2.0" resolved "https://registry.npmjs.org/@types/minipass/-/minipass-2.2.0.tgz#51ad404e8eb1fa961f75ec61205796807b6f9651" From fac3026699d2c7cad649456faa04a0146daa2623 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 21 Oct 2020 10:31:02 +0200 Subject: [PATCH 2/8] create-app: prettier backend + fix loadBackendConfig arg --- .../default-app/packages/backend/src/index.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index e5cfc31576..51de1ad6b3 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -42,7 +42,10 @@ function makeCreateEnv(config: Config) { } async function main() { - const config = await loadBackendConfig({logger: getRootLogger(), configPaths: []}); + const config = await loadBackendConfig({ + argv: process.argv, + logger: getRootLogger(), + }); const createEnv = makeCreateEnv(config); const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); @@ -52,16 +55,16 @@ async function main() { const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); const apiRouter = Router(); - apiRouter.use('/catalog', await catalog(catalogEnv)) - apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv)) - apiRouter.use('/auth', await auth(authEnv)) - apiRouter.use('/techdocs', await techdocs(techdocsEnv)) - apiRouter.use('/proxy', await proxy(proxyEnv)) + apiRouter.use('/catalog', await catalog(catalogEnv)); + apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv)); + apiRouter.use('/auth', await auth(authEnv)); + apiRouter.use('/techdocs', await techdocs(techdocsEnv)); + apiRouter.use('/proxy', await proxy(proxyEnv)); apiRouter.use(notFoundHandler()); const service = createServiceBuilder(module) .loadConfig(config) - .addRouter('/api', apiRouter) + .addRouter('/api', apiRouter); await service.start().catch(err => { console.log(err); From 4a6a5149df1db7918694fc5c2dd46b5a0cae29f1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 21 Oct 2020 10:49:41 +0200 Subject: [PATCH 3/8] backend-common: fix for args.config not always being an array --- packages/backend-common/src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-common/src/config.ts b/packages/backend-common/src/config.ts index 6223d3150b..69e46bd5b4 100644 --- a/packages/backend-common/src/config.ts +++ b/packages/backend-common/src/config.ts @@ -32,7 +32,7 @@ type Options = { */ export async function loadBackendConfig(options: Options): Promise { const args = parseArgs(options.argv); - const configOpts: string[] = args.config ?? []; + const configOpts: string[] = [args.config ?? []].flat(); /* eslint-disable-next-line no-restricted-syntax */ const paths = findPaths(__dirname); From 4ab6f559dd27717a9a05b1f412888b98e904c8fd Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 21 Oct 2020 21:04:57 +0200 Subject: [PATCH 4/8] app-config: merged dev config back into main config --- app-config.development.yaml | 13 ------------- app-config.yaml | 8 ++++++-- .../default-app/app-config.development.yaml | 13 ------------- .../templates/default-app/app-config.yaml.hbs | 8 ++++++-- 4 files changed, 12 insertions(+), 30 deletions(-) delete mode 100644 app-config.development.yaml delete mode 100644 packages/create-app/templates/default-app/app-config.development.yaml diff --git a/app-config.development.yaml b/app-config.development.yaml deleted file mode 100644 index 817847c6d6..0000000000 --- a/app-config.development.yaml +++ /dev/null @@ -1,13 +0,0 @@ -app: - baseUrl: http://localhost:3000 - -backend: - baseUrl: http://localhost:7000 - listen: - port: 7000 - cors: - origin: http://localhost:3000 - methods: [GET, POST, PUT, DELETE] - credentials: true - csp: - connect-src: ["'self'", 'http:', 'https:'] diff --git a/app-config.yaml b/app-config.yaml index 6e49e765cd..05bf39b5b3 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -1,6 +1,6 @@ app: title: Backstage Example App - baseUrl: http://localhost:7000 + baseUrl: http://localhost:3000 googleAnalyticsTrackingId: # UA-000000-0 backend: @@ -10,8 +10,12 @@ backend: database: client: sqlite3 connection: ':memory:' + cors: + origin: http://localhost:3000 + methods: [GET, POST, PUT, DELETE] + credentials: true csp: - connect-src: ["'self'", 'https:'] + connect-src: ["'self'", 'http:', 'https:'] # See README.md in the proxy-backend plugin for information on the configuration format proxy: diff --git a/packages/create-app/templates/default-app/app-config.development.yaml b/packages/create-app/templates/default-app/app-config.development.yaml deleted file mode 100644 index 817847c6d6..0000000000 --- a/packages/create-app/templates/default-app/app-config.development.yaml +++ /dev/null @@ -1,13 +0,0 @@ -app: - baseUrl: http://localhost:3000 - -backend: - baseUrl: http://localhost:7000 - listen: - port: 7000 - cors: - origin: http://localhost:3000 - methods: [GET, POST, PUT, DELETE] - credentials: true - csp: - connect-src: ["'self'", 'http:', 'https:'] diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index b92cdf22bd..a0b9f156ed 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -1,6 +1,6 @@ app: title: Scaffolded Backstage App - baseUrl: http://localhost:7000 + baseUrl: http://localhost:3000 organization: name: My Company @@ -10,7 +10,11 @@ backend: listen: port: 7000 csp: - connect-src: ["'self'", 'https:'] + connect-src: ["'self'", 'http:', 'https:'] + cors: + origin: http://localhost:3000 + methods: [GET, POST, PUT, DELETE] + credentials: true {{#if dbTypeSqlite}} database: client: sqlite3 From 87a6e78d0350b2b49b7e6882b1fb5233856e1ad3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 21 Oct 2020 22:02:51 +0200 Subject: [PATCH 5/8] CHANGELOG: bump to alpha.25 and add entry for new --config flags --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bcce2966f..f445c189f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re ## Next Release +### @backstage/cli + +- Configuration files are no longer selected through `APP_ENV` or `NODE_ENV`. The default configuration files are `app-config.yaml` and, fix it exists, `app-config.local.yaml` in the repo root. To load a different set of files, use `--config ` arguments. + +### @backstage/backend-common + +- Configuration files are no longer selected through `APP_ENV` or `NODE_ENV`. The default configuration files are `app-config.yaml` and, fix it exists, `app-config.local.yaml` in the repo root. To load a different set of files, use `--config ` arguments. + +## v0.1.1-alpha.25 + > Collect changes for the next release below ### @backstage/cli From c2ea3cd26aa826b034bf91ffdac31206b4f93cb1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 22 Oct 2020 10:08:37 +0200 Subject: [PATCH 6/8] docs: updated to reflect new --config flags --- docs/conf/index.md | 10 +++--- docs/conf/writing.md | 36 +++++++++++-------- docs/support/project-structure.md | 3 -- .../examples/dice-roller/README.md | 4 +-- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/docs/conf/index.md b/docs/conf/index.md index e1dfc30582..2c3ee06ba6 100644 --- a/docs/conf/index.md +++ b/docs/conf/index.md @@ -15,11 +15,11 @@ allowing for customization. ## Supplying Configuration -Configuration is stored in `app-config.yaml` files, with support for suffixes -such as `app-config.production.yaml` to override values for specific -environments. The configuration files themselves contain plain YAML, but with -support for loading in secrets from various sources using for example `$env` and -`$file` keys. +Configuration is stored in YAML files where the defaults are `app-config.yaml` +and `app-config.local.yaml` for local overrides. Other sets of files can by +loaded by passing `--config ` flags. The configuration files themselves +contain plain YAML, but with support for loading in secrets from various sources +using for example `$env` and `$file` keys. It is also possible to supply configuration through environment variables, for example `APP_CONFIG_app_baseUrl=https://staging.example.com`. However these diff --git a/docs/conf/writing.md b/docs/conf/writing.md index bb4d0beb75..06d4b52f3f 100644 --- a/docs/conf/writing.md +++ b/docs/conf/writing.md @@ -55,20 +55,28 @@ picked up by the serve tasks of `@backstage/cli` for local development, and are injected by the entrypoint of the nginx container serving the frontend in a production build. -## File Resolution +## Configuration Files It is possible to have multiple configuration files, both to support different environments, but also to define configuration that is local to specific -packages. +packages. The configuration files to load are selected using a `--config ` +flag, and it is possible to load any number of files. Paths are relative to the +working directory of the executed process, for example `package/backend`. This +means that to select a config file in the repo root when running the backend, +you would use `--config ../../my-config.yaml`. -All `app-config.yaml` files inside the monorepo root and package root are -considered, as are files with additional `local` and environment affixes such as -`development`, for example `app-config.local.yaml`, -`app-config.production.yaml`, and `app-config.development.local.yaml`. Which -environment config files are loaded is determined by the `APP_ENV` environment -variable, or `NODE_ENV` if it is not set. Local configuration files are always -loaded, but are meant for local development overrides and should typically be -`.gitignore`'d. +If no `config` flags are specified, the default behavior is to load +`app-config.yaml` and, if it exists, `app-config.local.yaml` from the repo root. +In the provided project setup, `app-config.local.yaml` is `.gitignore`'d, making +it a good place to add config overrides and secrets for local development. + +Note that if any config flags are provided, the default `app-config.yaml` files +are NOT loaded. To include them you need to explicitly include them with a flag, +for example: + +``` +yarn start --config ../../app-config.yaml --config ../../app-config.staging.yaml +``` All loaded configuration files are merged together using the following rules: @@ -84,10 +92,10 @@ order: - Configuration from the `APP_CONFIG_` environment variables has the highest priority, followed by files. -- Files inside package directories have higher priority than those in the root - directory. -- Files with environment affixes have higher priority than ones without. -- Files with the `local` affix have higher priority than ones without. +- Files loaded with config flags are ordered by priority, where the last flag + has the highest priority. +- If no config flags are provided, `app-config.local.yaml` has higher priority + than `app-config.yaml`. ## Secrets diff --git a/docs/support/project-structure.md b/docs/support/project-structure.md index 277ca3929f..987d6a8ff3 100644 --- a/docs/support/project-structure.md +++ b/docs/support/project-structure.md @@ -228,9 +228,6 @@ future. - [`app-config.yaml`](https://github.com/spotify/backstage/tree/master/app-config.yaml) - Configuration for the app, both frontend and backend -- [`app-config.development.yaml`](https://github.com/spotify/backstage/tree/master/app-config.development.yaml) - - Used for overriding configuration when developing locally. - - [`catalog-info.yaml`](https://github.com/spotify/backstage/tree/master/catalog-info.yaml) - Description of Backstage in the Backstage Entity format. diff --git a/plugins/kubernetes-backend/examples/dice-roller/README.md b/plugins/kubernetes-backend/examples/dice-roller/README.md index 774867de04..bf3e7d261a 100644 --- a/plugins/kubernetes-backend/examples/dice-roller/README.md +++ b/plugins/kubernetes-backend/examples/dice-roller/README.md @@ -23,7 +23,7 @@ This can be used to run the kubernetes plugin locally against a mock service. 6. Register existing component in Backstage - https://github.com/mclarke47/dice-roller/blob/master/catalog-info.yaml -Update `app-config.development.yaml` as follows. +Add or update `app-config.local.yaml` with the following: ```yaml kubernetes: @@ -45,4 +45,4 @@ Mac copy to clipboard: kubectl get secret $(kubectl get sa dice-roller -o=json | jq -r .secrets[0].name) -o=json | jq -r '.data["token"]' | base64 --decode | pbcopy ``` -Paste into `app-config.development.yaml` `kubernetes.clusters[0].serviceAccountToken` +Paste into `app-config.local.yaml` `kubernetes.clusters[0].serviceAccountToken` From 3dec8022d23409877f5f0f51402562949237908e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 22 Oct 2020 10:50:41 +0200 Subject: [PATCH 7/8] contrib/kubernetes: update plain example to load config with args --- .../plain_single_backend_deplyoment/deployment.yaml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/contrib/kubernetes/plain_single_backend_deplyoment/deployment.yaml b/contrib/kubernetes/plain_single_backend_deplyoment/deployment.yaml index 87dee94895..a20c47229d 100644 --- a/contrib/kubernetes/plain_single_backend_deplyoment/deployment.yaml +++ b/contrib/kubernetes/plain_single_backend_deplyoment/deployment.yaml @@ -28,6 +28,9 @@ spec: image: example-backend:latest imagePullPolicy: Never + command: [node, packages/backend] + args: [--config, app-config.yaml, --config, k8s-config.yaml] + env: # We set this to development to make the backend start with incomplete configuration. In a production # deployment you will want to make sure that you have a full configuration, and remove any plugins that @@ -35,10 +38,6 @@ spec: - name: NODE_ENV value: development - # This makes us load in `app-config.production.yaml` if there is one. - - name: APP_ENV - value: production - # This makes it possible for the app to reach the backend when serving through `kubectl proxy` # If you expose the service using for example an ingress controller, you should # switch this out or remove it. @@ -54,8 +53,8 @@ spec: volumeMounts: - name: config-volume - mountPath: /usr/src/app/app-config.local.yaml - subPath: app-config.local.yaml + mountPath: /usr/src/app/k8s-config.yaml + subPath: k8s-config.yaml resources: limits: @@ -77,7 +76,7 @@ spec: name: backstage-config items: - key: app-config - path: app-config.local.yaml + path: k8s-config.yaml --- apiVersion: v1 kind: ConfigMap From f495ba9c18f4295b1d43adc44d2c097587e0c480 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 22 Oct 2020 12:49:02 +0200 Subject: [PATCH 8/8] techdocs-backend: fix config loading in git-auth --- plugins/techdocs-backend/src/git-auth.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/techdocs-backend/src/git-auth.ts b/plugins/techdocs-backend/src/git-auth.ts index d77596929f..b580a6f05b 100644 --- a/plugins/techdocs-backend/src/git-auth.ts +++ b/plugins/techdocs-backend/src/git-auth.ts @@ -93,7 +93,11 @@ export function getAzureHostToken( export const getTokenForGitRepo = async ( repositoryUrl: string, ): Promise => { - const config = await loadBackendConfig({ logger: getRootLogger() }); + // TODO(Rugvip): Config should not be loaded here, pass it in instead + const config = await loadBackendConfig({ + logger: getRootLogger(), + argv: process.argv, + }); const host = getGitHost(repositoryUrl); const type = getGitRepoType(repositoryUrl);