backstage-cli: automatically update the yarn plugin during versions:bump

Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>
This commit is contained in:
MT Lewis
2024-11-24 20:21:56 +00:00
parent 207e217ae9
commit 2b6c1ea0be
3 changed files with 138 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
If the Backstage yarn plugin is installed, it will now be automatically updated as part of `versions:bump`.
@@ -33,6 +33,7 @@ jest.mock('global-agent/bootstrap', () => {});
// Remove log coloring to simplify log matching
jest.mock('chalk', () => ({
bold: (str: string) => str,
red: (str: string) => str,
blue: (str: string) => str,
cyan: (str: string) => str,
@@ -90,6 +91,12 @@ const REGISTRY_VERSIONS: { [name: string]: string } = {
'@backstage/create-app': '1.0.0',
};
const yarnRcMock = `plugins:
- checksum: cafedead
path: .yarn/plugins/@yarnpkg/plugin-backstage.cjs
spec: 'https://versions.backstage.io/v1/releases/0.0.0/yarn-plugin'
`;
const HEADER = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
@@ -435,6 +442,117 @@ describe('bump', () => {
});
});
it('should use backstage:^ versions for packages in the release manifest when the yarn plugin is installed', async () => {
mockDir.setContent({
'.yarnrc.yml': yarnRcMock,
'yarn.lock': lockfileMock,
'package.json': JSON.stringify({
workspaces: {
packages: ['packages/*'],
},
}),
packages: {
a: {
'package.json': JSON.stringify({
name: 'a',
dependencies: {
'@backstage/core': '^1.0.5',
},
}),
},
b: {
'package.json': JSON.stringify({
name: 'b',
dependencies: {
'@backstage/core': '^1.0.3',
'@backstage/theme': '^1.0.0',
},
}),
},
},
});
jest.spyOn(runObj, 'run').mockResolvedValue(undefined);
worker.use(
rest.get(
'https://versions.backstage.io/v1/tags/main/manifest.json',
(_, res, ctx) =>
res(
ctx.status(200),
ctx.json({
releaseVersion: '0.0.1',
packages: [
{
name: '@backstage/theme',
version: '5.0.0',
},
{
name: '@backstage/create-app',
version: '3.0.0',
},
],
}),
),
),
);
const { log: logs } = await withLogCollector(['log', 'warn'], async () => {
await bump({ pattern: null, release: 'main' } as unknown as Command);
});
expectLogsToMatch(logs, [
'Using default pattern glob @backstage/*',
'Checking for updates of @backstage/core',
'Checking for updates of @backstage/theme',
'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.',
'Some packages are outdated, updating',
'bumping @backstage/theme in b to ^5.0.0',
'bumping @backstage/core in b to ^1.0.6',
'bumping @backstage/core in a to ^1.0.6',
'Updating yarn plugin to v0.0.1...',
'Your project is now at version 0.0.1, which has been written to backstage.json',
'Running yarn install to install new versions',
'Checking for moved packages to the @backstage-community namespace...',
'⚠️ The following packages may have breaking changes:',
' @backstage/theme : 1.0.0 ~> 5.0.0',
' https://github.com/backstage/backstage/blob/master/packages/theme/CHANGELOG.md',
'Version bump complete!',
]);
expect(mockFetchPackageInfo).toHaveBeenCalledTimes(1);
expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core');
expect(runObj.run).toHaveBeenCalledTimes(2);
expect(runObj.run).toHaveBeenCalledWith('yarn', [
'plugin',
'import',
'https://versions.backstage.io/v1/releases/0.0.1/yarn-plugin',
]);
expect(runObj.run).toHaveBeenCalledWith(
'yarn',
['install'],
expect.any(Object),
);
const packageA = await fs.readJson(
mockDir.resolve('packages/a/package.json'),
);
expect(packageA).toEqual({
name: 'a',
dependencies: {
'@backstage/core': '^1.0.6',
},
});
const packageB = await fs.readJson(
mockDir.resolve('packages/b/package.json'),
);
expect(packageB).toEqual({
name: 'b',
dependencies: {
'@backstage/core': '^1.0.6',
'@backstage/theme': 'backstage:^',
},
});
});
it('should only bump packages in the manifest when a specific release is specified', async () => {
mockDir.setContent({
'yarn.lock': lockfileMock,
@@ -44,6 +44,7 @@ import {
} from '@backstage/release-manifests';
import { migrateMovedPackages } from './migrate';
import { runYarnInstall } from './utils';
import { run } from '../../lib/run';
function shouldUseGlobalAgent(): boolean {
// see https://www.npmjs.com/package/global-agent
@@ -120,6 +121,20 @@ export default async (opts: OptionValues) => {
});
}
if (hasYarnPlugin) {
console.log();
console.log(
`Updating yarn plugin to v${releaseManifest.releaseVersion}...`,
);
console.log();
await run('yarn', [
'plugin',
'import',
`https://versions.backstage.io/v1/releases/${releaseManifest.releaseVersion}/yarn-plugin`,
]);
console.log();
}
// First we discover all Backstage dependencies within our own repo
const dependencyMap = await mapDependencies(paths.targetDir, pattern);