cli: make create-plugin prefer version ranges that are already in the lockfile

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2021-09-23 19:42:18 +02:00
parent 07bd9068b4
commit 2a6c393c06
7 changed files with 81 additions and 44 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
The `create-plugin` command now prefers dependency versions ranges that are already in the lockfile.
@@ -30,8 +30,9 @@ import {
getCodeownersFilePath,
} from '../../lib/codeowners';
import { paths } from '../../lib/paths';
import { packageVersions } from '../../lib/version';
import { Task, templatingTask } from '../../lib/tasks';
import { Lockfile } from '../../lib/versioning';
import { createPackageVersionProvider } from '../../lib/version';
const exec = promisify(execCb);
@@ -262,6 +263,13 @@ export default async (cmd: Command) => {
? await fs.readJson(paths.resolveTargetRoot('lerna.json'))
: { version: '0.1.0' };
let lockfile: Lockfile | undefined;
try {
lockfile = await Lockfile.load(paths.resolveTargetRoot('yarn.lock'));
} catch (error) {
console.warn(`No yarn.lock available, ${error}`);
}
Task.log();
Task.log('Creating the plugin...');
@@ -288,7 +296,7 @@ export default async (cmd: Command) => {
privatePackage,
npmRegistry,
},
packageVersions,
createPackageVersionProvider(lockfile),
);
Task.section('Moving to final location');
+3 -3
View File
@@ -34,7 +34,7 @@ describe('templatingTask', () => {
// Files content
const testFileContent = 'testing';
const testVersionFileContent =
"version: {{pluginVersion}} {{version 'mock-pkg'}}";
"version: {{pluginVersion}} {{versionQuery 'mock-pkg'}}";
mockFs({
[tmplDir]: {
@@ -52,7 +52,7 @@ describe('templatingTask', () => {
{
pluginVersion: '0.0.0',
},
{ 'mock-pkg': '0.1.2' },
() => '^0.1.2',
);
await expect(
@@ -60,6 +60,6 @@ describe('templatingTask', () => {
).resolves.toBe(testFileContent);
await expect(
fs.readFile(resolvePath(destDir, 'sub/version.txt'), 'utf8'),
).resolves.toBe('version: 0.0.0 0.1.2');
).resolves.toBe('version: 0.0.0 ^0.1.2');
});
});
+6 -6
View File
@@ -69,7 +69,7 @@ export async function templatingTask(
templateDir: string,
destinationDir: string,
context: any,
versions: { [name: string]: string },
versionProvider: (name: string, versionHint?: string) => string,
) {
const files = await recursive(templateDir).catch(error => {
throw new Error(`Failed to read template directory: ${error.message}`);
@@ -90,11 +90,11 @@ export async function templatingTask(
{ name: basename(destination), ...context },
{
helpers: {
version(name: string) {
if (versions[name]) {
return versions[name];
}
throw new Error(`No version available for package ${name}`);
versionQuery(name: string, versionHint: string | unknown) {
return versionProvider(
name,
typeof versionHint === 'string' ? versionHint : undefined,
);
},
},
},
+25 -1
View File
@@ -15,7 +15,9 @@
*/
import fs from 'fs-extra';
import semver from 'semver';
import { paths } from './paths';
import { Lockfile } from './versioning';
/* eslint-disable import/no-extraneous-dependencies,monorepo/no-internal-import */
/*
@@ -41,7 +43,7 @@ import { version as devUtils } from '@backstage/dev-utils/package.json';
import { version as testUtils } from '@backstage/test-utils/package.json';
import { version as theme } from '@backstage/theme/package.json';
export const packageVersions = {
export const packageVersions: Record<string, string> = {
'@backstage/backend-common': backendCommon,
'@backstage/cli': cli,
'@backstage/config': config,
@@ -60,3 +62,25 @@ export function findVersion() {
export const version = findVersion();
export const isDev = fs.pathExistsSync(paths.resolveOwn('src'));
export function createPackageVersionProvider(lockfile?: Lockfile) {
return (name: string, versionHint?: string) => {
const targetVersion = versionHint || packageVersions[name];
if (!targetVersion) {
throw new Error(`No version available for package ${name}`);
}
const lockfileEntries = lockfile?.get(name);
if (
name.startsWith('@types/') &&
lockfileEntries?.some(entry => entry.range === '*')
) {
return '*';
}
const validRanges = lockfileEntries?.filter(entry =>
semver.satisfies(targetVersion, entry.range),
);
const highestRange = validRanges?.slice(-1)[0];
return highestRange?.range ?? `^${targetVersion}`;
};
}
@@ -23,20 +23,20 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^{{version '@backstage/backend-common'}}",
"@backstage/config": "^{{version '@backstage/config'}}",
"@types/express": "^4.17.6",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"winston": "^3.2.1",
"cross-fetch": "^3.0.6",
"yn": "^4.0.0"
"@backstage/backend-common": "{{versionQuery '@backstage/backend-common'}}",
"@backstage/config": "{{versionQuery '@backstage/config'}}",
"@types/express": "{{versionQuery '@types/express' '4.17.6'}}",
"express": "{{versionQuery 'express' '4.17.1'}}",
"express-promise-router": "{{versionQuery 'express-promise-router' '4.1.0'}}",
"winston": "{{versionQuery 'winston' '3.2.1'}}",
"cross-fetch": "{{versionQuery 'cross-fetch' '3.0.6'}}",
"yn": "{{versionQuery 'yn' '4.0.0'}}"
},
"devDependencies": {
"@backstage/cli": "^{{version '@backstage/cli'}}",
"@types/supertest": "^2.0.8",
"supertest": "^4.0.2",
"msw": "^0.29.0"
"@backstage/cli": "{{versionQuery '@backstage/cli'}}",
"@types/supertest": "{{versionQuery '@types/supertest' '2.0.8'}}",
"supertest": "{{versionQuery 'supertest' '4.0.2'}}",
"msw": "{{versionQuery 'msw' '0.29.0'}}"
},
"files": [
"dist"
@@ -24,28 +24,28 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/core-components": "^{{version '@backstage/core-components'}}",
"@backstage/core-plugin-api": "^{{version '@backstage/core-plugin-api'}}",
"@backstage/theme": "^{{version '@backstage/theme'}}",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-use": "^17.2.4"
"@backstage/core-components": "{{versionQuery '@backstage/core-components'}}",
"@backstage/core-plugin-api": "{{versionQuery '@backstage/core-plugin-api'}}",
"@backstage/theme": "{{versionQuery '@backstage/theme'}}",
"@material-ui/core": "{{versionQuery '@material-ui/core' '4.12.2'}}",
"@material-ui/icons": "{{versionQuery '@material-ui/icons' '4.9.1'}}",
"@material-ui/lab": "4{{versionQuery '@material-ui/lab' '.0.0-alpha.57'}}",
"react": "{{versionQuery 'react' '16.13.1'}}",
"react-dom": "{{versionQuery 'react-dom' '16.13.1'}}",
"react-use": "{{versionQuery 'react-use' '17.2.4'}}"
},
"devDependencies": {
"@backstage/cli": "^{{version '@backstage/cli'}}",
"@backstage/core-app-api": "^{{version '@backstage/core-app-api'}}",
"@backstage/dev-utils": "^{{version '@backstage/dev-utils'}}",
"@backstage/test-utils": "^{{version '@backstage/test-utils'}}",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
"@types/jest": "^26.0.7",
"@types/node": "^14.14.32",
"msw": "^0.29.0",
"cross-fetch": "^3.0.6"
"@backstage/cli": "{{versionQuery '@backstage/cli'}}",
"@backstage/core-app-api": "{{versionQuery '@backstage/core-app-api'}}",
"@backstage/dev-utils": "{{versionQuery '@backstage/dev-utils'}}",
"@backstage/test-utils": "{{versionQuery '@backstage/test-utils'}}",
"@testing-library/jest-dom": "{{versionQuery '@testing-library/jest-dom' '5.10.1'}}",
"@testing-library/react": "{{versionQuery '@testing-library/react' '11.2.5'}}",
"@testing-library/user-event": "{{versionQuery '@testing-library/user-event' '13.1.8'}}",
"@types/jest": "{{versionQuery '@types/jest' '26.0.7'}}",
"@types/node": "{{versionQuery '@types/node' '14.14.32'}}",
"msw": "{{versionQuery 'msw' '0.29.0'}}",
"cross-fetch": "{{versionQuery 'cross-fetch' '3.0.6'}}"
},
"files": [
"dist"