Skip to content

Commit 21c2dc7

Browse files
committed
feat(bazel): provide a validation macro to ensure that the package.json and MODULE.bazel.lock file versions of typescript match (#3010)
PR Close #3010
1 parent 390e677 commit 21c2dc7

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

bazel/validation/BUILD.bazel

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
2+
3+
copy_to_bin(
4+
name = "verify-typescript",
5+
srcs = [
6+
"verify-typescript.mjs",
7+
],
8+
visibility = [
9+
"//visibility:public",
10+
],
11+
)

bazel/validation/defs.bzl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
load("@aspect_rules_js//js:defs.bzl", "js_test")
2+
3+
def validate_ts_version_matching(package_json, module_lock_file):
4+
js_test(
5+
name = "validate_ts_version_match",
6+
data = [
7+
package_json,
8+
module_lock_file,
9+
],
10+
entry_point = "@devinfra//bazel/validation:verify-typescript",
11+
fixed_args = [
12+
"$(rlocationpath %s)" % package_json,
13+
"$(rlocationpath %s)" % module_lock_file,
14+
],
15+
)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {readFile} from 'node:fs/promises';
10+
import {join} from 'node:path';
11+
12+
/** The runfiles directory for the script. */
13+
const runfiles = process.env['RUNFILES'];
14+
15+
async function main([packageJsonPath, moduleLockFilePath]) {
16+
/** The json contents of the BAZEL.module.lock file. */
17+
const moduleLock = JSON.parse(await readFile(join(runfiles, moduleLockFilePath), 'utf8'));
18+
/** The json contents of the package.json file. */
19+
const packageJson = JSON.parse(await readFile(join(runfiles, packageJsonPath), 'utf8'));
20+
/** The version of typescript extracted from the package.json file. */
21+
let packageJsonVersion;
22+
try {
23+
packageJsonVersion =
24+
packageJson['dependencies']?.['typescript'] || packageJson['devDependencies']?.['typescript'];
25+
} catch {
26+
console.error('Unable to find the typescript version within the package.json file.');
27+
}
28+
29+
/** The version of typescript extracted from the BAZEL.module.lock file. */
30+
let lockfileVersion;
31+
try {
32+
// The path to the generated repo specs is static based on the location of the extension
33+
// used. The name of the generated repo is determined by the user so we instead need to take
34+
// the first value/item from the `generaredRepoSpecs` property and get the version from the
35+
// attributes there.
36+
const generatedRepoSpecs =
37+
moduleLock['moduleExtensions']?.['@@aspect_rules_ts~//ts:extensions.bzl%ext']?.['general']?.[
38+
'generatedRepoSpecs'
39+
];
40+
lockfileVersion =
41+
Object.values(generatedRepoSpecs || {})[0]?.['attributes']?.['version'] || 'unknown';
42+
} catch {
43+
console.error('Unable to find the typescript version within the MODULE.bazel.lock file.');
44+
}
45+
46+
// If either version is undefined, the comparison is invalid and we should exit.
47+
if (packageJsonVersion === undefined || lockfileVersion === undefined) {
48+
process.exitCode = 1;
49+
return;
50+
}
51+
52+
// If the versions don't match, exit as a failure.
53+
if (packageJsonVersion !== lockfileVersion) {
54+
console.error(
55+
`Typescript version mismatch between MODULE.bazel (${lockfileVersion}) and package.json (${packageJsonVersion})`,
56+
);
57+
process.exitCode = 1;
58+
return;
59+
}
60+
61+
console.info(
62+
`Typescript version matches between MODULE.bazel and package.json: ${lockfileVersion}`,
63+
);
64+
}
65+
66+
main(process.argv.slice(2)).catch((e) => {
67+
console.error(e);
68+
process.exit(2);
69+
});

0 commit comments

Comments
 (0)