Merge pull request #24459 from backstage/backstage-cli-handle-yarn-plugin
versions:bump: handle `backstage:^` versions
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Add support for `backstage:^` version ranges to versions:bump when using the experimental yarn plugin
|
||||
@@ -25,6 +25,8 @@ import chalk from 'chalk';
|
||||
import ora from 'ora';
|
||||
import semver from 'semver';
|
||||
import { OptionValues } from 'commander';
|
||||
import yaml from 'yaml';
|
||||
import z from 'zod';
|
||||
import { isError, NotFoundError } from '@backstage/errors';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { run } from '../../lib/run';
|
||||
@@ -76,6 +78,8 @@ type PkgVersionInfo = {
|
||||
export default async (opts: OptionValues) => {
|
||||
const lockfilePath = paths.resolveTargetRoot('yarn.lock');
|
||||
const lockfile = await Lockfile.load(lockfilePath);
|
||||
const hasYarnPlugin = await getHasYarnPlugin();
|
||||
|
||||
let pattern = opts.pattern;
|
||||
|
||||
if (!pattern) {
|
||||
@@ -177,12 +181,34 @@ export default async (opts: OptionValues) => {
|
||||
for (const depType of DEP_TYPES) {
|
||||
if (depType in pkgJson && dep.name in pkgJson[depType]) {
|
||||
const oldRange = pkgJson[depType][dep.name];
|
||||
pkgJson[depType][dep.name] = dep.range;
|
||||
|
||||
// backstage:^ are written to the lockfile as
|
||||
// backstage:<backstage-version>, so that updates to
|
||||
// backstage.json can be detected during yarn install. In order to
|
||||
// locate the corresponding lockfile entry for "backstage:^"
|
||||
// versions, we need to perform the same transformation.
|
||||
const oldLockfileRange = await asLockfileVersion(oldRange);
|
||||
|
||||
const useBackstageRange =
|
||||
hasYarnPlugin &&
|
||||
// Only use backstage:^ versions if the package is present in
|
||||
// the manifest for the release we're bumping to.
|
||||
releaseManifest.packages.find(
|
||||
({ name: manifestPackageName }) =>
|
||||
dep.name === manifestPackageName,
|
||||
) &&
|
||||
// Don't use backstage:^ versions for peerDependencies; they only
|
||||
// support npm and workspace: versions.
|
||||
depType !== 'peerDependencies';
|
||||
|
||||
const newRange = useBackstageRange ? 'backstage:^' : dep.range;
|
||||
|
||||
pkgJson[depType][dep.name] = newRange;
|
||||
|
||||
// Check if the update was at least a pre-v1 minor or post-v1 major release
|
||||
const lockfileEntry = lockfile
|
||||
.get(dep.name)
|
||||
?.find(entry => entry.range === oldRange);
|
||||
?.find(entry => entry.range === oldLockfileRange);
|
||||
if (lockfileEntry) {
|
||||
const from = lockfileEntry.version;
|
||||
const to = dep.target;
|
||||
@@ -266,6 +292,21 @@ export default async (opts: OptionValues) => {
|
||||
console.log();
|
||||
}
|
||||
|
||||
if (hasYarnPlugin) {
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.blue(
|
||||
`${chalk.bold(
|
||||
'NOTE',
|
||||
)}: this bump used backstage:^ versions in package.json files, since the Backstage ` +
|
||||
`yarn plugin was detected in the repository. To migrate back to explicit npm versions, ` +
|
||||
`remove the plugin by running "yarn plugin remove @yarnpkg/plugin-backstage", then ` +
|
||||
`repeat this command.`,
|
||||
),
|
||||
);
|
||||
console.log();
|
||||
}
|
||||
|
||||
console.log(chalk.green('Version bump complete!'));
|
||||
}
|
||||
|
||||
@@ -354,16 +395,23 @@ export function createVersionFinder(options: {
|
||||
};
|
||||
}
|
||||
|
||||
export async function bumpBackstageJsonVersion(version: string) {
|
||||
const backstageJsonPath = paths.resolveTargetRoot(BACKSTAGE_JSON);
|
||||
const backstageJson = await fs.readJSON(backstageJsonPath).catch(e => {
|
||||
function getBackstageJsonPath() {
|
||||
return paths.resolveTargetRoot(BACKSTAGE_JSON);
|
||||
}
|
||||
|
||||
async function getBackstageJson() {
|
||||
const backstageJsonPath = getBackstageJsonPath();
|
||||
return fs.readJSON(backstageJsonPath).catch(e => {
|
||||
if (e.code === 'ENOENT') {
|
||||
// gracefully continue in case the file doesn't exist
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
export async function bumpBackstageJsonVersion(version: string) {
|
||||
const backstageJson = await getBackstageJson();
|
||||
const prevVersion = backstageJson?.version;
|
||||
|
||||
if (prevVersion === version) {
|
||||
@@ -394,7 +442,7 @@ export async function bumpBackstageJsonVersion(version: string) {
|
||||
}
|
||||
|
||||
await fs.writeJson(
|
||||
backstageJsonPath,
|
||||
getBackstageJsonPath(),
|
||||
{ ...backstageJson, version },
|
||||
{
|
||||
spaces: 2,
|
||||
@@ -403,6 +451,53 @@ export async function bumpBackstageJsonVersion(version: string) {
|
||||
);
|
||||
}
|
||||
|
||||
async function asLockfileVersion(version: string) {
|
||||
if (version === 'backstage:^') {
|
||||
return `backstage:${(await getBackstageJson())?.version}`;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
const yarnRcSchema = z.object({
|
||||
plugins: z
|
||||
.array(
|
||||
z.object({
|
||||
path: z.string(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
});
|
||||
|
||||
async function getHasYarnPlugin() {
|
||||
const yarnRcPath = paths.resolveTargetRoot('.yarnrc.yml');
|
||||
const yarnRcContent = await fs.readFile(yarnRcPath, 'utf-8').catch(e => {
|
||||
if (e.code === 'ENOENT') {
|
||||
// gracefully continue in case the file doesn't exist
|
||||
return '';
|
||||
}
|
||||
throw e;
|
||||
});
|
||||
|
||||
if (!yarnRcContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parseResult = yarnRcSchema.safeParse(yaml.parse(yarnRcContent));
|
||||
|
||||
if (!parseResult.success) {
|
||||
throw new Error(
|
||||
`Unexpected content in .yarnrc.yml: ${parseResult.error.toString()}`,
|
||||
);
|
||||
}
|
||||
|
||||
const yarnRc = parseResult.data;
|
||||
|
||||
return yarnRc.plugins?.some(
|
||||
plugin => plugin.path === '.yarn/plugins/@yarnpkg/plugin-backstage.cjs',
|
||||
);
|
||||
}
|
||||
|
||||
export async function runYarnInstall() {
|
||||
const spinner = ora({
|
||||
prefixText: `Running ${chalk.blue('yarn install')} to install new versions`,
|
||||
|
||||
Reference in New Issue
Block a user