Skip to content

Commit 5428e93

Browse files
devversionjelbourn
authored andcommitted
build: rework package-builder script to node script (#17758)
Reworks the package-builder script from a Bash script to a NodeJS script. This makes it work better in all platforms, and makes the script more maintainable. Best example is how easy it can be integrated into the release tool. Framework did the same recently.
1 parent 3a204da commit 5428e93

File tree

5 files changed

+131
-95
lines changed

5 files changed

+131
-95
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ jobs:
297297
- *yarn_install
298298
- *setup_bazel_binary
299299

300-
- run: ./scripts/build-packages-dist.sh
300+
- run: yarn build
301301
- run: yarn check-release-output
302302

303303
# TODO(devversion): replace this with bazel tests that run Madge. This is

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"scripts": {
1616
"postinstall": "node tools/bazel/postinstall-patches.js && ngcc --properties main --create-ivy-entry-points",
17-
"build": "bash ./scripts/build-packages-dist.sh",
17+
"build": "node ./scripts/build-packages-dist.js",
1818
"bazel:buildifier": "find . -type f \\( -name \"*.bzl\" -or -name WORKSPACE -or -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs buildifier -v --warnings=attr-cfg,attr-license,attr-non-empty,attr-output-default,attr-single-file,constant-glob,ctx-args,depset-iteration,depset-union,dict-concatenation,duplicated-name,filetype,git-repository,http-archive,integer-division,load,load-on-top,native-build,native-package,output-group,package-name,package-on-top,redefined-variable,repository-name,same-origin-load,string-iteration,unused-variable,unsorted-dict-items,out-of-order-load",
1919
"bazel:format-lint": "yarn -s bazel:buildifier --lint=warn --mode=check",
2020
"dev-app": "ibazel run //src/dev-app:devserver",

scripts/build-packages-dist.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Script that builds the release output of all packages which have the "release-package
5+
* bazel tag set. The script builds all those packages and copies the release output to the
6+
* distribution folder within the project.
7+
*/
8+
9+
const {execSync} = require('child_process');
10+
const {join} = require('path');
11+
const {chmod, cp, mkdir, rm, set, test} = require('shelljs');
12+
13+
// ShellJS should exit if a command fails.
14+
set('-e');
15+
16+
/** Name of the Bazel tag that will be used to find release package targets. */
17+
const releaseTargetTag = 'release-package';
18+
19+
/** Path to the project directory. */
20+
const projectDir = join(__dirname, '../');
21+
22+
/** Command that runs Bazel. */
23+
const bazelCmd = process.env.BAZEL_COMMAND || `yarn -s bazel`;
24+
25+
/** Command that queries Bazel for all release package targets. */
26+
const queryPackagesCmd =
27+
`${bazelCmd} query --output=label "attr('tags', '\\[.*${releaseTargetTag}.*\\]', //src/...) ` +
28+
`intersect kind('.*_package', //src/...)"`;
29+
30+
// Export the methods for building the release packages. These
31+
// can be consumed by the release tool.
32+
exports.buildReleasePackages = buildReleasePackages;
33+
exports.defaultBuildReleasePackages = defaultBuildReleasePackages;
34+
35+
if (module === require.main) {
36+
defaultBuildReleasePackages();
37+
}
38+
39+
/**
40+
* Builds the release packages with the default compile mode and
41+
* output directory.
42+
*/
43+
function defaultBuildReleasePackages() {
44+
buildReleasePackages('legacy', join(projectDir, 'dist/releases'));
45+
}
46+
47+
/**
48+
* Builds the release packages with the given compile mode and copies
49+
* the package output into the given directory.
50+
*/
51+
function buildReleasePackages(compileMode, distPath) {
52+
console.log('######################################');
53+
console.log(' Building release packages...');
54+
console.log(` Compile mode: ${compileMode}`);
55+
console.log('######################################');
56+
57+
// List of targets to build. e.g. "src/cdk:npm_package", or "src/material:npm_package".
58+
const targets = exec(queryPackagesCmd, true).split(/\r?\n/);
59+
const packageNames = getPackageNamesOfTargets(targets);
60+
const bazelBinPath = exec(`${bazelCmd} info bazel-bin`, true);
61+
const getOutputPath = pkgName => join(bazelBinPath, 'src', pkgName, 'npm_package');
62+
63+
// Walk through each release package and clear previous "npm_package" outputs. This is
64+
// a workaround for: https://github.com/bazelbuild/rules_nodejs/issues/1219. We need to
65+
// do this to ensure that the version placeholders are properly populated.
66+
packageNames.forEach(pkgName => {
67+
const outputPath = getOutputPath(pkgName);
68+
if (test('-d', outputPath)) {
69+
chmod('-R', 'u+w', outputPath);
70+
rm('-rf', outputPath);
71+
}
72+
});
73+
74+
// Build with "--config=release" so that Bazel runs the workspace stamping script. The
75+
// stamping script ensures that the version placeholder is populated in the release output.
76+
exec(`${bazelCmd} build --config=release --define=compile=${compileMode} ${targets.join(' ')}`);
77+
78+
// Delete the distribution directory so that the output is guaranteed to be clean. Re-create
79+
// the empty directory so that we can copy the release packages into it later.
80+
rm('-rf', distPath);
81+
mkdir('-p', distPath);
82+
83+
// Copy the package output into the specified distribution folder.
84+
packageNames.forEach(pkgName => {
85+
const outputPath = getOutputPath(pkgName);
86+
const targetFolder = join(distPath, pkgName);
87+
console.log(`> Copying package output to "${targetFolder}"`);
88+
cp('-R', outputPath, targetFolder);
89+
chmod('-R', 'u+w', targetFolder);
90+
});
91+
}
92+
93+
/**
94+
* Gets the package names of the specified Bazel targets.
95+
* e.g. //src/material:npm_package -> material
96+
*/
97+
function getPackageNamesOfTargets(targets) {
98+
return targets.map(targetName => {
99+
const matches = targetName.match(/\/\/src\/(.*):npm_package/);
100+
if (matches === null) {
101+
throw Error(`Found Bazel target with "${releaseTargetTag}" tag, but could not ` +
102+
`determine release output name: ${targetName}`);
103+
}
104+
return matches[1];
105+
});
106+
}
107+
108+
/**
109+
* Executes the given command in the project directory.
110+
* @param {string} command The command to run
111+
* @param {boolean=} captureStdout Whether the stdout should be captured and
112+
* returned.
113+
*/
114+
function exec(command, captureStdout) {
115+
const stdout = execSync(command, {
116+
cwd: projectDir,
117+
stdio: ['inherit', captureStdout ? 'pipe' : 'inherit', 'inherit'],
118+
});
119+
120+
if (captureStdout) {
121+
process.stdout.write(stdout);
122+
return stdout.toString().trim();
123+
}
124+
}

scripts/build-packages-dist.sh

Lines changed: 0 additions & 81 deletions
This file was deleted.

tools/release/publish-release.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import chalk from 'chalk';
2-
import {spawnSync} from 'child_process';
32
import {readFileSync, unlinkSync} from 'fs';
43
import {homedir} from 'os';
54
import {join} from 'path';
@@ -15,6 +14,10 @@ import {releasePackages} from './release-output/release-packages';
1514
import {CHANGELOG_FILE_NAME} from './stage-release';
1615
import {parseVersionName, Version} from './version-name/parse-version';
1716

17+
// The package builder script is not written in TypeScript and needs to
18+
// be imported through a CommonJS import.
19+
const {defaultBuildReleasePackages} = require('../../scripts/build-packages-dist');
20+
1821
/**
1922
* Class that can be instantiated in order to create a new release. The tasks requires user
2023
* interaction/input through command line prompts.
@@ -87,7 +90,7 @@ class PublishReleaseTask extends BaseReleaseTask {
8790
await this._promptStableVersionForNextTag();
8891
}
8992

90-
this._buildReleasePackages();
93+
defaultBuildReleasePackages();
9194
console.info(chalk.green(` ✓ Built the release output.`));
9295

9396
// Checks all release packages against release output validations before releasing.
@@ -149,16 +152,6 @@ class PublishReleaseTask extends BaseReleaseTask {
149152
}
150153
}
151154

152-
/** Builds all release packages that should be published. */
153-
private _buildReleasePackages() {
154-
const buildScript = join(this.projectDir, 'scripts/build-packages-dist.sh');
155-
156-
// TODO(devversion): I'd prefer disabling the output for those, but it might be only
157-
// worth if we consider adding some terminal spinner library (like "ora").
158-
return spawnSync('bash', [buildScript],
159-
{cwd: this.projectDir, stdio: 'inherit', shell: true}).status === 0;
160-
}
161-
162155
/**
163156
* Prompts the user whether they are sure that the current stable version should be
164157
* released to the "next" NPM dist-tag.

0 commit comments

Comments
 (0)