From ff9aa28301c8f31c1e83b61ac90ae39b0768c712 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 3 Jun 2020 14:37:22 +0200 Subject: [PATCH] packages/cli: move config loading to separate config-loader package --- packages/cli/package.json | 1 + packages/cli/src/commands/app/build.ts | 2 +- packages/cli/src/commands/app/serve.ts | 2 +- packages/cli/src/commands/plugin/serve.ts | 2 +- packages/config-loader/.eslintrc.js | 3 + packages/config-loader/README.md | 12 ++++ packages/config-loader/package.json | 43 ++++++++++++++ .../app-config => config-loader/src}/index.ts | 3 +- .../src/loader.ts} | 17 +++--- packages/config-loader/src/paths.ts | 57 +++++++++++++++++++ packages/config-loader/src/types.ts | 20 +++++++ 11 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 packages/config-loader/.eslintrc.js create mode 100644 packages/config-loader/README.md create mode 100644 packages/config-loader/package.json rename packages/{cli/src/lib/app-config => config-loader/src}/index.ts (86%) rename packages/{cli/src/lib/app-config/loaders.ts => config-loader/src/loader.ts} (79%) create mode 100644 packages/config-loader/src/paths.ts create mode 100644 packages/config-loader/src/types.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index 96c6261794..9cf60c0c4d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -30,6 +30,7 @@ }, "dependencies": { "@backstage/config": "^0.1.1-alpha.6", + "@backstage/config-loader": "^0.1.1-alpha.6", "@hot-loader/react-dom": "^16.13.0", "@lerna/package-graph": "^3.18.5", "@lerna/project": "^3.18.0", diff --git a/packages/cli/src/commands/app/build.ts b/packages/cli/src/commands/app/build.ts index fad3e6db13..d09b2abcdd 100644 --- a/packages/cli/src/commands/app/build.ts +++ b/packages/cli/src/commands/app/build.ts @@ -16,7 +16,7 @@ import { buildBundle } from '../../lib/bundler'; import { Command } from 'commander'; -import { loadConfig } from '../../lib/app-config'; +import { loadConfig } from '@backstage/config-loader'; export default async (cmd: Command) => { await buildBundle({ diff --git a/packages/cli/src/commands/app/serve.ts b/packages/cli/src/commands/app/serve.ts index 19dfd9a7be..5758aa2bf2 100644 --- a/packages/cli/src/commands/app/serve.ts +++ b/packages/cli/src/commands/app/serve.ts @@ -16,7 +16,7 @@ import { Command } from 'commander'; import { serveBundle } from '../../lib/bundler'; -import { loadConfig } from '../../lib/app-config'; +import { loadConfig } from '@backstage/config-loader'; export default async (cmd: Command) => { const waitForExit = await serveBundle({ diff --git a/packages/cli/src/commands/plugin/serve.ts b/packages/cli/src/commands/plugin/serve.ts index 174d1fe4af..9cc6cf55d0 100644 --- a/packages/cli/src/commands/plugin/serve.ts +++ b/packages/cli/src/commands/plugin/serve.ts @@ -16,7 +16,7 @@ import { Command } from 'commander'; import { serveBundle } from '../../lib/bundler'; -import { loadConfig } from '../../lib/app-config'; +import { loadConfig } from '@backstage/config-loader'; export default async (cmd: Command) => { const waitForExit = await serveBundle({ diff --git a/packages/config-loader/.eslintrc.js b/packages/config-loader/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/packages/config-loader/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; diff --git a/packages/config-loader/README.md b/packages/config-loader/README.md new file mode 100644 index 0000000000..595241e0d5 --- /dev/null +++ b/packages/config-loader/README.md @@ -0,0 +1,12 @@ +# @backstage/config-loader + +This package provides config loading functionality used by the backend, and CLI. + +## Installation + +Do not install this package directly, it is an internal package used by [@backstage/cli](https://www.npmjs.com/package/@backstage/cli), and [@backstage/backend-common](https://www.npmjs.com/package/@backstage/backend-common). Depend on either of those instead. + +## Documentation + +- [Backstage Readme](https://github.com/spotify/backstage/blob/master/README.md) +- [Backstage Documentation](https://github.com/spotify/backstage/blob/master/docs/README.md) diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json new file mode 100644 index 0000000000..558c91f529 --- /dev/null +++ b/packages/config-loader/package.json @@ -0,0 +1,43 @@ +{ + "name": "@backstage/config-loader", + "description": "Config loading functionality used by Backstage backend, and CLI", + "version": "0.1.1-alpha.6", + "private": false, + "publishConfig": { + "access": "public" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/spotify/backstage", + "directory": "packages/config-loader" + }, + "keywords": [ + "backstage" + ], + "license": "Apache-2.0", + "main": "dist/index.esm.js", + "main:src": "src/index.ts", + "types": "src/index.ts", + "scripts": { + "build": "backstage-cli plugin:build", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", + "clean": "backstage-cli clean" + }, + "dependencies": { + "@backstage/config": "^0.1.1-alpha.6", + "fs-extra": "^9.0.0", + "yaml": "^1.9.2" + }, + "devDependencies": { + "@backstage/cli": "^0.1.1-alpha.6", + "@types/jest": "^25.2.2", + "@types/node": "^12.0.0" + }, + "files": [ + "dist/**/*.{js,d.ts}" + ] +} diff --git a/packages/cli/src/lib/app-config/index.ts b/packages/config-loader/src/index.ts similarity index 86% rename from packages/cli/src/lib/app-config/index.ts rename to packages/config-loader/src/index.ts index 27b9f28e14..822fb53d04 100644 --- a/packages/cli/src/lib/app-config/index.ts +++ b/packages/config-loader/src/index.ts @@ -14,4 +14,5 @@ * limitations under the License. */ -export { loadConfig } from './loaders'; +export { loadConfig } from './loader'; +export type { LoadConfigOptions } from './types'; diff --git a/packages/cli/src/lib/app-config/loaders.ts b/packages/config-loader/src/loader.ts similarity index 79% rename from packages/cli/src/lib/app-config/loaders.ts rename to packages/config-loader/src/loader.ts index e6de9216d2..006d241e8a 100644 --- a/packages/cli/src/lib/app-config/loaders.ts +++ b/packages/config-loader/src/loader.ts @@ -16,20 +16,23 @@ import fs from 'fs-extra'; import yaml from 'yaml'; +import { resolve as resolvePath } from 'path'; import { AppConfig } from '@backstage/config'; -import { paths } from '../paths'; - -type LoadConfigOptions = { - // Config path, defaults to app-config.yaml in project root - configPath?: string; -}; +import { findRootPath } from './paths'; +import { LoadConfigOptions } from './types'; export async function loadConfig( options: LoadConfigOptions = {}, ): Promise { // TODO: We'll want this to be a bit more elaborate, probably adding configs for // specific env, and maybe local config for plugins. - const { configPath = paths.resolveTargetRoot('app-config.yaml') } = options; + let { configPath } = options; + if (!configPath) { + configPath = resolvePath( + findRootPath(fs.realpathSync(process.cwd())), + 'app-config.yaml', + ); + } try { const configYaml = await fs.readFile(configPath, 'utf8'); diff --git a/packages/config-loader/src/paths.ts b/packages/config-loader/src/paths.ts new file mode 100644 index 0000000000..d0e7e96e36 --- /dev/null +++ b/packages/config-loader/src/paths.ts @@ -0,0 +1,57 @@ +/* + * 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/types.ts b/packages/config-loader/src/types.ts new file mode 100644 index 0000000000..d25a2d3e8b --- /dev/null +++ b/packages/config-loader/src/types.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export type LoadConfigOptions = { + // Config path, defaults to app-config.yaml in project root + configPath?: string; +};