diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 18131236df..b8a4e372ab 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -29,7 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { + "@backstage/cli-common": "^0.1.1-alpha.16", "@backstage/config": "^0.1.1-alpha.16", + "@backstage/config-loader": "^0.1.1-alpha.16", "@types/cors": "^2.8.6", "@types/express": "^4.17.6", "compression": "^1.7.4", diff --git a/packages/config-loader/src/lib/paths.test.ts b/packages/backend-common/src/config.ts similarity index 63% rename from packages/config-loader/src/lib/paths.test.ts rename to packages/backend-common/src/config.ts index dd5ed14748..8391ed4104 100644 --- a/packages/config-loader/src/lib/paths.test.ts +++ b/packages/backend-common/src/config.ts @@ -14,11 +14,17 @@ * limitations under the License. */ -import { findRootPath } from './paths'; +import { findPaths } from '@backstage/cli-common'; +import { loadConfig } from '@backstage/config-loader'; -describe('findRootPath', () => { - it('should find root path', () => { - const rootPath = findRootPath(process.cwd()); - expect(typeof rootPath).toBe('string'); +/** + * Load configuration for a Backend + */ +export async function loadBackendConfig() { + const paths = findPaths(__dirname); + const configs = await loadConfig({ + rootPath: paths.targetRoot, + shouldReadSecrets: true, }); -}); + return configs; +} diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts index 0e4e5b2c6b..a3f57ed9df 100644 --- a/packages/backend-common/src/index.ts +++ b/packages/backend-common/src/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export * from './config'; export * from './errors'; export * from './logging'; export * from './middleware'; diff --git a/packages/backend/package.json b/packages/backend/package.json index 7ca11fc636..1de51948d8 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -21,7 +21,6 @@ "@backstage/backend-common": "^0.1.1-alpha.16", "@backstage/catalog-model": "^0.1.1-alpha.16", "@backstage/config": "^0.1.1-alpha.16", - "@backstage/config-loader": "^0.1.1-alpha.16", "@backstage/plugin-auth-backend": "^0.1.1-alpha.16", "@backstage/plugin-catalog-backend": "^0.1.1-alpha.16", "@backstage/plugin-identity-backend": "^0.1.1-alpha.16", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 3fccfe9c59..261a4d2894 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -24,11 +24,11 @@ import { createServiceBuilder, + loadBackendConfig, getRootLogger, useHotMemoize, } from '@backstage/backend-common'; import { ConfigReader, AppConfig } from '@backstage/config'; -import { loadConfig } from '@backstage/config-loader'; import knex, { PgConnectionConfig } from 'knex'; import healthcheck from './plugins/healthcheck'; import auth from './plugins/auth'; @@ -85,7 +85,7 @@ function makeCreateEnv(loadedConfigs: AppConfig[]) { } async function main() { - const configs = await loadConfig({ shouldReadSecrets: true }); + const configs = await loadBackendConfig(); const configReader = ConfigReader.fromConfigs(configs); const createEnv = makeCreateEnv(configs); diff --git a/packages/cli/src/commands/app/build.ts b/packages/cli/src/commands/app/build.ts index 4ecf54f532..b3ec5ad2bf 100644 --- a/packages/cli/src/commands/app/build.ts +++ b/packages/cli/src/commands/app/build.ts @@ -17,10 +17,11 @@ 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'; export default async (cmd: Command) => { - const appConfigs = await loadConfig(); + const appConfigs = await loadConfig({ rootPath: paths.targetRoot }); await buildBundle({ entry: 'src/index', statsJsonEnabled: cmd.stats, diff --git a/packages/cli/src/commands/app/serve.ts b/packages/cli/src/commands/app/serve.ts index 023a3a4663..732370ef3b 100644 --- a/packages/cli/src/commands/app/serve.ts +++ b/packages/cli/src/commands/app/serve.ts @@ -17,10 +17,11 @@ 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'; export default async (cmd: Command) => { - const appConfigs = await loadConfig(); + const appConfigs = await loadConfig({ rootPath: paths.targetRoot }); const waitForExit = await serveBundle({ entry: 'src/index', checksEnabled: cmd.check, diff --git a/packages/cli/src/commands/backend/dev.ts b/packages/cli/src/commands/backend/dev.ts index f04f904e09..03d9464722 100644 --- a/packages/cli/src/commands/backend/dev.ts +++ b/packages/cli/src/commands/backend/dev.ts @@ -17,10 +17,11 @@ 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(); + const appConfigs = await loadConfig({ rootPath: paths.targetRoot }); const waitForExit = await serveBackend({ entry: 'src/index', checksEnabled: cmd.check, diff --git a/packages/cli/src/commands/plugin/export.ts b/packages/cli/src/commands/plugin/export.ts index b6db0d8ddd..be6df707f3 100644 --- a/packages/cli/src/commands/plugin/export.ts +++ b/packages/cli/src/commands/plugin/export.ts @@ -17,10 +17,11 @@ 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'; export default async (cmd: Command) => { - const appConfigs = await loadConfig(); + const appConfigs = await loadConfig({ rootPath: paths.targetRoot }); await buildBundle({ entry: 'dev/index', statsJsonEnabled: cmd.stats, diff --git a/packages/cli/src/commands/plugin/serve.ts b/packages/cli/src/commands/plugin/serve.ts index 57b939fa63..5ee4b70a1e 100644 --- a/packages/cli/src/commands/plugin/serve.ts +++ b/packages/cli/src/commands/plugin/serve.ts @@ -17,10 +17,11 @@ 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'; export default async (cmd: Command) => { - const appConfigs = await loadConfig(); + const appConfigs = await loadConfig({ rootPath: paths.targetRoot }); const waitForExit = await serveBundle({ entry: 'dev/index', checksEnabled: cmd.check, diff --git a/packages/config-loader/src/lib/paths.ts b/packages/config-loader/src/lib/paths.ts deleted file mode 100644 index d0e7e96e36..0000000000 --- a/packages/config-loader/src/lib/paths.ts +++ /dev/null @@ -1,57 +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 fs from 'fs-extra'; -import { dirname, resolve as resolvePath } from 'path'; - -/** - * Looks for a package.json that has name: "root" to identify the root of the monorepo - * - * This is a copy of the same function in the CLI - */ -export function findRootPath(topPath: string): string { - let path = topPath; - - // Some sanity check to avoid infinite loop - for (let i = 0; i < 1000; i++) { - const packagePath = resolvePath(path, 'package.json'); - const exists = fs.pathExistsSync(packagePath); - if (exists) { - try { - const data = fs.readJsonSync(packagePath); - if (data.name === 'root' || data.name.includes('backstage-e2e')) { - return path; - } - } catch (error) { - throw new Error( - `Failed to parse package.json file while searching for root, ${error}`, - ); - } - } - - const newPath = dirname(path); - if (newPath === path) { - throw new Error( - `No package.json with name "root" found as a parent of ${topPath}`, - ); - } - path = newPath; - } - - throw new Error( - `Iteration limit reached when searching for root package.json at ${topPath}`, - ); -} diff --git a/packages/config-loader/src/lib/resolver.ts b/packages/config-loader/src/lib/resolver.ts index 4a06f3ebca..a3921f07aa 100644 --- a/packages/config-loader/src/lib/resolver.ts +++ b/packages/config-loader/src/lib/resolver.ts @@ -14,13 +14,11 @@ * limitations under the License. */ -import fs from 'fs-extra'; import { resolve as resolvePath } from 'path'; -import { findRootPath } from './paths'; type ResolveOptions = { - // Same as configPath in LoadConfigOptions - configPath?: string; + // Root path for search for app-config.yaml + rootPath: string; }; /** @@ -31,13 +29,7 @@ export async function resolveStaticConfig( ): Promise { // TODO: We'll want this to be a bit more elaborate, probably adding configs for // specific env, and maybe local config for plugins. - let { configPath } = options; - if (!configPath) { - configPath = resolvePath( - findRootPath(fs.realpathSync(process.cwd())), - 'app-config.yaml', - ); - } + const configPath = resolvePath(options.rootPath, 'app-config.yaml'); return [configPath]; } diff --git a/packages/config-loader/src/loader.ts b/packages/config-loader/src/loader.ts index 1b6c8f34da..ce0e09e815 100644 --- a/packages/config-loader/src/loader.ts +++ b/packages/config-loader/src/loader.ts @@ -25,8 +25,8 @@ import { } from './lib'; export type LoadConfigOptions = { - // Config path, defaults to app-config.yaml in project root - configPath?: string; + // Root path for search for app-config.yaml + rootPath: string; // Whether to read secrets or omit them, defaults to false. shouldReadSecrets?: boolean; @@ -59,7 +59,7 @@ class Context { } export async function loadConfig( - options: LoadConfigOptions = {}, + options: LoadConfigOptions, ): Promise { const configs = []; diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index 93c076a967..a978349b02 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -19,8 +19,7 @@ "dependencies": { "@backstage/backend-common": "^{{version}}", "@backstage/catalog-model": "^{{version}}", - "@backstage/config": "^0.1.1-alpha.13", - "@backstage/config-loader": "^0.1.1-alpha.13", + "@backstage/config": "^{{version}}", "@backstage/plugin-auth-backend": "^{{version}}", "@backstage/plugin-catalog-backend": "^{{version}}", "@backstage/plugin-identity-backend": "^{{version}}", @@ -42,7 +41,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.15", + "@backstage/cli": "^{{version}}", "@types/dockerode": "^2.5.32", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts.hbs b/packages/create-app/templates/default-app/packages/backend/src/index.ts.hbs index 591fa1a28f..ec050970d7 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts.hbs +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts.hbs @@ -24,11 +24,11 @@ import { createServiceBuilder, + loadBackendConfig, getRootLogger, useHotMemoize, } from '@backstage/backend-common'; import { ConfigReader, AppConfig } from '@backstage/config'; -import { loadConfig } from '@backstage/config-loader'; {{#if dbTypePG}} import knex, { PgConnectionConfig } from 'knex'; {{/if}} @@ -78,7 +78,7 @@ function makeCreateEnv(loadedConfigs: AppConfig[]) { } async function main() { - const configs = await loadConfig(); + const configs = await loadBackendConfig(); const configReader = ConfigReader.fromConfigs(configs); const createEnv = makeCreateEnv(configs); diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index b16c1e5a4f..a0a863618f 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -22,7 +22,6 @@ "dependencies": { "@backstage/backend-common": "^0.1.1-alpha.16", "@backstage/config": "^0.1.1-alpha.16", - "@backstage/config-loader": "^0.1.1-alpha.16", "@types/express": "^4.17.6", "body-parser": "^1.19.0", "compression": "^1.7.4", diff --git a/plugins/auth-backend/src/service/standaloneServer.ts b/plugins/auth-backend/src/service/standaloneServer.ts index d2372a7e91..dc91c92631 100644 --- a/plugins/auth-backend/src/service/standaloneServer.ts +++ b/plugins/auth-backend/src/service/standaloneServer.ts @@ -18,9 +18,12 @@ import Knex from 'knex'; import { Server } from 'http'; import { Logger } from 'winston'; import { ConfigReader } from '@backstage/config'; -import { loadConfig } from '@backstage/config-loader'; import { createRouter } from './router'; -import { createServiceBuilder, useHotMemoize } from '@backstage/backend-common'; +import { + createServiceBuilder, + useHotMemoize, + loadBackendConfig, +} from '@backstage/backend-common'; export interface ServerOptions { logger: Logger; @@ -30,7 +33,7 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'auth-backend' }); - const config = ConfigReader.fromConfigs(await loadConfig()); + const config = ConfigReader.fromConfigs(await loadBackendConfig()); const database = useHotMemoize(module, () => { const knex = Knex({ diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index e80bf0e00f..f65e3a7298 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -21,7 +21,6 @@ "dependencies": { "@backstage/backend-common": "^0.1.1-alpha.16", "@backstage/config": "^0.1.1-alpha.16", - "@backstage/config-loader": "^0.1.1-alpha.16", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^3.0.3", diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts index 699ed9b99d..10690dfbdd 100644 --- a/plugins/proxy-backend/src/service/router.test.ts +++ b/plugins/proxy-backend/src/service/router.test.ts @@ -17,12 +17,12 @@ import { createRouter } from './router'; import winston from 'winston'; import { ConfigReader } from '@backstage/config'; -import { loadConfig } from '@backstage/config-loader'; +import { loadBackendConfig } from '@backstage/backend-common'; describe('createRouter', () => { it('works', async () => { const logger = winston.createLogger(); - const config = ConfigReader.fromConfigs(await loadConfig()); + const config = ConfigReader.fromConfigs(await loadBackendConfig()); const router = await createRouter({ config, logger, diff --git a/plugins/proxy-backend/src/service/standaloneServer.ts b/plugins/proxy-backend/src/service/standaloneServer.ts index 84c803eeac..f75c044f0f 100644 --- a/plugins/proxy-backend/src/service/standaloneServer.ts +++ b/plugins/proxy-backend/src/service/standaloneServer.ts @@ -14,12 +14,14 @@ * limitations under the License. */ -import { createServiceBuilder } from '@backstage/backend-common'; +import { + createServiceBuilder, + loadBackendConfig, +} from '@backstage/backend-common'; import { Server } from 'http'; import { Logger } from 'winston'; import { createRouter } from './router'; import { ConfigReader } from '@backstage/config'; -import { loadConfig } from '@backstage/config-loader'; export interface ServerOptions { port: number; @@ -34,7 +36,7 @@ export async function startStandaloneServer( logger.debug('Creating application...'); - const config = ConfigReader.fromConfigs(await loadConfig()); + const config = ConfigReader.fromConfigs(await loadBackendConfig()); const router = await createRouter({ config, logger,