Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ jobs:

# Exclude release and docs packages here as those will be built within
# the "build_release_packages" and "publish_snapshots" jobs.
- run: bazel build src/... --build_tag_filters=-docs-package,-release-package
# TODO(devversion): remove target exclusion once https://github.com/bazelbuild/rules_nodejs/pull/2646 is available.
- run: bazel build --build_tag_filters=-docs-package,-release-package -- src/... -//src/e2e-app:devserver_with_linked_declarations.MF
- *slack_notify_on_failure

# -----------------------------------
Expand All @@ -219,7 +220,8 @@ jobs:

# Exclude release and docs packages here as those will be built within
# the "build_release_packages" and "publish_snapshots" jobs.
- run: bazel build src/... --build_tag_filters=-docs-package,-release-package --config=view-engine
# TODO(devversion): remove target exclusion once https://github.com/bazelbuild/rules_nodejs/pull/2646 is available.
- run: bazel build --build_tag_filters=-docs-package,-release-package --config=view-engine -- src/... -//src/e2e-app:devserver_with_linked_declarations.MF
- *slack_notify_on_failure

# --------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -281,7 +283,8 @@ jobs:
- *yarn_install
- *setup_bazel_binary

- run: bazel test src/... --build_tag_filters=-e2e --test_tag_filters=-e2e --build_tests_only
# TODO(devversion): remove target exclusion once https://github.com/bazelbuild/rules_nodejs/pull/2646 is available.
- run: bazel test --build_tag_filters=-e2e --test_tag_filters=-e2e --build_tests_only -- src/... -//src/e2e-app:devserver_with_linked_declarations.MF
- *slack_notify_on_failure

# ----------------------------------------------------------------------------
Expand Down Expand Up @@ -533,7 +536,8 @@ jobs:
- *yarn_install_loose_lockfile
- *setup_bazel_binary

- run: bazel test src/... --build_tag_filters=-e2e --test_tag_filters=-e2e --build_tests_only
# TODO(devversion): remove target exclusion once https://github.com/bazelbuild/rules_nodejs/pull/2646 is available.
- run: bazel test --build_tag_filters=-e2e --test_tag_filters=-e2e --build_tests_only -- src/... -//src/e2e-app:devserver_with_linked_declarations.MF
- *slack_notify_on_failure

# ----------------------------------------------------------------------------
Expand All @@ -554,7 +558,8 @@ jobs:
- *setup_bazel_binary

# Run project tests with NGC and View Engine.
- run: bazel test src/... --build_tag_filters=-docs-package,-e2e --test_tag_filters=-e2e --config=view-engine --build_tests_only
# TODO(devversion): remove target exclusion once https://github.com/bazelbuild/rules_nodejs/pull/2646 is available.
- run: bazel test --build_tag_filters=-docs-package,-e2e --test_tag_filters=-e2e --config=view-engine --build_tests_only -- src/... -//src/e2e-app:devserver_with_linked_declarations.MF
- *slack_notify_on_failure

# ----------------------------------------------------------------------------
Expand All @@ -575,7 +580,8 @@ jobs:
- *setup_bazel_binary

# Run project tests with NGC and View Engine.
- run: bazel test src/... --build_tag_filters=-docs-package,-e2e --test_tag_filters=-e2e --config=view-engine --build_tests_only
# TODO(devversion): remove target exclusion once https://github.com/bazelbuild/rules_nodejs/pull/2646 is available.
- run: bazel test --build_tag_filters=-docs-package,-e2e --test_tag_filters=-e2e --config=view-engine --build_tests_only -- src/... -//src/e2e-app:devserver_with_linked_declarations.MF
- *slack_notify_on_failure

# ----------------------------------------------------------------------------
Expand All @@ -593,6 +599,9 @@ jobs:
- *setup_bazel_remote_execution
- *yarn_install
- *setup_bazel_binary

- run: yarn integration-tests:partial-ivy
- run: yarn integration-tests:view-engine
# TODO: Re-enable when there are integration tests that should run with Ivy.
# Currently this command fails as there are no tests.
# - run: yarn integration-tests
Expand All @@ -601,7 +610,26 @@ jobs:
command: |
# If the size integration tests fail, report the failure to a dedicated #components-ci-size-tracking Slack channel.
yarn integration-tests:size-test || node ./scripts/circleci/notify-slack-job-failure.js components-ci-size-tracking
- run: yarn integration-tests:view-engine
- *slack_notify_on_failure

