Skip to content

Commit 9c99aeb

Browse files
committed
build: add script to diff local npm package with snapshot repository
This script will be very useful for the `rules_js` migration, as it allows us to quickly spot differences between the local `npm_package` target and the valid golden (based on the snapshot repository).
1 parent 81a83df commit 9c99aeb

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed

scripts/diff-release-package.mts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
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+
/**
10+
* Script that can be used to compare the local `npm_package` snapshot artifact
11+
* with the snapshot artifact from GitHub at upstream `HEAD`.
12+
*
13+
* This is useful during the `rules_js` migration to verify the npm artifact
14+
* doesn't differ unexpectedly.
15+
*
16+
* Run via:
17+
* node --loader ts-node/esm/transpile-only scripts/diff-release-package.mts <pkg-name>
18+
*/
19+
20+
import { GitClient } from '@angular/ng-dev';
21+
import childProcess from 'node:child_process';
22+
import fs from 'node:fs';
23+
import os from 'node:os';
24+
import path from 'node:path';
25+
import sh from 'shelljs';
26+
27+
// Do not remove `.git` as we use Git for comparisons later.
28+
// Also preserve `uniqueId` as it's irrelevant for the diff and not included via Bazel.
29+
// The `README.md` is also put together outside of Bazel, so ignore it too.
30+
const SKIP_FILES = ['README.md', 'uniqueId', '.git'];
31+
32+
const packageName = process.argv[2];
33+
if (!packageName) {
34+
console.error('Expected package name to be specified.');
35+
process.exit(1);
36+
}
37+
38+
try {
39+
await main(packageName);
40+
} catch (e) {
41+
console.error(e);
42+
process.exitCode = 1;
43+
}
44+
45+
async function main(packageName: string) {
46+
const bazel = process.env.BAZEL ?? 'bazel';
47+
const git = await GitClient.get();
48+
const monorepoData = JSON.parse(fs.readFileSync('./.monorepo.json', 'utf-8'));
49+
const targetDir = packageName.replace(/^@/g, '').replace(/-/g, '_');
50+
51+
const snapshotRepoName = monorepoData.packages[packageName]?.snapshotRepo;
52+
const tmpDir = await fs.promises.mkdtemp(
53+
path.join(os.tmpdir(), `diff-release-package-${snapshotRepoName.replace(/\//g, '_')}`),
54+
);
55+
56+
console.log(`Cloning snapshot repo (${snapshotRepoName}) into ${tmpDir}..`);
57+
git.run(['clone', `https://github.com/${snapshotRepoName}.git`, tmpDir]);
58+
console.log(`--> Cloned snapshot repo.`);
59+
60+
const bazelBinDir = childProcess
61+
.spawnSync(bazel, ['info', 'bazel-bin'], {
62+
shell: true,
63+
encoding: 'utf8',
64+
})
65+
.stdout.trim();
66+
const outputPath = path.join(bazelBinDir, 'packages/', targetDir, 'npm_package');
67+
68+
// Delete old directory to avoid surprises, or stamping being outdated.
69+
await deleteDir(outputPath);
70+
71+
childProcess.spawnSync(
72+
bazel,
73+
['build', `//packages/${targetDir}:npm_package`, '--config=snapshot'],
74+
{
75+
shell: true,
76+
stdio: 'inherit',
77+
encoding: 'utf8',
78+
},
79+
);
80+
81+
console.log('--> Built npm package with --config=snapshot');
82+
console.error(`--> Output: ${outputPath}`);
83+
84+
const removeTasks: Promise<void>[] = [];
85+
for (const subentry of await fs.promises.readdir(tmpDir)) {
86+
if (SKIP_FILES.includes(subentry)) {
87+
continue;
88+
}
89+
90+
removeTasks.push(
91+
fs.promises.rm(path.join(tmpDir, subentry), { recursive: true, maxRetries: 3 }),
92+
);
93+
}
94+
await Promise.all(removeTasks);
95+
96+
const copyTasks: Promise<void>[] = [];
97+
for (const subentry of await fs.promises.readdir(outputPath)) {
98+
if (SKIP_FILES.includes(subentry)) {
99+
continue;
100+
}
101+
102+
copyTasks.push(
103+
fs.promises.cp(path.join(outputPath, subentry), path.join(tmpDir, subentry), {
104+
recursive: true,
105+
}),
106+
);
107+
}
108+
await Promise.all(copyTasks);
109+
110+
git.run(['config', 'core.filemode', 'false'], { cwd: tmpDir });
111+
112+
const diff = git.run(['diff', '--color'], { cwd: tmpDir }).stdout;
113+
114+
console.log('\n\n----- Diff ------');
115+
console.log(diff);
116+
117+
await deleteDir(tmpDir);
118+
}
119+
120+
async function deleteDir(dirPath: string) {
121+
// Needed as Bazel artifacts are readonly and cannot be deleted otherwise.
122+
sh.chmod('-R', 'u+w', dirPath);
123+
await fs.promises.rm(dirPath, { recursive: true, force: true, maxRetries: 3 });
124+
}

0 commit comments

Comments
 (0)