Skip to content

Commit fdc0cd4

Browse files
authored
[rush-lib] Fix PreferredVersions being ignored when projects have overlapping dependencies (#4835)
* Prioritize explicit preferredVersions over implicit ones * Add tests * Add changelog * Address feedback: foreach() function -> for...of loop * Fix CI failures --------- Co-authored-by: ace-n-msft <[email protected]>
1 parent 9370024 commit fdc0cd4

File tree

6 files changed

+85
-1
lines changed

6 files changed

+85
-1
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@microsoft/rush",
5+
"comment": "Fix an issue where PreferredVersions are ignored when a project contains an overlapping dependency entry (https://github.com/microsoft/rushstack/issues/3205)",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@microsoft/rush"
10+
}

libraries/rush-lib/src/logic/pnpm/PnpmfileConfiguration.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// See LICENSE in the project root for license information.
33

44
import * as path from 'path';
5+
import * as semver from 'semver';
56
import { FileSystem, Import, type IPackageJson, JsonFile, MapExtensions } from '@rushstack/node-core-library';
67

78
import type { PnpmPackageManager } from '../../api/packageManager/PnpmPackageManager';
@@ -91,11 +92,16 @@ export class PnpmfileConfiguration {
9192
if ((rushConfiguration.packageManagerOptions as PnpmOptionsConfiguration).useWorkspaces) {
9293
const commonVersionsConfiguration: CommonVersionsConfiguration = subspace.getCommonVersions();
9394
const preferredVersions: Map<string, string> = new Map();
94-
MapExtensions.mergeFromMap(preferredVersions, commonVersionsConfiguration.getAllPreferredVersions());
9595
MapExtensions.mergeFromMap(
9696
preferredVersions,
9797
rushConfiguration.getImplicitlyPreferredVersions(subspace)
9898
);
99+
for (const [name, version] of commonVersionsConfiguration.getAllPreferredVersions()) {
100+
// Use the most restrictive version range available
101+
if (!preferredVersions.has(name) || semver.subset(version, preferredVersions.get(name)!)) {
102+
preferredVersions.set(name, version);
103+
}
104+
}
99105
allPreferredVersions = MapExtensions.toObject(preferredVersions);
100106
allowedAlternativeVersions = MapExtensions.toObject(
101107
commonVersionsConfiguration.allowedAlternativeVersions
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import { RushConfiguration } from '../../../api/RushConfiguration';
5+
import { PnpmfileConfiguration } from '../PnpmfileConfiguration';
6+
import { JsonFile, type JsonObject } from '@rushstack/node-core-library';
7+
8+
describe(PnpmfileConfiguration.name, () => {
9+
const repoPath: string = `${__dirname}/repo`;
10+
const rushFilename: string = `${repoPath}/rush3.json`;
11+
const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename);
12+
const shimPath: string = `${rushConfiguration.defaultSubspace.getSubspaceTempFolderPath()}/pnpmfileSettings.json`;
13+
14+
beforeAll(async () => {
15+
const subspace = rushConfiguration.defaultSubspace;
16+
await PnpmfileConfiguration.writeCommonTempPnpmfileShimAsync(
17+
rushConfiguration,
18+
subspace.getSubspaceTempFolderPath(),
19+
subspace
20+
);
21+
});
22+
23+
it('should use the smallest-available SemVer range (preferredVersions)', async () => {
24+
const shimJson: JsonObject = await JsonFile.loadAsync(shimPath);
25+
expect(shimJson.allPreferredVersions).toHaveProperty('core-js', '3.6.5');
26+
});
27+
28+
it('should use the smallest-available SemVer range (per-project)', async () => {
29+
const shimJson: JsonObject = await JsonFile.loadAsync(shimPath);
30+
expect(shimJson.allPreferredVersions).toHaveProperty('delay', '5.0.0');
31+
});
32+
33+
it('should override preferredVersions when per-project versions conflict', async () => {
34+
const shimJson: JsonObject = await JsonFile.loadAsync(shimPath);
35+
expect(shimJson.allPreferredVersions).toHaveProperty('find-up', '5.0.0');
36+
});
37+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "baz",
3+
"version": "1.0.0",
4+
"dependencies": {
5+
"core-js": "^3.0.0",
6+
"delay": "5.0.0",
7+
"find-up": "*"
8+
}
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json",
3+
"preferredVersions": {
4+
"core-js": "3.6.5",
5+
"delay": "4.0.0",
6+
"find-up": "5.0.0"
7+
}
8+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json",
3+
"pnpmVersion": "7.0.0",
4+
"rushVersion": "5.46.1",
5+
"projects": [
6+
{
7+
"packageName": "baz",
8+
"projectFolder": "apps/baz"
9+
}
10+
],
11+
"pnpmOptions": {
12+
"useWorkspaces": true
13+
}
14+
}

0 commit comments

Comments
 (0)