cli: add versions:lint command

This commit is contained in:
Patrik Oldsberg
2020-11-22 15:58:28 +01:00
parent 4c64272137
commit 46a20ad22f
2 changed files with 120 additions and 0 deletions
+6
View File
@@ -154,6 +154,12 @@ export function registerCommands(program: CommanderStatic) {
)
.action(lazy(() => import('./config/validate').then(m => m.default)));
program
.command('versions:lint')
.option('--fix', 'Fix any auto-fixable versioning problems')
.description('Lint Backstage package versioning')
.action(lazy(() => import('./versions/lint').then(m => m.default)));
program
.command('prepack')
.description('Prepares a package for packaging before publishing')
+114
View File
@@ -0,0 +1,114 @@
/*
* 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 { Command } from 'commander';
import { Lockfile } from '../../lib/versioning';
import { paths } from '../../lib/paths';
import partition from 'lodash/partition';
// Packages that we try to avoid duplicates for
const INCLUDED = [/^@backstage\//];
// Packages that are not allowed to have any duplicates
const FORBID_DUPLICATES = [
/^@backstage\/core$/,
/^@backstage\/core-api$/,
/^@backstage\/plugin-/,
];
export default async (cmd: Command) => {
const fix = Boolean(cmd.fix);
let success = true;
const lockfilePath = paths.resolveTargetRoot('yarn.lock');
const lockfile = await Lockfile.load(lockfilePath);
const result = lockfile.analyze({
filter: name => INCLUDED.some(pattern => pattern.test(name)),
});
logArray(
result.invalidRanges,
"The following packages versions are invalid and can't be analyzed:",
e => ` ${e.name} @ ${e.range}`,
);
if (fix) {
lockfile.replaceVersions(result.newVersions);
await fs.writeFile(lockfilePath, lockfile.toString(), 'utf8');
} else {
const [
newVersionsForbidden,
newVersionsAllowed,
] = partition(result.newVersions, ({ name }) =>
FORBID_DUPLICATES.some(pattern => pattern.test(name)),
);
if (newVersionsForbidden.length && !fix) {
success = false;
}
logArray(
newVersionsForbidden,
'The following packages must be deduplicated, this can be done automatically with --fix',
e =>
` ${e.name} @ ${e.range} bumped from ${e.oldVersion} to ${e.newVersion}`,
);
logArray(
newVersionsAllowed,
'The following packages can be deduplicated, this can be done automatically with --fix',
e =>
` ${e.name} @ ${e.range} bumped from ${e.oldVersion} to ${e.newVersion}`,
);
}
const [newRangesForbidden, newRangesAllowed] = partition(
result.newRanges,
({ name }) => FORBID_DUPLICATES.some(pattern => pattern.test(name)),
);
if (newRangesForbidden.length) {
success = false;
}
logArray(
newRangesForbidden,
'The following packages must be deduplicated by updating dependencies in package.json',
e => ` ${e.name} @ ${e.oldRange} should be changed to ${e.newRange}`,
);
logArray(
newRangesAllowed,
'The following packages can be deduplicated by updating dependencies in package.json',
e => ` ${e.name} @ ${e.oldRange} should be changed to ${e.newRange}`,
);
if (!success) {
throw new Error('Failed versioning check');
}
};
function logArray<T>(arr: T[], header: string, each: (item: T) => void) {
if (arr.length === 0) {
return;
}
console.log(header);
console.log();
for (const e of arr) {
console.log(each(e));
}
console.log();
}