first cut at addressing bug with adding backstage dependencies to a package maintained by the backstage plugin

Signed-off-by: Cory Steers <cory.steers.gmu9@statefarm.com>
This commit is contained in:
Cory Steers
2025-05-29 15:21:37 -05:00
parent d1600abab1
commit a0f9e4efce
9 changed files with 234 additions and 5 deletions
+5
View File
@@ -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.
+2 -1
View File
@@ -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"
@@ -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<suggestUtils.Strategy> = [];
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');
});
});
@@ -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<suggestUtils.Strategy>,
) => {
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:^';
}
};
@@ -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');
});
});
@@ -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?`,
);
}
};
@@ -16,3 +16,5 @@
export { beforeWorkspacePacking } from './beforeWorkspacePacking';
export { reduceDependency } from './reduceDependency';
export { afterWorkspaceDependencyAddition } from './afterWorkspaceDependencyAddition';
export { afterWorkspaceDependencyReplacement } from './afterWorkspaceDependencyReplacement';
+10 -2
View File
@@ -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<Hooks & PackHooks> = {
const plugin: Plugin<Hooks & EssentialHooks & PackHooks> = {
hooks: {
afterWorkspaceDependencyAddition,
afterWorkspaceDependencyReplacement,
reduceDependency,
beforeWorkspacePacking,
},
+3 -2
View File
@@ -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"