From 97ffd7ec18a737ac93a5765e6da42f71f4a87de4 Mon Sep 17 00:00:00 2001 From: MT Lewis Date: Tue, 16 Apr 2024 21:45:07 +0100 Subject: [PATCH] yarn-plugin: replace backstage:^ with ^ ranges when packing Signed-off-by: MT Lewis --- .../src/handlers/beforeWorkspacePacking.ts | 25 ++++++--- .../src/resolver/BackstageResolver.ts | 6 +-- packages/yarn-plugin/src/util.ts | 51 ++++++++----------- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.ts b/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.ts index a98e8270a1..e9f46a6159 100644 --- a/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.ts +++ b/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.ts @@ -15,7 +15,7 @@ */ import { Descriptor, Workspace, structUtils } from '@yarnpkg/core'; -import { inferPackageVersion } from '../util'; +import { getCurrentBackstageVersion, getPackageVersion } from '../util'; import { PROTOCOL } from '../constants'; const getFinalDependencyType = ( @@ -43,21 +43,34 @@ export const beforeWorkspacePacking = async ( 'devDependencies', 'peerDependencies', ] as const) { + const backstageVersion = getCurrentBackstageVersion(); + const entries = Array.from( workspace.manifest.getForScope(dependencyType).values(), - ).filter(descriptor => descriptor.range === `${PROTOCOL}^`); + ).filter(descriptor => descriptor.range.startsWith(PROTOCOL)); for (const descriptor of entries) { + const ident = structUtils.stringifyIdent(descriptor); + const range = structUtils.parseRange(descriptor.range); + + if (range.selector !== '^') { + throw new Error( + `Unexpected version range "${descriptor.range}" for dependency on "${ident}"`, + ); + } + const finalDependencyType = getFinalDependencyType( dependencyType, descriptor, workspace, ); - const ident = structUtils.stringifyIdent(descriptor); - rawManifest[finalDependencyType][ident] = await inferPackageVersion( - descriptor, - ); + rawManifest[finalDependencyType][ident] = `^${await getPackageVersion( + structUtils.makeDescriptor( + descriptor, + `${PROTOCOL}${backstageVersion}`, + ), + )}`; } } }; diff --git a/packages/yarn-plugin/src/resolver/BackstageResolver.ts b/packages/yarn-plugin/src/resolver/BackstageResolver.ts index 61fbdab58e..fa51ceb880 100644 --- a/packages/yarn-plugin/src/resolver/BackstageResolver.ts +++ b/packages/yarn-plugin/src/resolver/BackstageResolver.ts @@ -22,7 +22,7 @@ import { Resolver, } from '@yarnpkg/core'; import { PROTOCOL } from '../constants'; -import { inferBackstageVersion, inferPackageVersion } from '../util'; +import { getCurrentBackstageVersion, getPackageVersion } from '../util'; export class BackstageResolver implements Resolver { static protocol = PROTOCOL; @@ -35,7 +35,7 @@ export class BackstageResolver implements Resolver { bindDescriptor(descriptor: Descriptor): Descriptor { return structUtils.makeDescriptor( descriptor, - `${PROTOCOL}${inferBackstageVersion(descriptor)}`, + `${PROTOCOL}${getCurrentBackstageVersion()}`, ); } @@ -43,7 +43,7 @@ export class BackstageResolver implements Resolver { return [ structUtils.makeLocator( descriptor, - `npm:${await inferPackageVersion(descriptor)}`, + `npm:${await getPackageVersion(descriptor)}`, ), ]; } diff --git a/packages/yarn-plugin/src/util.ts b/packages/yarn-plugin/src/util.ts index ae11019c66..3e4e795c89 100644 --- a/packages/yarn-plugin/src/util.ts +++ b/packages/yarn-plugin/src/util.ts @@ -14,49 +14,40 @@ * limitations under the License. */ -import { Descriptor, structUtils } from '@yarnpkg/core'; import { npath, xfs } from '@yarnpkg/fslib'; import { valid as semverValid } from 'semver'; import { getManifestByVersion } from '@backstage/release-manifests'; +import { Descriptor, structUtils } from '@yarnpkg/core'; import { PROTOCOL } from './constants'; -export const inferBackstageVersion = (descriptor: Descriptor) => { +export const getCurrentBackstageVersion = () => { + const backstageJson = xfs.readJsonSync( + npath.toPortablePath('./backstage.json'), + ); + + const backstageVersion = semverValid(backstageJson.version); + + if (backstageVersion === null) { + throw new Error('Valid version string not found in backstage.json'); + } + + return backstageVersion; +}; + +export const getPackageVersion = async (descriptor: Descriptor) => { + const ident = structUtils.stringifyIdent(descriptor); const range = structUtils.parseRange(descriptor.range); if (range.protocol !== PROTOCOL) { - throw new Error( - `inferBackstageVersion called with unexpected protocol ${range.protocol}`, - ); + throw new Error(`Unexpected ${range.protocol} range when packing`); } - let selector = range.selector; - - // For backstage:^ we look up the version from backstage.json - if (selector === `^`) { - const backstageJson = xfs.readJsonSync( - npath.toPortablePath('./backstage.json'), - ); - - selector = backstageJson.version; + if (!semverValid(range.selector)) { + throw new Error(`Missing backstage version in range ${descriptor.range}`); } - if (!semverValid(selector)) { - throw new Error( - `Invalid "backstage:" version string found for ${structUtils.stringifyIdent( - descriptor, - )}. Version must be either "backstage:*" or "backstage:", where version is a single Backstage release version.`, - ); - } - - return selector; -}; - -export const inferPackageVersion = async (descriptor: Descriptor) => { - const ident = structUtils.stringifyIdent(descriptor); - const backstageVersion = inferBackstageVersion(descriptor); - const manifest = await getManifestByVersion({ - version: backstageVersion, + version: range.selector, }); const manifestEntry = manifest.packages.find(