diff --git a/integration/bazel-schematics/yarn.lock b/integration/bazel-schematics/yarn.lock
index b2b87bca5c..b6b57e7865 100644
--- a/integration/bazel-schematics/yarn.lock
+++ b/integration/bazel-schematics/yarn.lock
@@ -10,25 +10,14 @@
"@angular-devkit/core" "7.3.2"
rxjs "6.3.3"
-"@angular-devkit/architect@^0.10.6":
- version "0.10.7"
- resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.10.7.tgz#c74b9f6b7f1b4261ada2d24c832328aa4c394464"
- integrity sha512-S49LSslNRxIflHzrIrEgK7mGQ7HzETr/FU0fyTbB0vubcmfzMoYTsgYdK7SUz583lovc+UvASoUAhPJI3e35ng==
+"@angular-devkit/architect@^0.13.4":
+ version "0.13.4"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.13.4.tgz#f5db62f028e3c0971db5719be9c17a78fd8a67a2"
+ integrity sha512-wJF8oz8MurtpFi0ik42bkI2F5gEnuOe79KHPO1i3SYfdhEp5NY8igVKZ6chB/eq4Ml50aHxas8Hh9ke12K+Pxw==
dependencies:
- "@angular-devkit/core" "7.0.7"
+ "@angular-devkit/core" "7.3.4"
rxjs "6.3.3"
-"@angular-devkit/core@7.0.7":
- version "7.0.7"
- resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.0.7.tgz#665176ad8421adfd5f3ea0b2c4a9a432a158b1bb"
- integrity sha512-M8tTT9r3nUtWI3YyiyynHIQn+lQQgeKkxVZ+rdxvyvgE3U9+wn0yep5HkFLQETTuJetu9ARRRD94sD2XL3F/3A==
- dependencies:
- ajv "6.5.3"
- chokidar "2.0.4"
- fast-json-stable-stringify "2.0.0"
- rxjs "6.3.3"
- source-map "0.7.3"
-
"@angular-devkit/core@7.3.2", "@angular-devkit/core@^7.0.4":
version "7.3.2"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.2.tgz#67ac2cfcbe47f1e457929c19ab1b04c9e061b2e2"
@@ -40,6 +29,17 @@
rxjs "6.3.3"
source-map "0.7.3"
+"@angular-devkit/core@7.3.4":
+ version "7.3.4"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.4.tgz#fae0521652c7430237025f117531ca3262ef8335"
+ integrity sha512-MBfen51iOBKfK4tlg5KwmPxePsF1QoFNUMGLuvUUwPkteonrGcupX1Q7NWTpf+HA+i08mOnZGuepeuQkD12IQw==
+ dependencies:
+ ajv "6.9.1"
+ chokidar "2.0.4"
+ fast-json-stable-stringify "2.0.0"
+ rxjs "6.3.3"
+ source-map "0.7.3"
+
"@angular-devkit/schematics@7.3.2", "@angular-devkit/schematics@^7.3.0-rc.0":
version "7.3.2"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.3.2.tgz#e9d3c1f2128a56f66ea846ce3f80c69d4c3a9ae9"
@@ -51,11 +51,11 @@
"@angular/bazel@file:../../dist/packages-dist/bazel":
version "8.0.0-beta.6"
dependencies:
- "@angular-devkit/architect" "^0.10.6"
+ "@angular-devkit/architect" "^0.13.4"
"@angular-devkit/core" "^7.0.4"
"@angular-devkit/schematics" "^7.3.0-rc.0"
"@bazel/typescript" "^0.26.0"
- "@microsoft/api-extractor" "^7.0.17"
+ "@microsoft/api-extractor" "^7.0.21"
"@schematics/angular" "^7.0.4"
"@types/node" "6.0.84"
semver "^5.6.0"
@@ -112,26 +112,27 @@
source-map-support "0.5.9"
tsutils "2.27.2"
-"@microsoft/api-extractor@^7.0.17":
- version "7.0.18"
- resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.0.18.tgz#4eb931436495177dfcef8f2d8da3d084d10eebb6"
- integrity sha512-puQisjyoYK1A0I8DqyBoLPV9noyFUlxTE3WsjhgJw//TrmegGHYmsRlD3rnHeXcKPM1F7sd/VKJXeXC3IPTf2Q==
+"@microsoft/api-extractor@^7.0.21":
+ version "7.0.22"
+ resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.0.22.tgz#9c6eb0500168811ed14194de413ddd310622533a"
+ integrity sha512-1mNMbmUeqtjNmS9hgrONio2uRZL2eeZk39zCKq04ReImFXnMR+fnMTQG98B+SAkFFGJuOucwke5U0bgWnrG6kw==
dependencies:
- "@microsoft/node-core-library" "3.10.0"
+ "@microsoft/node-core-library" "3.12.0"
"@microsoft/ts-command-line" "4.2.3"
- "@microsoft/tsdoc" "0.12.5"
+ "@microsoft/tsdoc" "0.12.7"
"@types/node" "8.5.8"
"@types/z-schema" "3.16.31"
colors "~1.2.1"
lodash "~4.17.5"
resolve "1.8.1"
+ source-map "~0.6.1"
typescript "~3.1.6"
z-schema "~3.18.3"
-"@microsoft/node-core-library@3.10.0":
- version "3.10.0"
- resolved "https://registry.yarnpkg.com/@microsoft/node-core-library/-/node-core-library-3.10.0.tgz#70e089534d8e20f6a0f9c7a4a12a6aeafd6a1ddb"
- integrity sha512-1SbU+XNYAabhV9noGXHtsUVPc5ELV+oEuJQtZQoCncbOd6WAMeTgB1xFwh96hmdEXyKQyML/pnByiKocmh/nbQ==
+"@microsoft/node-core-library@3.12.0":
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/@microsoft/node-core-library/-/node-core-library-3.12.0.tgz#f9c27b8bb6b55d60b91d4e1962f42b03b9f8f47f"
+ integrity sha512-9T2dEXmmxZqnqcpHuIB8mTAOM/DNSi/QcAwKYDjvZvkd+PGT5lCUXjM9GL7SaR2NPa3UrWDGgFhNoqLqLfEPbw==
dependencies:
"@types/fs-extra" "5.0.4"
"@types/jju" "~1.4.0"
@@ -152,10 +153,10 @@
argparse "~1.0.9"
colors "~1.2.1"
-"@microsoft/tsdoc@0.12.5":
- version "0.12.5"
- resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.5.tgz#c448a38902ccb5601c1b2ef3b1a105012ef7712c"
- integrity sha512-xEAyvLXo4Cter/b0EMCWUZTgXOfLOPJ/Xr52WdjVclPx9eDmNTGFtZl8Pn/nqSnZsQBNcHL0eHk/YyRyyXXpiQ==
+"@microsoft/tsdoc@0.12.7":
+ version "0.12.7"
+ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.7.tgz#8fb4a9f4fdf01f1469c9fc54b0ad2d36ec57c25d"
+ integrity sha512-0bqNlQT8aR4Iq9xx/OsY579Zeqon9uTZDIuvl+XXu16TPPN2sASeKojwm366jA2MjgXd9iyTWpJM5/P1QJ4Dxg==
"@schematics/angular@7.3.2", "@schematics/angular@^7.0.4":
version "7.3.2"
@@ -249,16 +250,6 @@ agentkeepalive@^3.4.1:
dependencies:
humanize-ms "^1.2.1"
-ajv@6.5.3:
- version "6.5.3"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
- integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==
- dependencies:
- fast-deep-equal "^2.0.1"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.4.1"
- uri-js "^4.2.2"
-
ajv@6.9.1:
version "6.9.1"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1"
@@ -2154,7 +2145,7 @@ source-map@^0.5.6:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-source-map@^0.6.0:
+source-map@^0.6.0, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
diff --git a/packages/bazel/package.json b/packages/bazel/package.json
index c5d758923c..67c794cb93 100644
--- a/packages/bazel/package.json
+++ b/packages/bazel/package.json
@@ -18,7 +18,7 @@
}
},
"dependencies": {
- "@angular-devkit/architect": "^0.10.6",
+ "@angular-devkit/architect": "^0.13.4",
"@angular-devkit/core": "^7.0.4",
"@angular-devkit/schematics": "^7.3.0-rc.0",
"@bazel/typescript": "^0.26.0",
@@ -42,4 +42,4 @@
"ng-update": {
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
}
-}
\ No newline at end of file
+}
diff --git a/packages/bazel/src/builders/BUILD.bazel b/packages/bazel/src/builders/BUILD.bazel
index 23e4a0add8..142c80f60a 100644
--- a/packages/bazel/src/builders/BUILD.bazel
+++ b/packages/bazel/src/builders/BUILD.bazel
@@ -1,4 +1,4 @@
-load("//tools:defaults.bzl", "ts_library")
+load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")
package(default_visibility = ["//visibility:public"])
@@ -19,7 +19,7 @@ ts_library(
],
data = [
"schema.json",
- ],
+ ] + glob(["files/**/*"]),
module_name = "@angular/bazel/src/builders",
deps = [
"@npm//@angular-devkit/architect",
@@ -28,3 +28,24 @@ ts_library(
"@npm//rxjs",
],
)
+
+ts_library(
+ name = "test_lib",
+ testonly = True,
+ srcs = [
+ "bazel_spec.ts",
+ ],
+ deps = [
+ "builders",
+ "@npm//@angular-devkit/core",
+ ],
+)
+
+jasmine_node_test(
+ name = "test",
+ bootstrap = ["angular/tools/testing/init_node_spec.js"],
+ deps = [
+ ":test_lib",
+ "//tools/testing:node",
+ ],
+)
diff --git a/packages/bazel/src/builders/bazel.ts b/packages/bazel/src/builders/bazel.ts
index d1fe2cdbfb..90f07a586c 100644
--- a/packages/bazel/src/builders/bazel.ts
+++ b/packages/bazel/src/builders/bazel.ts
@@ -7,44 +7,145 @@
*/
///
-import {spawn, spawnSync} from 'child_process';
-import {Observable, Subject} from 'rxjs';
+
+import {Path, basename, dirname, getSystemPath, join} from '@angular-devkit/core';
+import {resolve} from '@angular-devkit/core/node';
+import {Host} from '@angular-devkit/core/src/virtual-fs/host';
+import {spawn} from 'child_process';
export type Executable = 'bazel' | 'ibazel';
export type Command = 'build' | 'test' | 'run' | 'coverage' | 'query';
+/**
+ * Spawn the Bazel process. Trap SINGINT to make sure Bazel process is killed.
+ */
export function runBazel(
- projectDir: string, executable: Executable, command: Command, workspaceTarget: string,
- flags: string[]): Observable {
- const doneSubject = new Subject();
- const bin = require.resolve(`@bazel/${executable}`);
- const buildProcess = spawn(bin, [command, workspaceTarget, ...flags], {
- cwd: projectDir,
- stdio: 'inherit',
- shell: false,
- });
+ projectDir: Path, binary: Path, command: Command, workspaceTarget: string, flags: string[]) {
+ return new Promise((resolve, reject) => {
+ const buildProcess = spawn(getSystemPath(binary), [command, workspaceTarget, ...flags], {
+ cwd: getSystemPath(projectDir),
+ stdio: 'inherit',
+ shell: false,
+ });
- buildProcess.once('close', (code: number) => {
- if (code === 0) {
- doneSubject.next();
- } else {
- doneSubject.error(`${executable} failed with code ${code}.`);
- }
- });
+ process.on('SIGINT', (signal) => {
+ if (!buildProcess.killed) {
+ buildProcess.kill();
+ reject(new Error(`Bazel process received ${signal}.`));
+ }
+ });
- return doneSubject.asObservable();
+ buildProcess.once('close', (code: number) => {
+ if (code === 0) {
+ resolve();
+ } else {
+ reject(new Error(`${basename(binary)} failed with code ${code}.`));
+ }
+ });
+ });
}
-export function checkInstallation(executable: Executable, projectDir: string) {
- let bin: string;
+/**
+ * Resolves the path to `@bazel/bazel` or `@bazel/ibazel`.
+ */
+export function checkInstallation(name: Executable, projectDir: Path): string {
+ const packageName = `@bazel/${name}`;
try {
- bin = require.resolve(`@bazel/${executable}`);
- } catch {
- return false;
+ return resolve(packageName, {
+ basedir: projectDir,
+ });
+ } catch (error) {
+ if (error.code === 'MODULE_NOT_FOUND') {
+ throw new Error(
+ `Could not run ${name}. Please make sure that the ` +
+ `"${name}" command is installed by running ` +
+ `"npm install ${packageName}" or "yarn install ${packageName}".`);
+ }
+ throw error;
}
- const child = spawnSync(bin, ['version'], {
- cwd: projectDir,
- shell: false,
- });
- return child.status === 0;
+}
+
+/**
+ * Returns the absolute path to the template directory in `@angular/bazel`.
+ */
+export async function getTemplateDir(host: Host, root: Path): Promise {
+ const packageJson = resolve('@angular/bazel', {
+ basedir: root,
+ resolvePackageJson: true,
+ });
+ const packageDir = dirname(packageJson as Path);
+ const templateDir = join(packageDir, 'src', 'builders', 'files');
+ if (!await host.isDirectory(templateDir).toPromise()) {
+ throw new Error('Could not find Bazel template directory in "@angular/bazel".');
+ }
+ return templateDir;
+}
+
+/**
+ * Recursively list the specified 'dir' using depth-first approach. Paths
+ * returned are relative to 'dir'.
+ */
+function listR(host: Host, dir: Path): Promise {
+ async function list(dir: Path, root: Path, results: Path[]) {
+ const paths = await host.list(dir).toPromise();
+ for (const path of paths) {
+ const absPath = join(dir, path);
+ const relPath = join(root, path);
+ if (await host.isFile(absPath).toPromise()) {
+ results.push(relPath);
+ } else {
+ await list(absPath, relPath, results);
+ }
+ }
+ return results;
+ }
+
+ return list(dir, '' as Path, []);
+}
+
+/**
+ * Copy the file from 'source' to 'dest'.
+ */
+async function copyFile(host: Host, source: Path, dest: Path) {
+ const buffer = await host.read(source).toPromise();
+ await host.write(dest, buffer).toPromise();
+}
+
+/**
+ * Copy Bazel files (WORKSPACE, BUILD.bazel, etc) from the template directory to
+ * the project `root` directory, and return the absolute paths of the files
+ * copied, so that they can be deleted later.
+ * Existing files in `root` will not be replaced.
+ */
+export async function copyBazelFiles(host: Host, root: Path, templateDir: Path) {
+ const bazelFiles: Path[] = [];
+ const templates = await listR(host, templateDir);
+
+ await Promise.all(templates.map(async(template) => {
+ const name = template.replace('__dot__', '.').replace('.template', '');
+ const source = join(templateDir, template);
+ const dest = join(root, name);
+ try {
+ const exists = await host.exists(dest).toPromise();
+ if (!exists) {
+ await copyFile(host, source, dest);
+ bazelFiles.push(dest);
+ }
+ } catch {
+ }
+ }));
+
+ return bazelFiles;
+}
+
+/**
+ * Delete the specified 'files' and return a promise that always resolves.
+ */
+export function deleteBazelFiles(host: Host, files: Path[]) {
+ return Promise.all(files.map(async(file) => {
+ try {
+ await host.delete(file).toPromise();
+ } catch {
+ }
+ }));
}
diff --git a/packages/bazel/src/builders/bazel_spec.ts b/packages/bazel/src/builders/bazel_spec.ts
new file mode 100644
index 0000000000..84bf86ddab
--- /dev/null
+++ b/packages/bazel/src/builders/bazel_spec.ts
@@ -0,0 +1,42 @@
+/**
+ * @license
+ * Copyright Google Inc. All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {Path} from '@angular-devkit/core';
+import {test} from '@angular-devkit/core/src/virtual-fs/host/test';
+
+import {copyBazelFiles, deleteBazelFiles} from './bazel';
+
+describe('Bazel builder', () => {
+ it('should copy Bazel files', async() => {
+ const host = new test.TestHost({
+ '/files/WORKSPACE.template': '',
+ '/files/BUILD.bazel.template': '',
+ '/files/__dot__bazelrc.template': '',
+ '/files/__dot__bazelignore.template': '',
+ '/files/e2e/BUILD.bazel.template': '',
+ '/files/src/BUILD.bazel.template': '',
+ });
+ const root = '/' as Path;
+ const templateDir = '/files' as Path;
+ await copyBazelFiles(host, root, templateDir);
+ const {records} = host;
+ expect(records).toContain({kind: 'write', path: '/WORKSPACE' as Path});
+ expect(records).toContain({kind: 'write', path: '/BUILD.bazel' as Path});
+ });
+
+ it('should delete Bazel files', async() => {
+ const host = new test.TestHost({
+ '/WORKSPACE': '',
+ '/BUILD.bazel': '',
+ });
+ await deleteBazelFiles(host, ['/WORKSPACE', '/BUILD.bazel'] as Path[]);
+ const {records} = host;
+ expect(records).toContain({kind: 'delete', path: '/WORKSPACE' as Path});
+ expect(records).toContain({kind: 'delete', path: '/BUILD.bazel' as Path});
+ });
+});
diff --git a/packages/bazel/src/builders/files/BUILD.bazel.template b/packages/bazel/src/builders/files/BUILD.bazel.template
new file mode 100644
index 0000000000..27b2fa1432
--- /dev/null
+++ b/packages/bazel/src/builders/files/BUILD.bazel.template
@@ -0,0 +1,7 @@
+package(default_visibility = ["//visibility:public"])
+
+# This export allows targets in other packages to reference files that live
+# in this package.
+exports_files([
+ "tsconfig.json",
+])
diff --git a/packages/bazel/src/builders/files/WORKSPACE.template b/packages/bazel/src/builders/files/WORKSPACE.template
new file mode 100644
index 0000000000..3d1fc71a93
--- /dev/null
+++ b/packages/bazel/src/builders/files/WORKSPACE.template
@@ -0,0 +1,60 @@
+# WARNING: This file is generated and it's not meant to be edited.
+# Before making any changes, please read Bazel documentation.
+# https://docs.bazel.build/versions/master/be/workspace.html
+# The WORKSPACE file tells Bazel that this directory is a "workspace", which is like a project root.
+# The content of this file specifies all the external dependencies Bazel needs to perform a build.
+
+####################################
+# ESModule imports (and TypeScript imports) can be absolute starting with the workspace name.
+# The name of the workspace should match the npm package where we publish, so that these
+# imports also make sense when referencing the published package.
+workspace(name = "project")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+RULES_NODEJS_VERSION = "0.26.0"
+http_archive(
+ name = "build_bazel_rules_nodejs",
+ sha256 = "5c86b055c57e15bf32d9009a15bcd6d8e190c41b1ff2fb18037b75e0012e4e7c",
+ url = "https://github.com/bazelbuild/rules_nodejs/releases/download/%s/rules_nodejs-%s.tar.gz" % (RULES_NODEJS_VERSION, RULES_NODEJS_VERSION),
+)
+
+# Rules for compiling sass
+RULES_SASS_VERSION = "1.17.2"
+http_archive(
+ name = "io_bazel_rules_sass",
+ sha256 = "e5316ee8a09d1cbb732d3938b400836bf94dba91a27476e9e27706c4c0edae1f",
+ url = "https://github.com/bazelbuild/rules_sass/archive/%s.zip" % RULES_SASS_VERSION,
+ strip_prefix = "rules_sass-%s" % RULES_SASS_VERSION,
+)
+
+####################################
+# Load and install our dependencies downloaded above.
+
+load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install")
+check_bazel_version("0.22.0")
+node_repositories()
+yarn_install(
+ name = "npm",
+ data = ["//:angular-metadata.tsconfig.json"],
+ package_json = "//:package.json",
+ yarn_lock = "//:yarn.lock",
+)
+
+load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
+install_bazel_dependencies()
+
+load("@npm_bazel_karma//:package.bzl", "rules_karma_dependencies")
+rules_karma_dependencies()
+
+load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories")
+web_test_repositories()
+
+load("@npm_bazel_karma//:browser_repositories.bzl", "browser_repositories")
+browser_repositories()
+
+load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
+ts_setup_workspace()
+
+load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
+sass_repositories()
diff --git a/packages/bazel/src/builders/files/__dot__bazelignore.template b/packages/bazel/src/builders/files/__dot__bazelignore.template
new file mode 100644
index 0000000000..de4d1f007d
--- /dev/null
+++ b/packages/bazel/src/builders/files/__dot__bazelignore.template
@@ -0,0 +1,2 @@
+dist
+node_modules
diff --git a/packages/bazel/src/builders/files/__dot__bazelrc.template b/packages/bazel/src/builders/files/__dot__bazelrc.template
new file mode 100644
index 0000000000..1b544399da
--- /dev/null
+++ b/packages/bazel/src/builders/files/__dot__bazelrc.template
@@ -0,0 +1,29 @@
+# Make TypeScript and Angular compilation fast, by keeping a few copies of the
+# compiler running as daemons, and cache SourceFile AST's to reduce parse time.
+build --strategy=TypeScriptCompile=worker
+build --strategy=AngularTemplateCompile=worker
+
+# Don't create bazel-* symlinks in the WORKSPACE directory, except `bazel-out`,
+# which is mandatory.
+# These require .gitignore and may scare users.
+# Also, it's a workaround for https://github.com/bazelbuild/rules_typescript/issues/12
+# which affects the common case of having `tsconfig.json` in the WORKSPACE directory.
+#
+# Instead, the output will appear in `dist/bin`. You'll need to ignore the
+# `bazel-out` directory that is created in the workspace root.
+build --symlink_prefix=dist/
+
+# Turn on --incompatible_strict_action_env which was on by default
+# in Bazel 0.21.0 but turned off again in 0.22.0. Follow
+# https://github.com/bazelbuild/bazel/issues/7026 for more details.
+# This flag is needed to so that the bazel cache is not invalidated
+# when running bazel via `yarn bazel`.
+# See https://github.com/angular/angular/issues/27514.
+build --incompatible_strict_action_env
+run --incompatible_strict_action_env
+test --incompatible_strict_action_env
+
+test --test_output=errors
+
+# Use the Angular 6 compiler
+build --define=compile=legacy
diff --git a/packages/bazel/src/builders/files/e2e/BUILD.bazel.template b/packages/bazel/src/builders/files/e2e/BUILD.bazel.template
new file mode 100644
index 0000000000..b38c34575f
--- /dev/null
+++ b/packages/bazel/src/builders/files/e2e/BUILD.bazel.template
@@ -0,0 +1,50 @@
+load("@npm_bazel_typescript//:index.bzl", "ts_library")
+load("@npm_angular_bazel//:index.bzl", "protractor_web_test_suite")
+
+ts_library(
+ name = "e2e_lib",
+ testonly = 1,
+ srcs = glob(["src/**/*.ts"]),
+ tsconfig = ":tsconfig.e2e.json",
+ deps = [
+ "@npm//@types/jasmine",
+ "@npm//@types/jasminewd2",
+ "@npm//@types/node",
+ "@npm//jasmine",
+ "@npm//protractor",
+ "@npm//tslib",
+ ],
+ data = [
+ "//:tsconfig.json",
+ ],
+)
+
+protractor_web_test_suite(
+ name = "prodserver_test",
+ data = [
+ "@npm//@angular/bazel",
+ "@npm//protractor",
+ ],
+ on_prepare = ":protractor.on-prepare.js",
+ server = "//src:prodserver",
+ deps = [":e2e_lib"],
+)
+
+protractor_web_test_suite(
+ name = "devserver_test",
+ data = [
+ "@npm//@angular/bazel",
+ "@npm//protractor",
+ ],
+ on_prepare = ":protractor.on-prepare.js",
+ server = "//src:devserver",
+ deps = [":e2e_lib"],
+)
+
+# Default target in this package is to run the e2e tests on the devserver.
+# This is a faster round-trip but doesn't exercise production optimizations like
+# code-splitting and lazy loading.
+alias(
+ name = "e2e",
+ actual = "devserver_test",
+)
diff --git a/packages/bazel/src/builders/files/src/BUILD.bazel.template b/packages/bazel/src/builders/files/src/BUILD.bazel.template
new file mode 100644
index 0000000000..ab60972ae4
--- /dev/null
+++ b/packages/bazel/src/builders/files/src/BUILD.bazel.template
@@ -0,0 +1,153 @@
+package(default_visibility = ["//visibility:public"])
+
+load("@npm_angular_bazel//:index.bzl", "ng_module")
+load("@npm_bazel_karma//:index.bzl", "ts_web_test_suite")
+load("@build_bazel_rules_nodejs//:defs.bzl", "rollup_bundle", "history_server")
+load("@build_bazel_rules_nodejs//internal/web_package:web_package.bzl", "web_package")
+load("@npm_bazel_typescript//:index.bzl", "ts_devserver", "ts_library")
+load("@io_bazel_rules_sass//:defs.bzl", "multi_sass_binary")
+
+multi_sass_binary(
+ name = "styles",
+ srcs = glob(["**/*.scss"]),
+)
+
+ng_module(
+ name = "src",
+ srcs = glob(
+ include = ["**/*.ts"],
+ exclude = [
+ "**/*.spec.ts",
+ "main.ts",
+ "test.ts",
+ "initialize_testbed.ts",
+ ],
+ ),
+ assets = glob([
+ "**/*.css",
+ "**/*.html",
+ ]) + ([":styles"] if len(glob(["**/*.scss"])) else []),
+ deps = [
+ "@npm//@angular/core",
+ "@npm//@angular/platform-browser",
+ "@npm//@angular/router",
+ "@npm//@types",
+ "@npm//rxjs",
+ ],
+)
+
+rollup_bundle(
+ name = "bundle",
+ entry_point = "src/main.prod",
+ deps = [
+ "//src",
+ "@npm//rxjs",
+ ],
+)
+
+web_package(
+ name = "prodapp",
+ assets = [
+ # do not sort
+ "@npm//node_modules/zone.js:dist/zone.min.js",
+ ":bundle.min.js",
+ ],
+ data = [
+ "favicon.ico",
+ ],
+ index_html = "index.html",
+)
+
+history_server(
+ name = "prodserver",
+ data = [":prodapp"],
+ templated_args = ["src/prodapp"],
+)
+
+filegroup(
+ name = "rxjs_umd_modules",
+ srcs = [
+ # do not sort
+ "@npm//node_modules/rxjs:bundles/rxjs.umd.js",
+ ":rxjs_shims.js",
+ ],
+)
+
+ts_devserver(
+ name = "devserver",
+ port = 4200,
+ entry_module = "project/src/main.dev",
+ serving_path = "/bundle.min.js",
+ scripts = [
+ "@npm//node_modules/@angular/common:bundles/common.umd.js",
+ "@npm//node_modules/@angular/common:bundles/common-http.umd.js",
+ "@npm//node_modules/@angular/core:bundles/core.umd.js",
+ "@npm//node_modules/@angular/platform-browser:bundles/platform-browser.umd.js",
+ "@npm//node_modules/tslib:tslib.js",
+ ":rxjs_umd_modules",
+ ],
+ static_files = [
+ "@npm//node_modules/zone.js:dist/zone.min.js",
+ ],
+ data = [
+ "favicon.ico",
+ ],
+ index_html = "index.html",
+ deps = [":src"],
+)
+
+ts_library(
+ name = "test_lib",
+ testonly = 1,
+ srcs = glob(["**/*.spec.ts"]),
+ deps = [
+ ":src",
+ "@npm//@angular/core",
+ "@npm//@types",
+ ],
+)
+
+ts_library(
+ name = "initialize_testbed",
+ testonly = 1,
+ srcs = [
+ "initialize_testbed.ts",
+ ],
+ deps = [
+ "@npm//@angular/core",
+ "@npm//@angular/platform-browser-dynamic",
+ "@npm//@types",
+ ],
+)
+
+ts_web_test_suite(
+ name = "test",
+ srcs = [
+ "@npm//node_modules/@angular/common:bundles/common.umd.js",
+ "@npm//node_modules/@angular/compiler:bundles/compiler.umd.js",
+ "@npm//node_modules/@angular/compiler:bundles/compiler-testing.umd.js",
+ "@npm//node_modules/@angular/core:bundles/core.umd.js",
+ "@npm//node_modules/@angular/core:bundles/core-testing.umd.js",
+ "@npm//node_modules/@angular/platform-browser:bundles/platform-browser.umd.js",
+ "@npm//node_modules/@angular/platform-browser:bundles/platform-browser-testing.umd.js",
+ "@npm//node_modules/@angular/platform-browser-dynamic:bundles/platform-browser-dynamic.umd.js",
+ "@npm//node_modules/@angular/platform-browser-dynamic:bundles/platform-browser-dynamic-testing.umd.js",
+ "@npm//node_modules/tslib:tslib.js",
+ ],
+ runtime_deps = [
+ ":initialize_testbed",
+ ],
+ # do not sort
+ bootstrap = [
+ "@npm//node_modules/zone.js:dist/zone-testing-bundle.js",
+ "@npm//node_modules/reflect-metadata:Reflect.js",
+ ],
+ browsers = [
+ "@io_bazel_rules_webtesting//browsers:chromium-local",
+ ],
+ deps = [
+ ":rxjs_umd_modules",
+ ":test_lib",
+ "@npm//karma-jasmine",
+ ],
+)
diff --git a/packages/bazel/src/builders/index.ts b/packages/bazel/src/builders/index.ts
index cf268067fc..6df7a4a4ca 100644
--- a/packages/bazel/src/builders/index.ts
+++ b/packages/bazel/src/builders/index.ts
@@ -9,34 +9,35 @@
*/
import {BuildEvent, Builder, BuilderConfiguration, BuilderContext} from '@angular-devkit/architect';
-import {getSystemPath, resolve} from '@angular-devkit/core';
-import {Observable, of } from 'rxjs';
-import {catchError, map} from 'rxjs/operators';
-
-import {checkInstallation, runBazel} from './bazel';
+import {Path} from '@angular-devkit/core';
+import {Observable, from} from 'rxjs';
+import {checkInstallation, copyBazelFiles, deleteBazelFiles, getTemplateDir, runBazel} from './bazel';
import {Schema} from './schema';
class BazelBuilder implements Builder {
constructor(private context: BuilderContext) {}
- run(builderConfig: BuilderConfiguration>): Observable {
- const projectRoot = getSystemPath(resolve(this.context.workspace.root, builderConfig.root));
- const targetLabel = builderConfig.options.targetLabel;
+ run(config: BuilderConfiguration>): Observable {
+ const {host, logger, workspace} = this.context;
+ const root: Path = workspace.root;
+ const {bazelCommand, targetLabel, watch} = config.options as Schema;
+ const executable = watch ? 'ibazel' : 'bazel';
+ const binary = checkInstallation(executable, root) as Path;
- const executable = builderConfig.options.watch ? 'ibazel' : 'bazel';
-
- if (!checkInstallation(executable, projectRoot)) {
- throw new Error(
- `Could not run ${executable}. Please make sure that the ` +
- `"${executable}" command is installed by running ` +
- `"npm install" or "yarn install".`);
- }
-
- // TODO: Support passing flags.
- return runBazel(
- projectRoot, executable, builderConfig.options.bazelCommand !, targetLabel !,
- [] /* flags */)
- .pipe(map(() => ({success: true})), catchError(() => of ({success: false})), );
+ return from(Promise.resolve().then(async() => {
+ const templateDir = await getTemplateDir(host, root);
+ const bazelFiles = await copyBazelFiles(host, root, templateDir);
+ try {
+ const flags: string[] = [];
+ await runBazel(root, binary, bazelCommand, targetLabel, flags);
+ return {success: true};
+ } catch (err) {
+ logger.error(err.message);
+ return {success: false};
+ } finally {
+ await deleteBazelFiles(host, bazelFiles); // this will never throw
+ }
+ }));
}
}