cli: add experimental add-deps command

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2022-03-11 18:03:32 +01:00
parent 66ffb38685
commit 6ad0c45648
3 changed files with 154 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Added an experimental `add-deps` command which adds missing monorepo dependencies to the target package.`
+142
View File
@@ -0,0 +1,142 @@
/*
* Copyright 2020 The Backstage Authors
*
* 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 { paths } from '../lib/paths';
import { ESLint } from 'eslint';
import { join as joinPath, basename } from 'path';
import fs from 'fs-extra';
import { isChildPath } from '@backstage/cli-common';
import { PackageGraph } from '../lib/monorepo';
function isTestPath(filePath: string) {
if (!isChildPath(joinPath(paths.targetDir, 'src'), filePath)) {
return true;
}
const name = basename(filePath);
return (
name.startsWith('setupTests.') ||
name.includes('.test.') ||
name.includes('.stories.')
);
}
export async function command() {
const pkgJsonPath = paths.resolveTarget('package.json');
const pkg = await fs.readJson(pkgJsonPath);
if (pkg.workspaces) {
throw new Error(
'Adding dependencies to the workspace root is not supported',
);
}
const packages = await PackageGraph.listTargetPackages();
const localPackageVersions = new Map(
packages.map(p => [p.packageJson.name, p.packageJson.version]),
);
const eslint = new ESLint({
cwd: paths.targetDir,
overrideConfig: {
plugins: ['monorepo'],
rules: {
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: [
`!${joinPath(paths.targetDir, 'src/**')}`,
joinPath(paths.targetDir, 'src/**/*.test.*'),
joinPath(paths.targetDir, 'src/**/*.stories.*'),
joinPath(paths.targetDir, 'src/setupTests.*'),
],
optionalDependencies: true,
peerDependencies: true,
bundledDependencies: true,
},
],
},
},
extensions: ['jsx', 'ts', 'tsx', 'mjs', 'cjs'],
});
const results = await eslint.lintFiles(['.']);
const addedDeps = new Set<string>();
const addedDevDeps = new Set<string>();
const removedDevDeps = new Set<string>();
for (const result of results) {
for (const message of result.messages) {
// Just in case
if (message.ruleId !== 'import/no-extraneous-dependencies') {
continue;
}
const match = message.message.match(/^'([^']*)' should be listed/);
if (!match) {
continue;
}
const packageName = match[1];
if (!localPackageVersions.has(packageName)) {
continue;
}
if (message.message.endsWith('not devDependencies.')) {
addedDeps.add(packageName);
removedDevDeps.add(packageName);
} else if (isTestPath(result.filePath)) {
addedDevDeps.add(packageName);
} else {
addedDeps.add(packageName);
}
}
}
if (addedDeps.size || addedDevDeps.size || removedDevDeps.size) {
for (const name of addedDeps) {
if (!pkg.dependencies) {
pkg.dependencies = {};
}
pkg.dependencies[name] = `^${localPackageVersions.get(name)}`;
}
for (const name of addedDevDeps) {
if (!pkg.devDependencies) {
pkg.devDependencies = {};
}
pkg.devDependencies[name] = `^${localPackageVersions.get(name)}`;
}
for (const name of removedDevDeps) {
delete pkg.devDependencies[name];
}
if (Object.keys(pkg.devDependencies).length === 0) {
delete pkg.devDependencies;
}
if (pkg.dependencies) {
pkg.dependencies = Object.fromEntries(
Object.entries(pkg.dependencies).sort(([a], [b]) => a.localeCompare(b)),
);
}
if (pkg.devDependencies) {
pkg.devDependencies = Object.fromEntries(
Object.entries(pkg.devDependencies).sort(([a], [b]) =>
a.localeCompare(b),
),
);
}
await fs.writeJson(pkgJsonPath, pkg, { spaces: 2 });
}
}
+7
View File
@@ -386,6 +386,13 @@ export function registerCommands(program: CommanderStatic) {
.description('Check Backstage package versioning')
.action(lazy(() => import('./versions/lint').then(m => m.default)));
program
.command('add-deps', { hidden: true })
.description(
'Add missing monorepo dependencies to package.json [EXPERIMENTAL]',
)
.action(lazy(() => import('./add-deps').then(m => m.command)));
// TODO(Rugvip): Deprecate in favor of package variant
program
.command('prepack')