create-app: use cli-common to discover paths and import version directly

This commit is contained in:
Patrik Oldsberg
2020-08-03 18:18:51 +02:00
parent 2f76581b60
commit 0a09976548
5 changed files with 7 additions and 180 deletions
+1
View File
@@ -25,6 +25,7 @@
"lint": "backstage-cli lint"
},
"dependencies": {
"@backstage/cli-common": "^0.1.1-alpha.16",
"commander": "^4.1.1",
"chalk": "^4.0.0",
"fs-extra": "^9.0.0",
+4 -2
View File
@@ -21,10 +21,10 @@ import { Command } from 'commander';
import inquirer, { Answers, Question } from 'inquirer';
import { exec as execCb } from 'child_process';
import { resolve as resolvePath } from 'path';
import { findPaths } from '@backstage/cli-common';
import { version } from '../package.json';
import os from 'os';
import { Task, templatingTask } from './lib/tasks';
import { paths } from './lib/paths';
import { version } from './lib/version';
const exec = promisify(execCb);
@@ -88,6 +88,8 @@ async function moveApp(tempDir: string, destination: string, id: string) {
}
export default async (cmd: Command): Promise<void> => {
const paths = findPaths(__dirname);
const questions: Question[] = [
{
type: 'input',
+2 -2
View File
@@ -17,7 +17,7 @@
import program from 'commander';
import chalk from 'chalk';
import { exitWithError } from './lib/errors';
import { version } from './lib/version';
import { version } from '../package.json';
import createApp from './createApp';
const main = (argv: string[]) => {
@@ -29,7 +29,7 @@ const main = (argv: string[]) => {
'--skip-install',
'Skip the install and builds steps after creating the app',
)
.action(createApp)
.action(createApp);
if (!process.argv.slice(2).length) {
program.outputHelp(chalk.yellow);
-150
View File
@@ -1,150 +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';
export type ResolveFunc = (...paths: string[]) => string;
// Common paths and resolve functions used by the cli.
// Currently assumes it is being executed within a monorepo.
export type Paths = {
// Root dir of the cli itself, containing package.json
ownDir: string;
// Monorepo root dir of the cli itself. Only accessible when running inside Backstage repo.
ownRoot: string;
// The location of the app that the cli is being executed in
targetDir: string;
// The monorepo root package of the app that the cli is being executed in.
targetRoot: string;
// Resolve a path relative to own repo
resolveOwn: ResolveFunc;
// Resolve a path relative to own monorepo root. Only accessible when running inside Backstage repo.
resolveOwnRoot: ResolveFunc;
// Resolve a path relative to the app
resolveTarget: ResolveFunc;
// Resolve a path relative to the app repo root
resolveTargetRoot: ResolveFunc;
};
// Looks for a package.json that has name: "root" to identify the root of the monorepo
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}`,
);
}
// Finds the root of the cli package itself
export function findOwnDir() {
// Known relative locations of package in dist/dev
const pathDist = '..';
const pathDev = '../..';
// Check the closest dir first
const pkgInDist = resolvePath(__dirname, pathDist, 'package.json');
const isDist = fs.pathExistsSync(pkgInDist);
const path = isDist ? pathDist : pathDev;
return resolvePath(__dirname, path);
}
// Finds the root of the monorepo that the cli exists in. Only accessible when running inside Backstage repo.
export function findOwnRootPath(ownDir: string) {
const isLocal = fs.pathExistsSync(resolvePath(ownDir, 'src'));
if (!isLocal) {
throw new Error(
'Tried to access monorepo package root dir outside of Backstage repository',
);
}
return resolvePath(ownDir, '../..');
}
export function findPaths(): Paths {
const ownDir = findOwnDir();
const targetDir = fs.realpathSync(process.cwd());
// Lazy load this as it will throw an error if we're not inside the Backstage repo.
let ownRoot = '';
const getOwnRoot = () => {
if (!ownRoot) {
ownRoot = findOwnRootPath(ownDir);
}
return ownRoot;
};
// We're not always running in a monorepo, so we lazy init this to only crash commands
// that require a monorepo when we're not in one.
let targetRoot = '';
const getTargetRoot = () => {
if (!targetRoot) {
targetRoot = findRootPath(targetDir);
}
return targetRoot;
};
return {
ownDir,
get ownRoot() {
return getOwnRoot();
},
targetDir,
get targetRoot() {
return getTargetRoot();
},
resolveOwn: (...paths) => resolvePath(ownDir, ...paths),
resolveOwnRoot: (...paths) => resolvePath(getOwnRoot(), ...paths),
resolveTarget: (...paths) => resolvePath(targetDir, ...paths),
resolveTargetRoot: (...paths) => resolvePath(getTargetRoot(), ...paths),
};
}
export const paths = findPaths();
-26
View File
@@ -1,26 +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 { paths } from './paths';
export function findVersion() {
const pkgContent = fs.readFileSync(paths.resolveOwn('package.json'), 'utf8');
return JSON.parse(pkgContent).version;
}
export const version = findVersion();
export const isDev = fs.pathExistsSync(paths.resolveOwn('src'));