enhance logic to make sure backstage can manage the version of the dependency before changing the range

Signed-off-by: Cory Steers <cory.steers.gmu9@statefarm.com>
This commit is contained in:
Cory Steers
2025-05-30 10:23:28 -05:00
parent a0f9e4efce
commit 797688a944
4 changed files with 155 additions and 17 deletions
@@ -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<suggestUtils.Strategy> = [];
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();
});
});
@@ -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<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:^';
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
}
}
};
@@ -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();
});
});
@@ -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.
}
}
};