豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit ff39f60

Browse files
authored
fix(bazel): integration test rule not able to setup mappings for resolutions (#286)
Fixes that the Bazel integration test rule is not able to setup mappings for Yarn resolutions because the record keys do not exactly match to a package name, but rather follow certain allowed patterns, like `**/<pkg-name>`.
1 parent 4f0f6a0 commit ff39f60

File tree

3 files changed

+73
-8
lines changed

3 files changed

+73
-8
lines changed

bazel/integration/test_runner/package_json.ts

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,18 @@ export function updateMappingsForPackageJson(
4949
): PackageJson {
5050
const newPackageJson = {...packageJson};
5151

52-
updateMappingForRecord(newPackageJson.dependencies ?? {}, mappings);
53-
updateMappingForRecord(newPackageJson.devDependencies ?? {}, mappings);
54-
updateMappingForRecord(newPackageJson.optionalDependencies ?? {}, mappings);
55-
updateMappingForRecord(newPackageJson.resolutions ?? {}, mappings);
52+
updateMappingForRecord(newPackageJson, 'dependencies', mappings);
53+
updateMappingForRecord(newPackageJson, 'devDependencies', mappings);
54+
updateMappingForRecord(newPackageJson, 'optionalDependencies', mappings);
55+
// The object for Yarn resolutions will not directly match with the mapping keys
56+
// specified here, as resolutions usually follow a format as followed:
57+
// 1. `**/<pkg-name>`
58+
// 2. `<other-pkg>/**/<pkg-name>`
59+
// 3. `<pkg-name>`
60+
// More details here: https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/.
61+
// We pass a regular expression which matches the `<pkg-name>` so that the mappings can
62+
// be applied for resolutions as well.
63+
updateMappingForRecord(newPackageJson, 'resolutions', mappings, /([^/]+)$/);
5664

5765
return newPackageJson;
5866
}
@@ -64,15 +72,31 @@ export function updateMappingsForPackageJson(
6472
* @throws An error if there is a dependency entry referring to a local file. Such
6573
* entries should not use `file:` but instead configure a mapping through Bazel.
6674
*/
67-
function updateMappingForRecord(record: DependencyRecord, mappings: PackageMappings) {
68-
for (const [pkgName, value] of Object.entries(record)) {
75+
function updateMappingForRecord(
76+
pkgJson: PackageJson,
77+
recordName: keyof PackageJson,
78+
mappings: PackageMappings,
79+
nameMatchRegex?: RegExp,
80+
) {
81+
const record = pkgJson[recordName] ?? {};
82+
83+
for (const [entryKey, value] of Object.entries(record)) {
84+
const pkgName = getPackageNameFromDependencyEntry(entryKey, nameMatchRegex);
85+
86+
if (pkgName === null) {
87+
throw Error(`Could not determine package name for "${recordName}" entry: ${entryKey}.`);
88+
}
89+
90+
// Print the resolved package name to ease debugging when packages are not mapped properly.
91+
debug(`updateMappingForRecord: Resolved "${recordName}@${entryKey}" to package: ${pkgName}`);
92+
6993
const mappedAbsolutePath = mappings[pkgName];
7094

7195
// If the value of the dependency entry is referring to a local file, then we report
7296
// an error as this is likely a missing mapping that should be set up through Bazel.
7397
if (mappedAbsolutePath === undefined && value.startsWith(`file:`)) {
7498
throw Error(
75-
`Unexpected dependency entry for: ${pkgName}, pointing to: ${value}.` +
99+
`Unexpected dependency entry for: ${entryKey}, pointing to: ${value}. ` +
76100
`Instead, configure the mapping through the integration test Bazel target.`,
77101
);
78102
}
@@ -82,6 +106,25 @@ function updateMappingForRecord(record: DependencyRecord, mappings: PackageMappi
82106
continue;
83107
}
84108

85-
record[pkgName] = mappedAbsolutePath;
109+
record[entryKey] = mappedAbsolutePath;
110+
}
111+
}
112+
113+
/**
114+
* Gets the package name from a dependency record entry.
115+
*
116+
* @param entryKey Key of the dependency record entry.
117+
* @param nameMatchRegex Optional regular expression that can be specified to match the package
118+
* name in a dependency entry. This is useful for e.g. Yarn resolutions using patterns.
119+
* The first capturing group is expected to return the matched package name.
120+
*/
121+
function getPackageNameFromDependencyEntry(
122+
entryKey: string,
123+
nameMatchRegex?: RegExp,
124+
): string | null {
125+
if (nameMatchRegex) {
126+
const matches = entryKey.match(nameMatchRegex);
127+
return matches === null ? null : matches[1];
86128
}
129+
return entryKey;
87130
}

bazel/integration/tests/package_mappings/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,16 @@
55
"license": "MIT",
66
"dependencies": {
77
"fake_pkg": "0.0.0"
8+
},
9+
"devDependencies": {
10+
"fake_pkg": "0.0.0"
11+
},
12+
"optionalDependencies": {
13+
"fake_pkg": "0.0.0"
14+
},
15+
"resolutions": {
16+
"**/fake_pkg": "0.0.0",
17+
"some_pkg/**/fake_pkg": "0.0.0",
18+
"fake_pkg": "0.0.0"
819
}
920
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
import fakePkg from 'fake_pkg';
2+
import fs from 'fs';
23

34
// Sanity check that the installed package matches the one we have
45
// built from source using `pkg_npm`.
56
if (fakePkg !== 'This is a fake package!') {
67
console.error('Fake package is not matching with locally-built one.');
78
process.exitCode = 1;
89
}
10+
11+
const pkgJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
12+
const recordsToCheck = ['dependencies', 'devDependencies', 'optionalDependencies', 'resolutions'];
13+
14+
for (const recordName of recordsToCheck) {
15+
if (Object.values(pkgJson[recordName]).includes('0.0.0')) {
16+
console.error(`The "${recordName}" field has not been replaced with mapped archives.`);
17+
process.exitCode = 1;
18+
}
19+
}

0 commit comments

Comments
 (0)