Skip to content

Commit f84ca05

Browse files
committed
build: prepare NPM packages for use in Bazel-based integration tests
Updates the build tooling to prepare NPM packages from the project `package.json` to be accessible to the Bazel-based integration tests. The idea is to build tarballs for all NPM packages which can be mapped into Bazel-based integration tests. This allows us to only have a single dependency on e.g. the CLI, instead of having to maintain/update multiple versions of the CLI and devkit (as an example). Additionally, we will expose tarballs for the first-party built NPM packages like the CDK or Angular Material. Lastly, we will populate the `0.0.0-PLACEHOLDER` with an actual version when stamping is disabled. This allows us to use the first-party built NPM packages in tests with `yarn`. Yarn would otherwise complain about an invalid version.
1 parent b4e4700 commit f84ca05

File tree

6 files changed

+132
-7
lines changed

6 files changed

+132
-7
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
node_modules
1111
/bower_components
1212

13+
# Angular CLI project cache
14+
.angular/
15+
1316
# Dart
1417
/.pub
1518
/.packages

WORKSPACE

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ http_archive(
3434
],
3535
)
3636

37+
http_archive(
38+
name = "rules_pkg",
39+
sha256 = "a89e203d3cf264e564fcb96b6e06dd70bc0557356eb48400ce4b5d97c2c3720d",
40+
urls = [
41+
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz",
42+
"https://github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz",
43+
],
44+
)
45+
46+
load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
47+
48+
rules_pkg_dependencies()
49+
3750
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
3851

3952
bazel_skylib_workspace()
@@ -47,13 +60,17 @@ node_repositories(
4760
package_json = ["//:package.json"],
4861
)
4962

