Skip to content

Commit 8e78b4e

Browse files
devversionthePunderWoman
authored andcommitted
build: add script to diff packages and ensure no unexpected changes (#61275)
Adds a script to diff snapshot packages to allow for easy verification that no unexpected changes were made. PR Close #61275
1 parent 925b923 commit 8e78b4e

File tree

4 files changed

+152
-11
lines changed

4 files changed

+152
-11
lines changed

.aspect/rules/external_repository_action_cache/npm_translate_lock_MzA5NzUwNzMx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
# Input hashes for repository rule npm_translate_lock(name = "npm2", pnpm_lock = "@//:pnpm-lock.yaml").
33
# This file should be checked into version control along with the pnpm-lock.yaml file.
44
.npmrc=-1406867100
5-
package.json=-686175807
5+
package.json=1344581013
66
packages/compiler-cli/package.json=-1767555217
77
packages/compiler/package.json=-426903429
8-
pnpm-lock.yaml=-445193031
8+
pnpm-lock.yaml=953012603
99
pnpm-workspace.yaml=353334404
1010
tools/bazel/rules_angular_store/package.json=-239561259
1111
yarn.lock=1067917288

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
"devtools:test": "bazelisk test --//devtools/projects/shell-browser/src:flag_browser=chrome -- //devtools/...",
4545
"docs": "[[ -n $CI ]] && echo 'Cannot run this yarn script on CI' && exit 1 || yarn ibazel run //adev:serve",
4646
"docs:build": "[[ -n $CI ]] && echo 'Cannot run this yarn script on CI' && exit 1 || yarn bazel build //adev:build",
47-
"benchmarks": "tsx --tsconfig=scripts/tsconfig.json scripts/benchmarks/index.mts"
47+
"benchmarks": "tsx --tsconfig=scripts/tsconfig.json scripts/benchmarks/index.mts",
48+
"diff-release-package": "tsx --tsconfig=scripts/tsconfig.json scripts/diff-release-package.mts"
4849
},
4950
"// 1": "dependencies are used locally and by bazel",
5051
"dependencies": {

pnpm-lock.yaml

Lines changed: 3 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/diff-release-package.mts

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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+
* Example command: pnpm diff-release-package @angular/cli
17+
*/
18+
19+
import {GitClient} from '@angular/ng-dev';
20+
import childProcess from 'node:child_process';
21+
import fs from 'node:fs';
22+
import os from 'node:os';
23+
import path from 'node:path';
24+
import sh from 'shelljs';
25+
import {glob} from 'tinyglobby';
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$/, /\.map$/];
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 targetDir = packageName.replace(/^@/g, '').replace(/-/g, '_');
49+
50+
const snapshotRepoName = `angular/${packageName}-builds`;
51+
52+
const tmpDir = await fs.promises.mkdtemp(
53+
path.join(os.tmpdir(), `diff-release-package-${snapshotRepoName.replace(/\//g, '_')}`),
54+
);
55+
56+
console.info(`Cloning snapshot repo (${snapshotRepoName}) into ${tmpDir}..`);
57+
git.run(['clone', '--depth=1', `https://github.com/${snapshotRepoName}.git`, tmpDir]);
58+
console.info(`--> Cloned snapshot repo.`);
59+
60+
const bazelBinDir = childProcess
61+
.spawnSync(bazel, ['info', 'bazel-bin'], {
62+
shell: true,
63+
encoding: 'utf8',
64+
stdio: ['pipe', 'pipe', 'inherit'],
65+
})
66+
.stdout.trim();
67+
if (bazelBinDir === '') {
68+
throw new Error('Could not determine bazel-bin directory.');
69+
}
70+
71+
const outputPath = path.join(bazelBinDir, 'packages/', targetDir, 'npm_package');
72+
73+
// Delete old directory to avoid surprises, or stamping being outdated.
74+
await deleteDir(outputPath);
75+
76+
childProcess.spawnSync(
77+
bazel,
78+
['build', `//packages/${targetDir}:npm_package`, '--config=snapshot-build'],
79+
{
80+
shell: true,
81+
stdio: 'inherit',
82+
encoding: 'utf8',
83+
},
84+
);
85+
86+
console.info('--> Built npm package with --config=snapshot-build');
87+
console.error(`--> Output: ${outputPath}`);
88+
89+
const removeTasks: Promise<void>[] = [];
90+
for (const subentry of await glob('**/*', {
91+
dot: true,
92+
cwd: tmpDir,
93+
onlyFiles: true,
94+
ignore: ['.git'],
95+
})) {
96+
if (!SKIP_FILES.some((s) => s.test(subentry))) {
97+
continue;
98+
}
99+
100+
removeTasks.push(fs.promises.rm(path.join(tmpDir, subentry), {maxRetries: 3}));
101+
}
102+
await Promise.all(removeTasks);
103+
104+
// Stage all removed files that were skipped; to exclude them from the diff.
105+
git.run(['add', '-A'], {cwd: tmpDir});
106+
git.run(['commit', '-m', 'Delete skipped files for diff'], {cwd: tmpDir});
107+
108+
const copyTasks: Promise<void>[] = [];
109+
for (const subentry of await glob('**/*', {
110+
dot: true,
111+
cwd: outputPath,
112+
onlyFiles: true,
113+
ignore: ['.git'],
114+
})) {
115+
if (SKIP_FILES.some((s) => s.test(subentry))) {
116+
continue;
117+
}
118+
119+
copyTasks.push(
120+
fs.promises.cp(path.join(outputPath, subentry), path.join(tmpDir, subentry), {
121+
recursive: true,
122+
}),
123+
);
124+
}
125+
await Promise.all(copyTasks);
126+
127+
git.run(['config', 'core.filemode', 'false'], {cwd: tmpDir});
128+
129+
const diff = git.run(['diff', '--color'], {cwd: tmpDir}).stdout;
130+
131+
console.info('\n\n----- Diff ------');
132+
console.info(diff);
133+
134+
await deleteDir(tmpDir);
135+
}
136+
137+
async function deleteDir(dirPath: string) {
138+
if (!fs.existsSync(dirPath)) {
139+
return;
140+
}
141+
142+
// Needed as Bazel artifacts are readonly and cannot be deleted otherwise.
143+
sh.chmod('-R', 'u+w', dirPath);
144+
await fs.promises.rm(dirPath, {recursive: true, force: true, maxRetries: 3});
145+
}

0 commit comments

Comments
 (0)