From 3b213b514195a19d568bdb7f6c4d0a32d3406cb2 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Fri, 28 Dec 2018 09:34:18 +0100 Subject: [PATCH 1/3] feat(@angular-devkit/build-angular): add support for port 0 when using protractor Fixes #13129 --- .../build_angular/src/protractor/index.ts | 22 ++++++++++++------- .../test/protractor/works_spec_large.ts | 6 +++++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/protractor/index.ts b/packages/angular_devkit/build_angular/src/protractor/index.ts index d00e92608e1b..a6effc5032f8 100644 --- a/packages/angular_devkit/build_angular/src/protractor/index.ts +++ b/packages/angular_devkit/build_angular/src/protractor/index.ts @@ -13,9 +13,10 @@ import { BuilderContext, BuilderDescription, } from '@angular-devkit/architect'; +import { DevServerResult } from '@angular-devkit/build-webpack'; import { Path, getSystemPath, normalize, resolve, tags } from '@angular-devkit/core'; import { Observable, from, of } from 'rxjs'; -import { concatMap, take, tap } from 'rxjs/operators'; +import { concatMap, map, take, tap } from 'rxjs/operators'; import * as url from 'url'; import { requireProjectModule } from '../angular-cli-files/utilities/require-project-module'; import { DevServerBuilderOptions } from '../dev-server'; @@ -70,9 +71,15 @@ export class ProtractorBuilder implements Builder { return architect.getBuilderDescription(builderConfig).pipe( tap(description => devServerDescription = description), - concatMap(devServerDescription => architect.validateBuilderOptions( - builderConfig, devServerDescription)), - concatMap(() => { + concatMap(devServerDescription => + architect.validateBuilderOptions(builderConfig, devServerDescription)), + map(() => this.context.architect.getBuilder(devServerDescription, this.context)), + concatMap(builder => builder.run(builderConfig)), + tap(buildEvent => { + if (!buildEvent.success) { + return; + } + // Compute baseUrl from devServerOptions. if (options.devServerTarget && builderConfig.options.publicHost) { let publicHost = builderConfig.options.publicHost; @@ -84,19 +91,18 @@ export class ProtractorBuilder implements Builder { const clientUrl = url.parse(publicHost); baseUrl = url.format(clientUrl); } else if (options.devServerTarget) { + const result: DevServerResult | undefined = buildEvent.result; + baseUrl = url.format({ protocol: builderConfig.options.ssl ? 'https' : 'http', hostname: options.host, - port: builderConfig.options.port.toString(), + port: result && result.port.toString(), }); } // Save the computed baseUrl back so that Protractor can use it. options.baseUrl = baseUrl; - - return of(this.context.architect.getBuilder(devServerDescription, this.context)); }), - concatMap(builder => builder.run(builderConfig)), ); } diff --git a/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts b/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts index 0970512d951b..ecbb8f62ee36 100644 --- a/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts @@ -60,6 +60,12 @@ describe('Protractor Builder', () => { ).toPromise().then(done, done.fail); }, 60000); + it('works with port 0', (done) => { + runTargetSpec(host, protractorTargetSpec, { port: 0 }).pipe( + retry(3), + ).toPromise().then(done, done.fail); + }, 30000); + // TODO: test `element-explorer` when the protractor builder emits build events with text. // .then(() => execAndWaitForOutputToMatch('ng', ['e2e', '--element-explorer'], // /Element Explorer/)) From 2d555b4df057d130a1dc23e3777fc253f502693a Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Fri, 28 Dec 2018 09:37:03 +0100 Subject: [PATCH 2/3] feat(@angular-devkit/architect): add `result` property to `BuildEvent` --- etc/api/angular_devkit/architect/src/index.d.ts | 3 ++- packages/angular_devkit/architect/src/architect.ts | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/etc/api/angular_devkit/architect/src/index.d.ts b/etc/api/angular_devkit/architect/src/index.d.ts index 6abeeeb4c133..80731d409f38 100644 --- a/etc/api/angular_devkit/architect/src/index.d.ts +++ b/etc/api/angular_devkit/architect/src/index.d.ts @@ -63,7 +63,8 @@ export interface BuilderPathsMap { }; } -export interface BuildEvent { +export interface BuildEvent { + result?: BuildResultT; success: boolean; } diff --git a/packages/angular_devkit/architect/src/architect.ts b/packages/angular_devkit/architect/src/architect.ts index c83994aa33c6..2464f6551d94 100644 --- a/packages/angular_devkit/architect/src/architect.ts +++ b/packages/angular_devkit/architect/src/architect.ts @@ -70,8 +70,11 @@ export interface BuilderContext { // TODO: use Build Event Protocol // https://docs.bazel.build/versions/master/build-event-protocol.html // https://github.com/googleapis/googleapis/tree/master/google/devtools/build/v1 -export interface BuildEvent { +// TODO: use unknown +// tslint:disable-next-line:no-any +export interface BuildEvent { success: boolean; + result?: BuildResultT; } export interface Builder { From 30f6f08fc72c2f24944ef7bf6e6c9dadce4c89cc Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Fri, 28 Dec 2018 10:14:45 +0100 Subject: [PATCH 3/3] feat(@angular-devkit/build-webpack): expose `DevServerResult` in `BuildEvent` --- .../src/webpack-dev-server/index.ts | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts index 16a71eb93915..d99bfeddf460 100644 --- a/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts @@ -12,7 +12,8 @@ import { BuilderConfiguration, BuilderContext, } from '@angular-devkit/architect'; -import { Path, getSystemPath, normalize, resolve } from '@angular-devkit/core'; +import { getSystemPath, normalize, resolve } from '@angular-devkit/core'; +import * as net from 'net'; import { Observable, from } from 'rxjs'; import { concatMap } from 'rxjs/operators'; import * as webpack from 'webpack'; @@ -20,12 +21,18 @@ import * as WebpackDevServer from 'webpack-dev-server'; import { LoggingCallback, defaultLoggingCb } from '../webpack'; import { WebpackDevServerBuilderSchema } from './schema'; +export interface DevServerResult { + port: number; + family: string; + address: string; +} export class WebpackDevServerBuilder implements Builder { constructor(public context: BuilderContext) { } - run(builderConfig: BuilderConfiguration): Observable { + run(builderConfig: BuilderConfiguration) + : Observable> { const configPath = resolve(this.context.workspace.root, normalize(builderConfig.options.webpackConfig)); @@ -42,11 +49,13 @@ export class WebpackDevServerBuilder implements Builder { + ): Observable> { return new Observable(obs => { const devServerConfig = devServerCfg || webpackConfig.devServer || {}; devServerConfig.host = devServerConfig.host || 'localhost'; - devServerConfig.port = devServerConfig.port || 8080; + if (devServerConfig.port == undefined) { + devServerConfig.port = 8080; + } if (devServerConfig.stats) { webpackConfig.stats = devServerConfig.stats as webpack.Stats.ToStringOptionsObject; @@ -56,20 +65,26 @@ export class WebpackDevServerBuilder implements Builder { // Log stats. loggingCb(stats, webpackConfig, this.context.logger); - obs.next({ success: !stats.hasErrors() }); + obs.next({ success: !stats.hasErrors(), result }); }); server.listen( devServerConfig.port, devServerConfig.host, - (err) => { + function (err) { if (err) { obs.error(err); + } else { + // this is ignored because of ts errors + // that this is overshadowed by it's outer contain + // @ts-ignore; + result = (this as net.Server).address(); } }, );