# ----------------------------------------------------------------------------
# Job that runs all integration tests against Angular snapshot builds.
# ----------------------------------------------------------------------------
integration_tests_snapshot:
<<: *job_defaults
resource_class: xlarge
environment:
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
steps:
- checkout_and_rebase
- *restore_cache
- *setup_bazel_ci_config
- *setup_bazel_remote_execution
- *setup_snapshot_builds
- *yarn_install_loose_lockfile
- *setup_bazel_binary

- run: yarn integration-tests:partial-ivy
- *slack_notify_on_failure

# ----------------------------------------------------------------------------
Expand All @@ -626,7 +654,8 @@ jobs:

# Setup the components repository to use the MDC snapshot builds.
# Run project tests with the MDC canary builds.
- run: bazel test src/... --build_tag_filters=-docs-package,-e2e --test_tag_filters=-e2e --build_tests_only
# TODO(devversion): remove target exclusion once https://github.com/bazelbuild/rules_nodejs/pull/2646 is available.
- run: bazel test --build_tag_filters=-docs-package,-e2e --test_tag_filters=-e2e --build_tests_only -- src/... -//src/e2e-app:devserver_with_linked_declarations.MF
- *slack_notify_on_failure

# ----------------------------------------------------------------------------------------
Expand Down Expand Up @@ -695,6 +724,8 @@ workflows:
filters: *only_main_branch_filter
- mdc_snapshot_test_cronjob:
filters: *only_main_branch_filter
- integration_tests_snapshot:
filters: *only_main_branch_filter

triggers:
- schedule:
Expand Down
17 changes: 17 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@ http_archive(
],
)

# Add skylib which contains common Bazel utilities. Note that `rules_nodejs` would also
# bring in the skylib repository but with an older version that does not support shorthands
# for declaring Bazel build setting flags.
http_archive(
name = "bazel_skylib",
sha256 = "ebdf850bfef28d923a2cc67ddca86355a449b5e4f38b0a70e584dc24e5984aa6",
strip_prefix = "bazel-skylib-f80bc733d4b9f83d427ce3442be2e07427b2cc8d",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/archive/f80bc733d4b9f83d427ce3442be2e07427b2cc8d.tar.gz",
"https://github.com/bazelbuild/bazel-skylib/archive/f80bc733d4b9f83d427ce3442be2e07427b2cc8d.tar.gz",
],
)

load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")

bazel_skylib_workspace()

load("@build_bazel_rules_nodejs//:index.bzl", "check_bazel_version", "node_repositories", "yarn_install")

# The minimum bazel version to use with this repo is v3.1.0.
Expand Down
10 changes: 10 additions & 0 deletions integration/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")

package(default_visibility = ["//visibility:public"])

# JavaScript library that exposes a script for retrieving all NPM packages
# available in the runfiles of an action.
js_library(
name = "npm-packages-from-runfiles",
srcs = ["npm-packages-from-runfiles.js"],
)
23 changes: 23 additions & 0 deletions integration/linker/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")

# Test which ensures that specified NPM packages can be transformed from their partial
# declarations to definitions using the `@angular/compiler-cli` linker babel plugin.
nodejs_test(
name = "linker",
data = [
"//integration:npm-packages-from-runfiles",
"//src/cdk:npm_package",
"//src/cdk-experimental:npm_package",
"//src/google-maps:npm_package",
"//src/material:npm_package",
"//src/material-experimental:npm_package",
"//src/youtube-player:npm_package",
"@npm//@angular/compiler-cli",
"@npm//@babel/core",
"@npm//@babel/traverse",
"@npm//chalk",
"@npm//glob",
],
entry_point = "link-packages-test.js",
tags = ["partial-compilation-integration"],
)
100 changes: 100 additions & 0 deletions integration/linker/link-packages-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* Test that collects all partially built NPM packages and links their Angular
* declarations to the corresponding definitions.
*/

const {NodeJSFileSystem} = require('@angular/compiler-cli/src/ngtsc/file_system');
const {ConsoleLogger, LogLevel} = require('@angular/compiler-cli/src/ngtsc/logging');
const {createEs2015LinkerPlugin} = require('@angular/compiler-cli/linker/babel');
const {getNpmPackagesFromRunfiles} = require('../npm-packages-from-runfiles');
const {readFileSync} = require('fs');
const {join} = require('path');
const babel = require('@babel/core');
const {default: traverse} = require('@babel/traverse');
const glob = require('glob');
const chalk = require('chalk');

