Merge pull request #2316 from feiming/scaffold

remove mono repo dependency from create-plugin
This commit is contained in:
Patrik Oldsberg
2020-09-21 15:21:43 +02:00
committed by GitHub
7 changed files with 61 additions and 30 deletions
+1 -1
View File
@@ -21,7 +21,7 @@
"docgen": "lerna run docgen",
"docker-build:app": "yarn workspace example-app build && docker build . -t spotify/backstage",
"docker-build": "yarn tsc && yarn workspace example-backend build-image",
"create-plugin": "backstage-cli create-plugin",
"create-plugin": "backstage-cli create-plugin --scope backstage --no-private",
"remove-plugin": "backstage-cli remove-plugin",
"release": "if [ \"$(git symbolic-ref --short HEAD)\" = master ]; then echo \"don't try to release master\"; exit 1; else lerna version --no-push --force-publish; fi",
"prettier:check": "prettier --check .",
@@ -21,6 +21,7 @@ import inquirer, { Answers, Question } from 'inquirer';
import { exec as execCb } from 'child_process';
import { resolve as resolvePath } from 'path';
import os from 'os';
import { Command } from 'commander';
import {
parseOwnerIds,
addCodeownersEntry,
@@ -32,12 +33,12 @@ import { version as backstageVersion } from '../../lib/version';
const exec = promisify(execCb);
async function checkExists(rootDir: string, id: string) {
await Task.forItem('checking', id, async () => {
const destination = resolvePath(rootDir, 'plugins', id);
async function checkExists(destination: string) {
await Task.forItem('checking', destination, async () => {
if (await fs.pathExists(destination)) {
const existing = chalk.cyan(destination.replace(`${rootDir}/`, ''));
const existing = chalk.cyan(
destination.replace(`${paths.targetRoot}/`, ''),
);
throw new Error(
`A plugin with the same name already exists: ${existing}\nPlease try again with a different plugin ID`,
);
@@ -86,10 +87,9 @@ export const addExportStatement = async (
export async function addPluginDependencyToApp(
rootDir: string,
pluginName: string,
pluginPackage: string,
versionStr: string,
) {
const pluginPackage = `@backstage/plugin-${pluginName}`;
const packageFilePath = 'packages/app/package.json';
const packageFile = resolvePath(rootDir, packageFilePath);
@@ -116,8 +116,11 @@ export async function addPluginDependencyToApp(
});
}
export async function addPluginToApp(rootDir: string, pluginName: string) {
const pluginPackage = `@backstage/plugin-${pluginName}`;
export async function addPluginToApp(
rootDir: string,
pluginName: string,
pluginPackage: string,
) {
const pluginNameCapitalized = pluginName
.split('-')
.map(name => capitalize(name))
@@ -175,7 +178,7 @@ export async function movePlugin(
});
}
export default async () => {
export default async (cmd: Command) => {
const codeownersPath = await getCodeownersFilePath(paths.targetRoot);
const questions: Question[] = [
@@ -221,20 +224,29 @@ export default async () => {
}
const answers: Answers = await inquirer.prompt(questions);
const name = cmd.scope
? `@${cmd.scope.replace(/^@/, '')}/plugin-${answers.id}`
: `plugin-${answers.id}`;
const npmRegistry = cmd.npmRegistry && cmd.scope ? cmd.npmRegistry : '';
const privatePackage = cmd.private === false ? false : true;
const isMonoRepo = await fs.pathExists(paths.resolveTargetRoot('lerna.json'));
const appPackage = paths.resolveTargetRoot('packages/app');
const templateDir = paths.resolveOwn('templates/default-plugin');
const tempDir = resolvePath(os.tmpdir(), answers.id);
const pluginDir = paths.resolveTargetRoot('plugins', answers.id);
const pluginDir = isMonoRepo
? paths.resolveTargetRoot('plugins', answers.id)
: paths.resolveTargetRoot(answers.id);
const ownerIds = parseOwnerIds(answers.owner);
const { version } = await fs.readJson(paths.resolveTargetRoot('lerna.json'));
const { version } = isMonoRepo
? await fs.readJson(paths.resolveTargetRoot('lerna.json'))
: { version: '0.1.0' };
Task.log();
Task.log('Creating the plugin...');
try {
Task.section('Checking if the plugin ID is available');
await checkExists(paths.targetRoot, answers.id);
await checkExists(pluginDir);
Task.section('Creating a temporary plugin directory');
await createTemporaryPluginFolder(tempDir);
@@ -244,6 +256,9 @@ export default async () => {
...answers,
version,
backstageVersion,
name,
privatePackage,
npmRegistry,
});
Task.section('Moving to final location');
@@ -254,10 +269,10 @@ export default async () => {
if (await fs.pathExists(appPackage)) {
Task.section('Adding plugin as dependency in app');
await addPluginDependencyToApp(paths.targetRoot, answers.id, version);
await addPluginDependencyToApp(paths.targetRoot, name, version);
Task.section('Import plugin in app');
await addPluginToApp(paths.targetRoot, answers.id);
await addPluginToApp(paths.targetRoot, answers.id, name);
}
if (ownerIds && ownerIds.length) {
@@ -269,11 +284,7 @@ export default async () => {
}
Task.log();
Task.log(
`🥇 Successfully created ${chalk.cyan(
`@backstage/plugin-${answers.id}`,
)}`,
);
Task.log(`🥇 Successfully created ${chalk.cyan(`${name}`)}`);
Task.log();
Task.exit();
} catch (error) {
+3
View File
@@ -62,6 +62,9 @@ export function registerCommands(program: CommanderStatic) {
program
.command('create-plugin')
.description('Creates a new plugin in the current repository')
.option('--scope <scope>', 'NPM scope')
.option('--npm-registry <URL>', 'NPM registry URL')
.option('--no-private', 'Public NPM Package')
.action(
lazy(() => import('./create-plugin/createPlugin').then(m => m.default)),
);
+14 -4
View File
@@ -30,6 +30,9 @@ import { version as backstageVersion } from '../../lib/version';
export type PluginData = {
id: string;
name: string;
privatePackage: string;
version: string;
npmRegistry: string;
};
const fileHandlers = [
@@ -62,11 +65,8 @@ export default async (cmd: Command) => {
promptFunc = yesPromptFunc;
}
const { version } = await fs.readJson(paths.resolveTargetRoot('lerna.json'));
const data = await readPluginData();
const templateFiles = await diffTemplateFiles('default-plugin', {
version,
backstageVersion,
...data,
});
@@ -77,9 +77,19 @@ export default async (cmd: Command) => {
// Reads templating data from the existing plugin
async function readPluginData(): Promise<PluginData> {
let name: string;
let privatePackage: string;
let version: string;
let npmRegistry: string;
try {
const pkg = require(paths.resolveTarget('package.json'));
name = pkg.name;
privatePackage = pkg.private;
version = pkg.version;
const scope = name.split('/')[0];
if (`${scope}:registry` in pkg.publishConfig) {
const registryURL = pkg.publishConfig[`${scope}:registry`];
npmRegistry = `"${scope}:registry" : "${registryURL}"`;
} else npmRegistry = '';
} catch (error) {
throw new Error(`Failed to read target package, ${error}`);
}
@@ -96,5 +106,5 @@ async function readPluginData(): Promise<PluginData> {
const id = pluginIdMatch[1];
return { id, name };
return { id, name, privatePackage, version, npmRegistry };
}
@@ -1,11 +1,14 @@
{
"name": "@backstage/plugin-{{id}}",
"name": "{{name}}",
"version": "{{version}}",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"private": true,
{{#if privatePackage}} "private": {{privatePackage}},
{{/if}}
"publishConfig": {
{{#if npmRegistry}} "registry": "{{npmRegistry}}",
{{/if}}
"access": "public",
"main": "dist/index.esm.js",
"types": "dist/index.d.ts"
@@ -16,7 +16,7 @@
"test:all": "lerna run test -- --coverage",
"lint": "lerna run lint --since origin/master --",
"lint:all": "lerna run lint --",
"create-plugin": "backstage-cli create-plugin",
"create-plugin": "backstage-cli create-plugin --scope backstage --no-private",
"remove-plugin": "backstage-cli remove-plugin"
},
"workspaces": {
+5 -1
View File
@@ -81,7 +81,11 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) {
const path = paths.resolveOwnRoot(pkgJsonPath);
const pkgTemplate = await fs.readFile(path, 'utf8');
const { dependencies = {}, devDependencies = {} } = JSON.parse(
handlebars.compile(pkgTemplate)({ version: '0.0.0' }),
handlebars.compile(pkgTemplate)({
version: '0.0.0',
privatePackage: true,
scopeName: '@backstage',
}),
);
Array<string>()