From a0f9e4efce5db5d5fb9fe3d1fbfa09704b7cc35a Mon Sep 17 00:00:00 2001 From: Cory Steers Date: Thu, 29 May 2025 15:21:37 -0500 Subject: [PATCH 1/6] first cut at addressing bug with adding backstage dependencies to a package maintained by the backstage plugin Signed-off-by: Cory Steers --- .changeset/tiny-crews-shop.md | 5 ++ packages/yarn-plugin/package.json | 3 +- .../afterWorkspaceDependencyAddition.test.ts | 67 ++++++++++++++++ .../afterWorkspaceDependencyAddition.ts | 33 ++++++++ ...fterWorkspaceDependencyReplacement.test.ts | 77 +++++++++++++++++++ .../afterWorkspaceDependencyReplacement.ts | 35 +++++++++ packages/yarn-plugin/src/handlers/index.ts | 2 + packages/yarn-plugin/src/index.ts | 12 ++- yarn.lock | 5 +- 9 files changed, 234 insertions(+), 5 deletions(-) create mode 100644 .changeset/tiny-crews-shop.md create mode 100644 packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts create mode 100644 packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts create mode 100644 packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts create mode 100644 packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts diff --git a/.changeset/tiny-crews-shop.md b/.changeset/tiny-crews-shop.md new file mode 100644 index 0000000000..18f205c5fc --- /dev/null +++ b/.changeset/tiny-crews-shop.md @@ -0,0 +1,5 @@ +--- +'yarn-plugin-backstage': patch +--- + +added functionality so that adding or updating a backstage dependency to a package would maintain the "backstage:^" placeholder for the version. diff --git a/packages/yarn-plugin/package.json b/packages/yarn-plugin/package.json index 7de8d140bb..c764da4fa6 100644 --- a/packages/yarn-plugin/package.json +++ b/packages/yarn-plugin/package.json @@ -32,8 +32,9 @@ "dependencies": { "@backstage/cli-common": "workspace:^", "@backstage/release-manifests": "workspace:^", - "@yarnpkg/core": "^4.4.0", + "@yarnpkg/core": "^4.4.1", "@yarnpkg/fslib": "^3.1.2", + "@yarnpkg/plugin-essentials": "^4.4.0", "@yarnpkg/plugin-npm": "patch:@yarnpkg/plugin-npm@npm%3A3.1.0#~/.yarn/patches/@yarnpkg-plugin-npm-npm-3.1.0-6533d0f5a1.patch", "@yarnpkg/plugin-pack": "^4.0.1", "semver": "^7.6.0" diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts new file mode 100644 index 0000000000..fa89080889 --- /dev/null +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright 2025 The Backstage Authors + * + * 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 { + Descriptor, + DescriptorHash, + IdentHash, + Workspace, +} from '@yarnpkg/core'; +import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { afterWorkspaceDependencyAddition } from './afterWorkspaceDependencyAddition'; + +describe('afterWorkspaceDependencyAddition', () => { + const workspace = {} as Workspace; + const target = {} as suggestUtils.Target; + const strategies: Array = []; + + it('should replace the range for a backstage scoped dependency', async () => { + const input: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + await afterWorkspaceDependencyAddition( + workspace, + target, + input, + strategies, + ); + + expect(input.range).toBe('backstage:^'); + }); + + it('should not replace the range for a non-backstage scoped dependency', async () => { + const input: Descriptor = { + scope: 'backstage-community', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + await afterWorkspaceDependencyAddition( + workspace, + target, + input, + strategies, + ); + + expect(input.range).toBe('^1.0.0'); + }); +}); diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts new file mode 100644 index 0000000000..8e39b1c759 --- /dev/null +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts @@ -0,0 +1,33 @@ +/* + * Copyright 2025 The Backstage Authors + * + * 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 { Descriptor, Workspace } from '@yarnpkg/core'; +import { suggestUtils } from '@yarnpkg/plugin-essentials'; + +export const afterWorkspaceDependencyAddition = async ( + _workspace: Workspace, + _target: suggestUtils.Target, + descriptor: Descriptor, + _strategies: Array, +) => { + if (descriptor.scope === 'backstage' && descriptor.range !== 'backstage:^') { + // is there a better way to log than console.log? + console.log( + `afterWorkspaceDependencyAddition hook: Setting descriptor range from ${descriptor.range} to 'backstage:^' for ${descriptor.scope}/${descriptor.name}`, + ); + descriptor.range = 'backstage:^'; + } +}; diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts new file mode 100644 index 0000000000..eef3f25f97 --- /dev/null +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts @@ -0,0 +1,77 @@ +/* + * Copyright 2025 The Backstage Authors + * + * 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 { + Descriptor, + DescriptorHash, + IdentHash, + Workspace, +} from '@yarnpkg/core'; +import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { afterWorkspaceDependencyReplacement } from './afterWorkspaceDependencyReplacement'; + +describe('afterWorkspaceDependencyReplacement.test', () => { + const workspace = {} as Workspace; + const target = {} as suggestUtils.Target; + + it('should warn that the range is being changed for a backstage scoped dependency', async () => { + const fromDescriptor: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: 'backstage:^', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + const toDescriptor: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + await afterWorkspaceDependencyReplacement( + workspace, + target, + fromDescriptor, + toDescriptor, + ); + + expect(toDescriptor.range).toBe('^1.0.0'); + }); + it('should ignore that the range is being changed for a non-backstage scoped dependency', async () => { + const fromDescriptor: Descriptor = { + scope: 'backstage-community', + name: 'test-package', + range: 'backstage:^', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + const toDescriptor: Descriptor = { + scope: 'backstage-community', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + await afterWorkspaceDependencyReplacement( + workspace, + target, + fromDescriptor, + toDescriptor, + ); + + expect(toDescriptor.range).toBe('^1.0.0'); + }); +}); diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts new file mode 100644 index 0000000000..b8141c8bb3 --- /dev/null +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts @@ -0,0 +1,35 @@ +/* + * Copyright 2025 The Backstage Authors + * + * 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 { Descriptor, Workspace } from '@yarnpkg/core'; +import { suggestUtils } from '@yarnpkg/plugin-essentials'; + +export const afterWorkspaceDependencyReplacement = async ( + _workspace: Workspace, + _target: suggestUtils.Target, + fromDescriptor: Descriptor, + toDescriptor: Descriptor, +) => { + if ( + toDescriptor.scope === 'backstage' && + toDescriptor.range !== 'backstage:^' + ) { + // is there a better way to log than console.log? + console.log( + `afterWorkspaceDependencyReplacement hook: Setting descriptor range from '${fromDescriptor.range}' to '${toDescriptor.range}' for ${fromDescriptor.scope}/${fromDescriptor.name}. Are you sure you want to be doing that?`, + ); + } +}; diff --git a/packages/yarn-plugin/src/handlers/index.ts b/packages/yarn-plugin/src/handlers/index.ts index baa144b36f..fe8f05c935 100644 --- a/packages/yarn-plugin/src/handlers/index.ts +++ b/packages/yarn-plugin/src/handlers/index.ts @@ -16,3 +16,5 @@ export { beforeWorkspacePacking } from './beforeWorkspacePacking'; export { reduceDependency } from './reduceDependency'; +export { afterWorkspaceDependencyAddition } from './afterWorkspaceDependencyAddition'; +export { afterWorkspaceDependencyReplacement } from './afterWorkspaceDependencyReplacement'; diff --git a/packages/yarn-plugin/src/index.ts b/packages/yarn-plugin/src/index.ts index ad18deb0ff..b08d98eae7 100644 --- a/packages/yarn-plugin/src/index.ts +++ b/packages/yarn-plugin/src/index.ts @@ -23,7 +23,13 @@ import { Plugin, Hooks, semverUtils, YarnVersion } from '@yarnpkg/core'; import { Hooks as PackHooks } from '@yarnpkg/plugin-pack'; -import { beforeWorkspacePacking, reduceDependency } from './handlers'; +import { Hooks as EssentialHooks } from '@yarnpkg/plugin-essentials'; +import { + afterWorkspaceDependencyAddition, + afterWorkspaceDependencyReplacement, + beforeWorkspacePacking, + reduceDependency, +} from './handlers'; import { BackstageNpmResolver } from './resolvers'; // All dependencies of the yarn plugin are bundled during the build. Chalk @@ -44,8 +50,10 @@ if (!semverUtils.satisfiesWithPrereleases(YarnVersion, '^4.1.1')) { /** * @public */ -const plugin: Plugin = { +const plugin: Plugin = { hooks: { + afterWorkspaceDependencyAddition, + afterWorkspaceDependencyReplacement, reduceDependency, beforeWorkspacePacking, }, diff --git a/yarn.lock b/yarn.lock index 14e234f527..539b89f70c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22705,7 +22705,7 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/core@npm:^4.2.1, @yarnpkg/core@npm:^4.4.0": +"@yarnpkg/core@npm:^4.2.1, @yarnpkg/core@npm:^4.4.0, @yarnpkg/core@npm:^4.4.1": version: 4.4.1 resolution: "@yarnpkg/core@npm:4.4.1" dependencies: @@ -49221,8 +49221,9 @@ __metadata: "@backstage/cli-common": "workspace:^" "@backstage/release-manifests": "workspace:^" "@yarnpkg/builder": "npm:^4.2.1" - "@yarnpkg/core": "npm:^4.4.0" + "@yarnpkg/core": "npm:^4.4.1" "@yarnpkg/fslib": "npm:^3.1.2" + "@yarnpkg/plugin-essentials": "npm:^4.4.0" "@yarnpkg/plugin-npm": "patch:@yarnpkg/plugin-npm@npm%3A3.1.0#~/.yarn/patches/@yarnpkg-plugin-npm-npm-3.1.0-6533d0f5a1.patch" "@yarnpkg/plugin-pack": "npm:^4.0.1" fs-extra: "npm:^11.2.0" From 797688a944d2854fcea1be90903f7048b605a0ef Mon Sep 17 00:00:00 2001 From: Cory Steers Date: Fri, 30 May 2025 10:23:28 -0500 Subject: [PATCH 2/6] enhance logic to make sure backstage can manage the version of the dependency before changing the range Signed-off-by: Cory Steers --- .../afterWorkspaceDependencyAddition.test.ts | 54 +++++++++++++++- .../afterWorkspaceDependencyAddition.ts | 30 ++++++--- ...fterWorkspaceDependencyReplacement.test.ts | 63 ++++++++++++++++++- .../afterWorkspaceDependencyReplacement.ts | 25 +++++--- 4 files changed, 155 insertions(+), 17 deletions(-) diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts index fa89080889..ae575a8b02 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.test.ts @@ -20,12 +20,28 @@ import { Workspace, } from '@yarnpkg/core'; import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { getPackageVersion } from '../util'; import { afterWorkspaceDependencyAddition } from './afterWorkspaceDependencyAddition'; +jest.mock('../util', () => ({ + getPackageVersion: jest.fn(), +})); + describe('afterWorkspaceDependencyAddition', () => { - const workspace = {} as Workspace; + const workspace = { + project: { + configuration: {}, + }, + } as Workspace; const target = {} as suggestUtils.Target; const strategies: Array = []; + const mockGetPackageVersion = getPackageVersion as jest.MockedFunction< + typeof getPackageVersion + >; + + beforeEach(() => { + mockGetPackageVersion.mockReset(); + }); it('should replace the range for a backstage scoped dependency', async () => { const input: Descriptor = { @@ -36,6 +52,8 @@ describe('afterWorkspaceDependencyAddition', () => { identHash: {} as IdentHash, }; + mockGetPackageVersion.mockImplementation(() => Promise.resolve('success')); + await afterWorkspaceDependencyAddition( workspace, target, @@ -44,6 +62,39 @@ describe('afterWorkspaceDependencyAddition', () => { ); expect(input.range).toBe('backstage:^'); + expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); + expect(mockGetPackageVersion).toHaveBeenCalledWith( + input, + workspace.project.configuration, + ); + }); + + it('should not replace the range for a backstage scoped dependency where it cant find a version from remote', async () => { + const input: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + mockGetPackageVersion.mockImplementation(() => + Promise.reject(new Error('test error')), + ); + + await afterWorkspaceDependencyAddition( + workspace, + target, + input, + strategies, + ); + + expect(input.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); + expect(mockGetPackageVersion).toHaveBeenCalledWith( + input, + workspace.project.configuration, + ); }); it('should not replace the range for a non-backstage scoped dependency', async () => { @@ -63,5 +114,6 @@ describe('afterWorkspaceDependencyAddition', () => { ); expect(input.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).not.toHaveBeenCalled(); }); }); diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts index 8e39b1c759..9307790930 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts @@ -14,20 +14,34 @@ * limitations under the License. */ -import { Descriptor, Workspace } from '@yarnpkg/core'; +import { Descriptor, structUtils, Workspace } from '@yarnpkg/core'; import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { getPackageVersion } from '../util'; +import { PROTOCOL } from '../constants'; export const afterWorkspaceDependencyAddition = async ( - _workspace: Workspace, + workspace: Workspace, _target: suggestUtils.Target, descriptor: Descriptor, _strategies: Array, ) => { - if (descriptor.scope === 'backstage' && descriptor.range !== 'backstage:^') { - // is there a better way to log than console.log? - console.log( - `afterWorkspaceDependencyAddition hook: Setting descriptor range from ${descriptor.range} to 'backstage:^' for ${descriptor.scope}/${descriptor.name}`, - ); - descriptor.range = 'backstage:^'; + const descriptorRange = structUtils.parseRange(descriptor.range); + + if ( + descriptor.scope === 'backstage' && + descriptorRange.protocol !== PROTOCOL + ) { + try { + await getPackageVersion(descriptor, workspace.project.configuration); + // is there a better way to log than console.log? + console.log( + `afterWorkspaceDependencyAddition hook: Setting descriptor range from ${descriptor.range} to 'backstage:^' for ${descriptor.scope}/${descriptor.name}`, + ); + descriptor.range = `${PROTOCOL}^`; + } catch (_error: any) { + // if there's no found version then this is likely a deprecated package + // or otherwise the plugin won't be able to resolve the real version + // and we should leave the desired range as is + } } }; diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts index eef3f25f97..7bf9c77554 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.test.ts @@ -20,11 +20,27 @@ import { Workspace, } from '@yarnpkg/core'; import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { getPackageVersion } from '../util'; import { afterWorkspaceDependencyReplacement } from './afterWorkspaceDependencyReplacement'; +jest.mock('../util', () => ({ + getPackageVersion: jest.fn(), +})); + describe('afterWorkspaceDependencyReplacement.test', () => { - const workspace = {} as Workspace; + const workspace = { + project: { + configuration: {}, + }, + } as Workspace; const target = {} as suggestUtils.Target; + const mockGetPackageVersion = getPackageVersion as jest.MockedFunction< + typeof getPackageVersion + >; + + beforeEach(() => { + mockGetPackageVersion.mockReset(); + }); it('should warn that the range is being changed for a backstage scoped dependency', async () => { const fromDescriptor: Descriptor = { @@ -41,6 +57,9 @@ describe('afterWorkspaceDependencyReplacement.test', () => { descriptorHash: {} as DescriptorHash, identHash: {} as IdentHash, }; + + mockGetPackageVersion.mockImplementation(() => Promise.resolve('success')); + await afterWorkspaceDependencyReplacement( workspace, target, @@ -49,7 +68,48 @@ describe('afterWorkspaceDependencyReplacement.test', () => { ); expect(toDescriptor.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); + expect(mockGetPackageVersion).toHaveBeenCalledWith( + toDescriptor, + workspace.project.configuration, + ); }); + + it('should not warn that the range is being changed for a backstage scoped dependency where it cant find a version from remote', async () => { + const fromDescriptor: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: 'backstage:^', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + const toDescriptor: Descriptor = { + scope: 'backstage', + name: 'test-package', + range: '^1.0.0', + descriptorHash: {} as DescriptorHash, + identHash: {} as IdentHash, + }; + + mockGetPackageVersion.mockImplementation(() => + Promise.reject(new Error('test error')), + ); + + await afterWorkspaceDependencyReplacement( + workspace, + target, + fromDescriptor, + toDescriptor, + ); + + expect(toDescriptor.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).toHaveBeenCalledTimes(1); + expect(mockGetPackageVersion).toHaveBeenCalledWith( + toDescriptor, + workspace.project.configuration, + ); + }); + it('should ignore that the range is being changed for a non-backstage scoped dependency', async () => { const fromDescriptor: Descriptor = { scope: 'backstage-community', @@ -73,5 +133,6 @@ describe('afterWorkspaceDependencyReplacement.test', () => { ); expect(toDescriptor.range).toBe('^1.0.0'); + expect(mockGetPackageVersion).not.toHaveBeenCalled(); }); }); diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts index b8141c8bb3..a955191244 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts @@ -14,22 +14,33 @@ * limitations under the License. */ -import { Descriptor, Workspace } from '@yarnpkg/core'; +import { Descriptor, structUtils, Workspace } from '@yarnpkg/core'; import { suggestUtils } from '@yarnpkg/plugin-essentials'; +import { getPackageVersion } from '../util'; +import { PROTOCOL } from '../constants'; export const afterWorkspaceDependencyReplacement = async ( - _workspace: Workspace, + workspace: Workspace, _target: suggestUtils.Target, fromDescriptor: Descriptor, toDescriptor: Descriptor, ) => { + const toDescriptorRange = structUtils.parseRange(toDescriptor.range); + if ( toDescriptor.scope === 'backstage' && - toDescriptor.range !== 'backstage:^' + toDescriptorRange.protocol !== PROTOCOL ) { - // is there a better way to log than console.log? - console.log( - `afterWorkspaceDependencyReplacement hook: Setting descriptor range from '${fromDescriptor.range}' to '${toDescriptor.range}' for ${fromDescriptor.scope}/${fromDescriptor.name}. Are you sure you want to be doing that?`, - ); + try { + await getPackageVersion(toDescriptor, workspace.project.configuration); + // is there a better way to log than console.log? + console.log( + `afterWorkspaceDependencyReplacement hook: Setting descriptor range from '${fromDescriptor.range}' to '${toDescriptor.range}' for ${fromDescriptor.scope}/${fromDescriptor.name}. Are you sure you want to be doing that?`, + ); + } catch (_error: any) { + // if there's no found version then this is likely a deprecated package + // or otherwise the plugin won't be able to resolve the real version + // and we should not warn them. + } } }; From 95955c21f28ac07c05bae543f9a810fc0a6bb660 Mon Sep 17 00:00:00 2001 From: Cory Steers Date: Fri, 30 May 2025 10:47:15 -0500 Subject: [PATCH 3/6] update with doc on new hooks added Signed-off-by: Cory Steers --- packages/yarn-plugin/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/yarn-plugin/README.md b/packages/yarn-plugin/README.md index 073669b9a5..49b57fe0ef 100644 --- a/packages/yarn-plugin/README.md +++ b/packages/yarn-plugin/README.md @@ -82,3 +82,12 @@ specific Backstage repository. As such, when publishing packages, all `backstage:^` versions should be removed from the package.json and replaced with the appropriate npm version ranges. This is handled by the `beforeWorkspacePacking` hook. + +### `afterWorkspaceDependencyAddition` hook + +\_Replaces npm version ranges with `backstage:^` ranges for `@backstage/*` dependencies added after +the plugin has converted existing dependencies to `backstage:^` range + +### `afterWorkspaceDependencyReplacement` hook + +\_warns user with console message when running `yarn add` for a `@backstage/*` scoped dependency that is already a dependency in the target package. Doing so will remove the `backstage:^` scope and replace it with the actual npm version range, which may not be desired. From 1115791e35d7fe824e5701c69aeadfabd541837b Mon Sep 17 00:00:00 2001 From: Cory Steers Date: Fri, 30 May 2025 12:37:22 -0500 Subject: [PATCH 4/6] formatting fixes Signed-off-by: Cory Steers --- packages/yarn-plugin/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/yarn-plugin/README.md b/packages/yarn-plugin/README.md index 49b57fe0ef..5c112506e3 100644 --- a/packages/yarn-plugin/README.md +++ b/packages/yarn-plugin/README.md @@ -85,9 +85,9 @@ the appropriate npm version ranges. This is handled by the ### `afterWorkspaceDependencyAddition` hook -\_Replaces npm version ranges with `backstage:^` ranges for `@backstage/*` dependencies added after -the plugin has converted existing dependencies to `backstage:^` range +_Replaces npm version ranges with `backstage:^` ranges for `@backstage/*` dependencies added after +the plugin has converted existing dependencies to `backstage:^` range_ ### `afterWorkspaceDependencyReplacement` hook -\_warns user with console message when running `yarn add` for a `@backstage/*` scoped dependency that is already a dependency in the target package. Doing so will remove the `backstage:^` scope and replace it with the actual npm version range, which may not be desired. +_warns user with console message when running `yarn add` for a `@backstage/*` scoped dependency that is already a dependency in the target package. Doing so will remove the `backstage:^` scope and replace it with the actual npm version range, which may not be desired._ From 52f5f431d018a7022741ce79cfcca0fa9c7bc0ee Mon Sep 17 00:00:00 2001 From: Cory Steers Date: Fri, 30 May 2025 12:41:39 -0500 Subject: [PATCH 5/6] update to include 3rd hooks import Signed-off-by: Cory Steers --- packages/yarn-plugin/report.api.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/yarn-plugin/report.api.md b/packages/yarn-plugin/report.api.md index 620bbbb567..b9425282b4 100644 --- a/packages/yarn-plugin/report.api.md +++ b/packages/yarn-plugin/report.api.md @@ -4,10 +4,11 @@ ```ts import { Hooks } from '@yarnpkg/core'; -import { Hooks as Hooks_2 } from '@yarnpkg/plugin-pack'; +import { Hooks as Hooks_2 } from '@yarnpkg/plugin-essentials'; +import { Hooks as Hooks_3 } from '@yarnpkg/plugin-pack'; import { Plugin as Plugin_2 } from '@yarnpkg/core'; // @public (undocumented) -const plugin: Plugin_2; +const plugin: Plugin_2; export default plugin; ``` From a353f9364c780ebf4c4a600adb8b0abdf133c1d4 Mon Sep 17 00:00:00 2001 From: Cory Steers Date: Mon, 16 Jun 2025 10:42:52 -0500 Subject: [PATCH 6/6] implement sugested changes Signed-off-by: Cory Steers --- .../src/handlers/afterWorkspaceDependencyAddition.ts | 5 ++--- .../src/handlers/afterWorkspaceDependencyReplacement.ts | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts index 9307790930..219830a8c9 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyAddition.ts @@ -33,9 +33,8 @@ export const afterWorkspaceDependencyAddition = async ( ) { try { await getPackageVersion(descriptor, workspace.project.configuration); - // is there a better way to log than console.log? - console.log( - `afterWorkspaceDependencyAddition hook: Setting descriptor range from ${descriptor.range} to 'backstage:^' for ${descriptor.scope}/${descriptor.name}`, + console.info( + `Setting ${descriptor.scope}/${descriptor.name} to ${PROTOCOL}^`, ); descriptor.range = `${PROTOCOL}^`; } catch (_error: any) { diff --git a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts index a955191244..55a11086fd 100644 --- a/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts +++ b/packages/yarn-plugin/src/handlers/afterWorkspaceDependencyReplacement.ts @@ -22,7 +22,7 @@ import { PROTOCOL } from '../constants'; export const afterWorkspaceDependencyReplacement = async ( workspace: Workspace, _target: suggestUtils.Target, - fromDescriptor: Descriptor, + _fromDescriptor: Descriptor, toDescriptor: Descriptor, ) => { const toDescriptorRange = structUtils.parseRange(toDescriptor.range); @@ -33,9 +33,8 @@ export const afterWorkspaceDependencyReplacement = async ( ) { try { await getPackageVersion(toDescriptor, workspace.project.configuration); - // is there a better way to log than console.log? - console.log( - `afterWorkspaceDependencyReplacement hook: Setting descriptor range from '${fromDescriptor.range}' to '${toDescriptor.range}' for ${fromDescriptor.scope}/${fromDescriptor.name}. Are you sure you want to be doing that?`, + console.warn( + `${toDescriptor.name} should be set to "${PROTOCOL}^" instead of "${toDescriptor.range}". Make sure this change is intentional and not a mistake.`, ); } catch (_error: any) { // if there's no found version then this is likely a deprecated package