/** File system used by the Angular linker plugin. */
const fileSystem = new NodeJSFileSystem();
/** Logger used by the Angular linker plugin. */
const logger = new ConsoleLogger(LogLevel.info);
/** List of NPM packages available in the Bazel runfiles. */
const npmPackages = getNpmPackagesFromRunfiles();
/** Whether any package could not be linked successfully. */
let failedPackages = false;

// Iterate through all determined NPM packages and ensure that entry point
// files can be processed successfully by the Angular linker.
for (const pkg of npmPackages) {
const {failures, passedFiles} = testPackage(pkg);

console.info(chalk.cyan(`------- Package: @angular/${pkg.name} -------`));
console.info(`Passed files: ${passedFiles.length}`);
console.info(`Failed files: ${failures.length}`);

if (failures.length > 0) {
failures.forEach(({debugFileName, error}) => {
console.error(` • ${chalk.yellow(debugFileName)}: ${error}`);
});
failedPackages = true;
}

console.info('-------------------------------------');
console.info();
}

if (failedPackages) {
console.error(chalk.red(`✘ Not all packages could be linked successfully. See errors above.`));
// If there are failures, exit the process with a non-zero exit code. Bazel
// uses exit code `3` to indicate non-fatal test failures.
process.exitCode = 3;
} else {
console.info(chalk.green('✓ All packages have been successfully linked.'));
}

/**
* Tests the specified package against the Angular linker plugin.
* @param pkg Package being tested.
* @returns An object containing linker failures and passed files.
*/
function testPackage(pkg) {
const entryPointFesmFiles = glob.sync(`fesm2015/**/*.js`, {cwd: pkg.pkgPath});
const passedFiles = [];
const failures = [];

// Iterate through each entry point and confirm that all partial declarations can be linked
// to their corresponding Angular definitions without errors.
for (const fesmFileName of entryPointFesmFiles) {
const diskFilePath = join(pkg.pkgPath, fesmFileName);
const debugFileName = join(pkg.name, fesmFileName);
const fileContent = readFileSync(diskFilePath, 'utf8');
const linkerPlugin = createEs2015LinkerPlugin({fileSystem, logger});

// Babel throws errors if the transformation fails. We catch these so that we
// can print incompatible entry points with their errors at the end.
try {
const {ast} = babel.transformSync(fileContent, {
ast: true,
filename: diskFilePath,
filenameRelative: debugFileName,
plugins: [linkerPlugin]
});

// Naively check if there are any Angular declarations left that haven't been linked.
traverse(ast, {
Identifier: (astPath) => {
if (astPath.node.name.startsWith('ɵɵngDeclare')) {
throw astPath.buildCodeFrameError(
'Found Angular declaration that has not been linked.', Error);
}
}
});

passedFiles.push(debugFileName);
} catch (error) {
failures.push({debugFileName, error});
}
}

return {passedFiles, failures}
}
36 changes: 36 additions & 0 deletions integration/npm-packages-from-runfiles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Collection of common logic for dealing with Bazel runfiles within
* integration tests.
*/

const {relative, sep, join} = require('path');
const {readdirSync, readFileSync, existsSync} = require('fs');

/**
* Gets all built Angular NPM package artifacts by querying the Bazel runfiles.
* In case there is a runfiles manifest (e.g. on Windows), the packages are resolved
* through the manifest because the runfiles are not symlinked and cannot be searched
* within the real filesystem.
* TODO: Simplify if Bazel on Windows uses runfile symlinking.
*/
exports.getNpmPackagesFromRunfiles = function() {
// Path to the Bazel runfiles manifest if present. This file is present if runfiles are
// not symlinked into the runfiles directory.
const runfilesManifestPath = process.env.RUNFILES_MANIFEST_FILE;
const workspacePath = 'angular_material/src';
if (!runfilesManifestPath) {
const packageRunfilesDir = join(process.env.RUNFILES, workspacePath);
return readdirSync(packageRunfilesDir)
.map(name => ({name, pkgPath: join(packageRunfilesDir, name, 'npm_package/')}))
.filter(({pkgPath}) => existsSync(pkgPath));
}
const workspaceManifestPathRegex = new RegExp(`^${workspacePath}/[\\w-]+/npm_package$`);
return readFileSync(runfilesManifestPath, 'utf8')
.split('\n')
.map(mapping => mapping.split(' '))
.filter(([runfilePath]) => runfilePath.match(workspaceManifestPathRegex))
.map(([runfilePath, realPath]) => ({
name: relative(workspacePath, runfilePath).split(sep)[0],
pkgPath: realPath,
}));
}
1 change: 1 addition & 0 deletions integration/ts-compat/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ typescript_version_packages = [
"helpers.js",
"test.js",
":import-all-entry-points-file",
"//integration:npm-packages-from-runfiles",
"//src/cdk:npm_package",
"//src/cdk-experimental:npm_package",
"//src/google-maps:npm_package",
Expand Down
32 changes: 3 additions & 29 deletions integration/ts-compat/helpers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const {relative, sep, join} = require('path');
const {readdirSync, readFileSync, existsSync, unlinkSync} = require('fs');
const {join} = require('path');
const {unlinkSync} = require('fs');
const {set, ln, rm, mkdir} = require('shelljs');
const {fork} = require('child_process');
const {getNpmPackagesFromRunfiles} = require('../npm-packages-from-runfiles');
const {runfiles} = require('@bazel/runfiles');

// Exit if any command fails.
Expand Down Expand Up @@ -57,30 +58,3 @@ exports.runTypeScriptCompatibilityTest = async (tscBinPath) => {
});
};