63+
load("//tools:integration.bzl", "create_npm_package_archive_build_file")
64+
5065
yarn_install(
5166
name = "npm",
5267
# We add the postinstall patches file here so that Yarn will rerun whenever
5368
# the file is modified.
5469
data = [
5570
"//:tools/postinstall/apply-patches.js",
5671
],
72+
# Add archive targets for some NPM packages that are needed in integration tests.
73+
manual_build_file_contents = create_npm_package_archive_build_file(),
5774
package_json = "//:package.json",
5875
quiet = False,
5976
yarn_lock = "//:yarn.lock",

packages.bzl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ MDC_PACKAGE_VERSION = "13.0.0-canary.860ad06a1.0"
66
TSLIB_PACKAGE_VERSION = "^2.3.0"
77
RXJS_PACKAGE_VERSION = "^6.5.3 || ^7.0.0"
88

9-
# Each placer holder is used to stamp versions during the build process, replacing the key with it's
9+
# Each placeholder is used to stamp versions during the build process, replacing the key with it's
1010
# value pair. These replacements occur during building of `npm_package` and `ng_package` stamping in
1111
# the peer dependencies and versions, primarily in `package.json`s.
12-
VERSION_PLACEHOLDER_REPLACEMENTS = {
12+
NPM_PACKAGE_SUBSTITUTIONS = {
1313
# Version of `material-components-web`
1414
"0.0.0-MDC": MDC_PACKAGE_VERSION,
1515
# Version of `@angular/core`
@@ -22,6 +22,11 @@ VERSION_PLACEHOLDER_REPLACEMENTS = {
2222
"0.0.0-RXJS": RXJS_PACKAGE_VERSION,
2323
}
2424

25+
TEST_NPM_PACKAGE_SUBSTITUTIONS = dict(NPM_PACKAGE_SUBSTITUTIONS, **{
26+
# When building NPM packages for tests, we use `0.0.0` for the version placeholder.
27+
"0.0.0-PLACEHOLDER": "0.0.0",
28+
})
29+
2530
# List of MDC packages.
2631
MDC_PACKAGES = [
2732
"@material/animation",

tools/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ config_setting(
1313
},
1414
)
1515

16+
# Detect if the build is running with stamping enabled.
17+
config_setting(
18+
name = "stamp",
19+
values = {"stamp": "true"},
20+
)
21+
1622
# This file generates the `angular_ivy_enabled.js` file, which exports a truthy value
1723
# whether Ivy should be enabled based on the `--defined=angular_ivy_enabled` value
1824
# so runtime can detect which mode it is running in.

tools/defaults.bzl

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
# Re-export of Bazel rules with repository-wide defaults
22

3+
load("@rules_pkg//:pkg.bzl", "pkg_tar")
34
load("@build_bazel_rules_nodejs//:index.bzl", _pkg_npm = "pkg_npm")
45
load("@io_bazel_rules_sass//:defs.bzl", _npm_sass_library = "npm_sass_library", _sass_binary = "sass_binary", _sass_library = "sass_library")
56
load("@npm//@angular/bazel:index.bzl", _ng_module = "ng_module", _ng_package = "ng_package")
7+
load("@npm//@angular/dev-infra-private/bazel/integration:index.bzl", _integration_test = "integration_test")
68
load("@npm//@bazel/jasmine:index.bzl", _jasmine_node_test = "jasmine_node_test")
79
load("@npm//@bazel/concatjs:index.bzl", _karma_web_test = "karma_web_test", _karma_web_test_suite = "karma_web_test_suite")
810
load("@npm//@bazel/protractor:index.bzl", _protractor_web_test_suite = "protractor_web_test_suite")
911
load("@npm//@bazel/typescript:index.bzl", _ts_library = "ts_library")
10-
load("//:packages.bzl", "VERSION_PLACEHOLDER_REPLACEMENTS")
12+
load("//:packages.bzl", "NPM_PACKAGE_SUBSTITUTIONS", "TEST_NPM_PACKAGE_SUBSTITUTIONS")
1113
load("//:pkg-externals.bzl", "PKG_EXTERNALS")
1214
load("//tools/markdown-to-html:index.bzl", _markdown_to_html = "markdown_to_html")
1315
load("//tools/spec-bundling:index.bzl", "spec_bundle")
1416

1517
_DEFAULT_TSCONFIG_BUILD = "//src:bazel-tsconfig-build.json"
1618
_DEFAULT_TSCONFIG_TEST = "//src:tsconfig-test"
1719

20+
npmPackageSubstitutions = select({
21+
"//tools:stamp": NPM_PACKAGE_SUBSTITUTIONS,
22+
"//conditions:default": TEST_NPM_PACKAGE_SUBSTITUTIONS,
23+
})
24+
1825
# Re-exports to simplify build file load statements
1926
markdown_to_html = _markdown_to_html
27+
integration_test = _integration_test
2028

2129
def _compute_module_name(testonly):
2230
current_pkg = native.package_name()
@@ -147,7 +155,7 @@ def ng_module(
147155
**kwargs
148156
)
149157

150-
def ng_package(name, data = [], deps = [], externals = PKG_EXTERNALS, readme_md = None, **kwargs):
158+
def ng_package(name, data = [], deps = [], externals = PKG_EXTERNALS, readme_md = None, visibility = None, **kwargs):
151159
# If no readme file has been specified explicitly, use the default readme for
152160
# release packages from "src/README.md".
153161
if not readme_md:
@@ -183,12 +191,24 @@ def ng_package(name, data = [], deps = [], externals = PKG_EXTERNALS, readme_md
183191
package_name = None,
184192
validate = False,
185193
readme_md = readme_md,
186-
substitutions = VERSION_PLACEHOLDER_REPLACEMENTS,
194+
substitutions = npmPackageSubstitutions,
195+
visibility = visibility,
187196
**kwargs
188197
)
189198

190-
def pkg_npm(**kwargs):
199+
pkg_tar(
200+
name = name + "_archive",
201+
srcs = [":%s" % name],
202+
extension = "tar.gz",
203+
strip_prefix = "./%s" % name,
204+
# Target should not build on CI unless it is explicitly requested.
205+
tags = ["manual"],
206+
visibility = visibility,
207+
)
208+
209+
def pkg_npm(name, visibility = None, **kwargs):
191210
_pkg_npm(
211+
name = name,
192212
# We never set a `package_name` for NPM packages, neither do we enable validation.
193213
# This is necessary because the source targets of the NPM packages all have
194214
# package names set and setting a similar `package_name` on the NPM package would
@@ -204,10 +224,21 @@ def pkg_npm(**kwargs):
204224
# https://github.com/bazelbuild/rules_nodejs/issues/2810.
205225
package_name = None,
206226
validate = False,
207-
substitutions = VERSION_PLACEHOLDER_REPLACEMENTS,
227+
substitutions = npmPackageSubstitutions,
228+
visibility = visibility,
208229
**kwargs
209230
)
210231

232+
pkg_tar(
233+
name = name + "_archive",
234+
srcs = [":%s" % name],
235+
extension = "tar.gz",
236+
strip_prefix = "./%s" % name,
237+
# Target should not build on CI unless it is explicitly requested.
238+
tags = ["manual"],
239+
visibility = visibility,
240+
)
241+
211242
def jasmine_node_test(**kwargs):
212243
kwargs["templated_args"] = ["--bazel_patch_module_resolver"] + kwargs.get("templated_args", [])
213244
_jasmine_node_test(**kwargs)
@@ -306,6 +337,23 @@ def protractor_web_test_suite(name, deps, **kwargs):
306337
**kwargs
307338
)
308339

340+
def node_integration_test(data = [], tool_mappings = {}, **kwargs):
341+
"""Macro for defining an integration test with `node` and `yarn` being
342+
declared as global tools."""
343+
344+
integration_test(
345+
data = data + [
346+
# The Yarn files also need to be part of the integration test as runfiles
347+
# because the `yarn_bin` target is not a self-contained standalone binary.
348+
"@nodejs//:yarn_files",
349+
],
350+
tool_mappings = dict(tool_mappings, **{
351+
"@nodejs//:yarn_bin": "yarn",
352+
"@nodejs//:node_bin": "node",
353+
}),
354+
**kwargs
355+
)
356+
309357
def ng_web_test_suite(deps = [], static_css = [], exclude_init_script = False, **kwargs):
310358
bootstrap = [
311359
# This matches the ZoneJS bundles used in default CLI projects. See:

tools/integration.bzl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
load("//:packages.bzl", "ANGULAR_PACKAGES")
2+
3+
"""File which manages the NPM packages from the workspace `@npm` repository which
4+
should be available to integration tests"""
5+
6+
def _get_archive_label_of_package(package_name):
7+
return package_name.replace("/", "_").replace("@", "") + "_archive"
8+
9+
INTEGRATION_TEST_PACKAGES = [pkg.module_name for pkg in ANGULAR_PACKAGES] + [
10+
"@angular/cli",
11+
"@angular/compiler-cli",
12+
"@angular-devkit/build-angular",
13+
"typescript",
14+
"rxjs",
15+
]
16+
17+
CLI_PROJECT_MAPPINGS = {
18+
"@npm//:%s" % _get_archive_label_of_package(pkg): pkg
19+
for pkg in INTEGRATION_TEST_PACKAGES
20+
}
21+
22+
def create_npm_package_archive_build_file():
23+
"""Creates the contents of a `BUILD.bazel` file for exposing NPM package tarballs
24+
for the integration test packages configured in the constant.
25+
26+
The `BUILD.bazel` file contents are supposed to be placed into the `@npm//`
27+
workspace top-level BUILD file. This is necessary because all files of a NPM
28+
package are not accessible outside from the `@npm//` workspace.
29+
"""
30+
31+
result = """load("@rules_pkg//:pkg.bzl", "pkg_tar")"""
32+
33+
for pkg in INTEGRATION_TEST_PACKAGES:
34+
label_name = _get_archive_label_of_package(pkg)
35+
last_segment = pkg.split("/")[-1]
36+
37+
result += """
38+
pkg_tar(
39+
name = "{label_name}",
40+
srcs = ["//{name}:{last_segment}__all_files"],
41+
extension = "tar.gz",
42+
strip_prefix = "/external/npm/node_modules/{name}",
43+
tags = ["manual"],
44+
)""".format(name = pkg, label_name = label_name, last_segment = last_segment)
45+
46+
return result

0 commit comments

Comments
 (0)