From 231c991fe064e836a1459e3991799028e43a5165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Sun, 22 Mar 2020 20:59:53 +0100 Subject: [PATCH] Address review comments --- .../commands/create-plugin/createPlugin.ts | 27 ++++++--- .../commands/create-plugin/lib/codeowners.ts | 59 ++++++++++++++----- scripts/cli-e2e-test.js | 2 + 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/packages/cli/src/commands/create-plugin/createPlugin.ts b/packages/cli/src/commands/create-plugin/createPlugin.ts index bd76ef6d21..112377cbda 100644 --- a/packages/cli/src/commands/create-plugin/createPlugin.ts +++ b/packages/cli/src/commands/create-plugin/createPlugin.ts @@ -25,7 +25,11 @@ import { resolve as resolvePath } from 'path'; import { realpathSync, existsSync } from 'fs'; import os from 'os'; import ora from 'ora'; -import { parseOwnerIds, addCodeownersEntry } from './lib/codeowners'; +import { + parseOwnerIds, + addCodeownersEntry, + getCodeownersFilePath, +} from './lib/codeowners'; const MARKER_SUCCESS = chalk.green(` ✔︎\n`); const MARKER_FAILURE = chalk.red(` ✘\n`); @@ -328,6 +332,9 @@ export const movePlugin = ( }; const createPlugin = async () => { + const rootDir = realpathSync(process.cwd()); + const codeownersPath = await getCodeownersFilePath(rootDir); + const questions: Question[] = [ { type: 'input', @@ -344,7 +351,10 @@ const createPlugin = async () => { return true; }, }, - { + ]; + + if (codeownersPath) { + questions.push({ type: 'input', name: 'owner', message: chalk.blue( @@ -364,14 +374,13 @@ const createPlugin = async () => { return true; }, - }, - ]; + }); + } + const answers: Answers = await inquirer.prompt(questions); - const rootDir = realpathSync(process.cwd()); - const codeownersPath = path.join(rootDir, '.github', 'CODEOWNERS'); const appPackage = resolvePath(rootDir, 'packages', 'app'); - const cliPackage = resolvePath(__dirname, '..', '..'); + const cliPackage = resolvePath(__dirname, '..', '..', '..'); const templateFolder = resolvePath(cliPackage, 'templates', 'default-plugin'); const tempDir = path.join(os.tmpdir(), answers.id); const pluginDir = path.join(rootDir, 'plugins', answers.id); @@ -394,8 +403,8 @@ const createPlugin = async () => { } if (ownerIds && ownerIds.length) { - addCodeownersEntry( - codeownersPath, + await addCodeownersEntry( + codeownersPath!, path.join('plugins', answers.id), ownerIds, ); diff --git a/packages/cli/src/commands/create-plugin/lib/codeowners.ts b/packages/cli/src/commands/create-plugin/lib/codeowners.ts index 96e9a2f76c..1ffa640f04 100644 --- a/packages/cli/src/commands/create-plugin/lib/codeowners.ts +++ b/packages/cli/src/commands/create-plugin/lib/codeowners.ts @@ -15,10 +15,35 @@ */ import fs from 'fs-extra'; +import path from 'path'; const TEAM_ID_RE = /^@[-\w]+\/[-\w]+$/; const USER_ID_RE = /^@[-\w]+$/; -const EMAIL_RE = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; +const EMAIL_RE = /^[^@]+@[-.\w]+\.[-\w]+$/i; + +type CodeownersEntry = { + ownedPath: string; + ownerIds: string[]; +}; + +export async function getCodeownersFilePath( + rootDir: string, +): Promise { + const paths = [ + path.join(rootDir, '.github', 'CODEOWNERS'), + path.join(rootDir, '.gitlab', 'CODEOWNERS'), + path.join(rootDir, 'docs', 'CODEOWNERS'), + path.join(rootDir, 'CODEOWNERS'), + ]; + + for (const p of paths) { + if (await fs.pathExists(p)) { + return p; + } + } + + return undefined; +} export function isValidSingleOwnerId(id: string): boolean { if (!id || typeof id !== 'string') { @@ -43,12 +68,12 @@ export function parseOwnerIds( return ids; } -export function addCodeownersEntry( +export async function addCodeownersEntry( codeownersFilePath: string, ownedPath: string, ownerIds: string[], -): void { - const allLines = fs.readFileSync(codeownersFilePath, 'utf8').split('\n'); +): Promise { + const allLines = (await fs.readFile(codeownersFilePath, 'utf8')).split('\n'); // Only keep comments from the top of the file const commentLines = []; @@ -59,30 +84,34 @@ export function addCodeownersEntry( commentLines.push(line); } - const oldDeclarationEntries = allLines + const oldDeclarationEntries: CodeownersEntry[] = allLines .filter(line => line[0] !== '#') .map(line => line.split(/\s+/).filter(Boolean)) - .filter(items => items.length >= 2); + .filter(tokens => tokens.length >= 2) + .map(tokens => ({ + ownedPath: tokens[0], + ownerIds: tokens.slice(1), + })); const newDeclarationEntries = oldDeclarationEntries - .filter(items => items[0] !== '*') - .concat([[ownedPath, ...ownerIds]]) - .sort((l1, l2) => l1[0].localeCompare(l2[0])) - .concat([['*', '@spotify/backstage-core']]); + .filter(entry => entry.ownedPath !== '*') + .concat([{ ownedPath, ownerIds }]) + .sort((l1, l2) => l1.ownedPath.localeCompare(l2.ownedPath)) + .concat([{ ownedPath: '*', ownerIds: ['@spotify/backstage-core'] }]); // Calculate longest path to be able to align entries nicely const longestOwnedPath = newDeclarationEntries.reduce( - (length, entry) => Math.max(length, entry[0].length), + (length, entry) => Math.max(length, entry.ownedPath.length), 0, ); const newDeclarationLines = newDeclarationEntries.map(entry => { - const entryPath = entry[0] + ' '.repeat(longestOwnedPath - entry[0].length); - const entryOwners = entry.slice(1); - return [entryPath, ...entryOwners].join(' '); + const entryPath = + entry.ownedPath + ' '.repeat(longestOwnedPath - entry.ownedPath.length); + return [entryPath, ...entry.ownerIds].join(' '); }); const newLines = [...commentLines, '', ...newDeclarationLines, '']; - fs.writeFileSync(codeownersFilePath, newLines.join('\n'), 'utf8'); + await fs.writeFile(codeownersFilePath, newLines.join('\n'), 'utf8'); } diff --git a/scripts/cli-e2e-test.js b/scripts/cli-e2e-test.js index 8d2535fdc3..10be71b1c4 100644 --- a/scripts/cli-e2e-test.js +++ b/scripts/cli-e2e-test.js @@ -37,6 +37,8 @@ async function main() { const createPlugin = spawnPiped(['yarn', 'create-plugin']); createPlugin.stdin.write('test-plugin\n'); + await new Promise(resolve => setTimeout(resolve, 2000)); + createPlugin.stdin.write('@someuser\n'); print('Waiting for plugin create script to be done'); await waitForExit(createPlugin);