/**
* Gets all built Angular NPM package artifacts by querying the Bazel runfiles.
* In case there is a runfiles manifest (e.g. on Windows), the packages are resolved
* through the manifest because the runfiles are not symlinked and cannot be searched
* within the real filesystem. TODO: Remove if Bazel on Windows uses runfile symlinking.
*/
function getNpmPackagesFromRunfiles() {
// Path to the Bazel runfiles manifest if present. This file is present if runfiles are
// not symlinked into the runfiles directory.
const runfilesManifestPath = process.env.RUNFILES_MANIFEST_FILE;
const workspacePath = 'angular_material/src';
if (!runfilesManifestPath) {
const packageRunfilesDir = join(process.env.RUNFILES, workspacePath);
return readdirSync(packageRunfilesDir)
.map(name => ({name, pkgPath: join(packageRunfilesDir, name, 'npm_package/')}))
.filter(({pkgPath}) => existsSync(pkgPath));
}
const workspaceManifestPathRegex = new RegExp(`^${workspacePath}/[\\w-]+/npm_package$`);
return readFileSync(runfilesManifestPath, 'utf8')
.split('\n')
.map(mapping => mapping.split(' '))
.filter(([runfilePath]) => runfilePath.match(workspaceManifestPathRegex))
.map(([runfilePath, realPath]) => ({
name: relative(workspacePath, runfilePath).split(sep)[0],
pkgPath: realPath,
}));
}
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@
"merge": "ng-dev pr merge",
"approve-api": "node ./scripts/approve-api-golden.js",
"approve-size-tests": "node ./scripts/approve-size-golden.js",
"integration-tests": "bazel test --test_tag_filters=-view-engine-only --build_tests_only -- //integration/... -//integration/size-test/...",
"integration-tests": "bazel test --test_tag_filters=-view-engine-only,-linker-integration-test --build_tests_only -- //integration/... -//integration/size-test/...",
"integration-tests:view-engine": "bazel test --test_tag_filters=view-engine-only --build_tests_only -- //integration/... -//integration/size-test/...",
"integration-tests:partial-ivy": "bazel test --//tools:partial_compilation=True --test_tag_filters=partial-compilation-integration --build_tests_only -- //integration/... //src/...",
"integration-tests:size-test": "bazel test //integration/size-test/...",
"check-mdc-tests": "ts-node --project scripts/tsconfig.json scripts/check-mdc-tests.ts",
"check-mdc-exports": "ts-node --project scripts/tsconfig.json scripts/check-mdc-exports.ts",
Expand Down Expand Up @@ -80,6 +81,8 @@
"@angular/platform-server": "^12.0.0",
"@angular/router": "^12.0.0",
"@axe-core/webdriverjs": "^4.1.0",
"@babel/core": "^7.13.10",
"@babel/traverse": "^7.13.0",
"@bazel/bazelisk": "1.7.5",
"@bazel/buildifier": "4.0.1",
"@bazel/concatjs": "3.2.1",
Expand Down Expand Up @@ -139,6 +142,8 @@
"@material/touch-target": "^12.0.0-canary.a23ecb682.0",
"@material/typography": "^12.0.0-canary.a23ecb682.0",
"@octokit/rest": "18.3.5",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^18.0.0",
"@schematics/angular": "^12.0.0",
"@types/autoprefixer": "^9.7.2",
"@types/browser-sync": "^2.26.1",
Expand Down
Loading