Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Architect qol #13825

Merged
merged 3 commits into from
Mar 6, 2019
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
3 changes: 1 addition & 2 deletions packages/angular_devkit/architect/builders/false.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
* 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 { of } from 'rxjs';
import { createBuilder } from '../src/index2';

export default createBuilder(() => of({
export default createBuilder(() => ({
success: false,
error: 'False builder always errors.',
}));
3 changes: 1 addition & 2 deletions packages/angular_devkit/architect/builders/true.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* 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 { of } from 'rxjs';
import { createBuilder } from '../src/index2';

export default createBuilder(() => of({ success: true }));
export default createBuilder(() => ({ success: true }));
24 changes: 24 additions & 0 deletions packages/angular_devkit/architect/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ export interface BuilderRun {
stop(): Promise<void>;
}

/**
* Additional optional scheduling options.
*/
export interface ScheduleOptions {
/**
* Logger to pass to the builder. Note that messages will stop being forwarded, and if you want
* to log a builder scheduled from your builder you should forward log events yourself.
*/
logger?: logging.Logger;
}

/**
* The context received as a second argument in your builder.
*/
Expand Down Expand Up @@ -148,25 +159,38 @@ export interface BuilderContext {
* Targets are considered the same if the project, the target AND the configuration are the same.
* @param target The target to schedule.
* @param overrides A set of options to override the workspace set of options.
* @param scheduleOptions Additional optional scheduling options.
* @return A promise of a run. It will resolve when all the members of the run are available.
*/
scheduleTarget(
target: Target,
overrides?: json.JsonObject,
scheduleOptions?: ScheduleOptions,
): Promise<BuilderRun>;

/**
* Schedule a builder by its name. This can be the same builder that is being executed.
* @param builderName The name of the builder, ie. its `packageName:builderName` tuple.
* @param options All options to use for the builder (by default empty object). There is no
* additional options added, e.g. from the workspace.
* @param scheduleOptions Additional optional scheduling options.
* @return A promise of a run. It will resolve when all the members of the run are available.
*/
scheduleBuilder(
builderName: string,
options?: json.JsonObject,
scheduleOptions?: ScheduleOptions,
): Promise<BuilderRun>;

/**
* Resolve and return options for a specified target. If the target isn't defined in the
* workspace this will reject the promise. This object will be read directly from the workspace
* but not validated against the builder of the target.
* @param target The target to resolve the options of.
* @return A non-validated object resolved from the workspace.
*/
getTargetOptions(target: Target): Promise<json.JsonObject>;

/**
* Set the builder to running. This should be used if an external event triggered a re-run,
* e.g. a file watched was changed.
Expand Down
53 changes: 36 additions & 17 deletions packages/angular_devkit/architect/src/architect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export interface ScheduleOptions {
/**
* A JobRegistry that resolves builder targets from the host.
*/
export class ArchitectBuilderJobRegistry implements BuilderRegistry {
class ArchitectBuilderJobRegistry implements BuilderRegistry {
constructor(
protected _host: ArchitectHost,
protected _registry: json.schema.SchemaRegistry,
Expand Down Expand Up @@ -172,18 +172,16 @@ export class ArchitectBuilderJobRegistry implements BuilderRegistry {
return result;
}

get<
A extends json.JsonObject,
I extends BuilderInput,
O extends BuilderOutput,
>(name: string): Observable<experimental.jobs.JobHandler<A, I, O> | null> {
get<A extends json.JsonObject, I extends BuilderInput, O extends BuilderOutput>(
name: string,
): Observable<experimental.jobs.JobHandler<A, I, O> | null> {
const m = name.match(/^([^:]+):([^:]+)$/i);
if (!m) {
return of(null);
}

return from(this._resolveBuilder(name)).pipe(
concatMap(builderInfo => builderInfo ? this._createBuilder(builderInfo) : of(null)),
concatMap(builderInfo => (builderInfo ? this._createBuilder(builderInfo) : of(null))),
first(null, null),
) as Observable<experimental.jobs.JobHandler<A, I, O> | null>;
}
Expand All @@ -192,12 +190,10 @@ export class ArchitectBuilderJobRegistry implements BuilderRegistry {
/**
* A JobRegistry that resolves targets from the host.
*/
export class ArchitectTargetJobRegistry extends ArchitectBuilderJobRegistry {
get<
A extends json.JsonObject,
I extends BuilderInput,
O extends BuilderOutput,
>(name: string): Observable<experimental.jobs.JobHandler<A, I, O> | null> {
class ArchitectTargetJobRegistry extends ArchitectBuilderJobRegistry {
get<A extends json.JsonObject, I extends BuilderInput, O extends BuilderOutput>(
name: string,
): Observable<experimental.jobs.JobHandler<A, I, O> | null> {
const m = name.match(/^{([^:]+):([^:]+)(?::([^:]*))?}$/i);
if (!m) {
return of(null);
Expand All @@ -209,10 +205,12 @@ export class ArchitectTargetJobRegistry extends ArchitectBuilderJobRegistry {
configuration: m[3],
};

return from(Promise.all([
this._host.getBuilderNameForTarget(target),
this._host.getOptionsForTarget(target),
])).pipe(
return from(
Promise.all([
this._host.getBuilderNameForTarget(target),
this._host.getOptionsForTarget(target),
]),
).pipe(
concatMap(([builderStr, options]) => {
if (builderStr === null || options === null) {
return of(null);
Expand All @@ -234,6 +232,22 @@ export class ArchitectTargetJobRegistry extends ArchitectBuilderJobRegistry {
}


function _getTargetOptionsFactory(host: ArchitectHost) {
return experimental.jobs.createJobHandler<Target, json.JsonValue, json.JsonObject>(
target => {
return host.getOptionsForTarget(target).then(options => {
return options || {};
});
},
{
name: '..getTargetOptions',
output: { type: 'object' },
argument: inputSchema.properties.target,
},
);
}


export class Architect {
private readonly _scheduler: experimental.jobs.Scheduler;
private readonly _jobCache = new Map<string, Observable<BuilderJobHandler>>();
Expand All @@ -244,9 +258,14 @@ export class Architect {
private _registry: json.schema.SchemaRegistry = new json.schema.CoreSchemaRegistry(),
additionalJobRegistry?: experimental.jobs.Registry,
) {
const privateArchitectJobRegistry = new experimental.jobs.SimpleJobRegistry();
// Create private jobs.
privateArchitectJobRegistry.register(_getTargetOptionsFactory(_host));

const jobRegistry = new experimental.jobs.FallbackRegistry([
new ArchitectTargetJobRegistry(_host, _registry, this._jobCache, this._infoCache),
new ArchitectBuilderJobRegistry(_host, _registry, this._jobCache, this._infoCache),
privateArchitectJobRegistry,
...(additionalJobRegistry ? [additionalJobRegistry] : []),
] as experimental.jobs.Registry[]);

Expand Down
25 changes: 19 additions & 6 deletions packages/angular_devkit/architect/src/create-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
BuilderOutput,
BuilderOutputLike,
BuilderProgressState,
ScheduleOptions,
Target,
TypedBuilderProgress,
targetStringFromTarget,
Expand Down Expand Up @@ -96,10 +97,14 @@ export function createBuilder<
target: i.target as Target,
logger: logger,
id: i.id,
async scheduleTarget(target: Target, overrides: json.JsonObject = {}) {
async scheduleTarget(
target: Target,
overrides: json.JsonObject = {},
scheduleOptions: ScheduleOptions = {},
) {
const run = await scheduleByTarget(target, overrides, {
scheduler,
logger: logger.createChild(''),
logger: scheduleOptions.logger || logger.createChild(''),
workspaceRoot: i.workspaceRoot,
currentDirectory: i.currentDirectory,
});
Expand All @@ -109,10 +114,14 @@ export function createBuilder<

return run;
},
async scheduleBuilder(builderName: string, options: json.JsonObject = {}) {
async scheduleBuilder(
builderName: string,
options: json.JsonObject = {},
scheduleOptions: ScheduleOptions = {},
) {
const run = await scheduleByName(builderName, options, {
scheduler,
logger: logger.createChild(''),
logger: scheduleOptions.logger || logger.createChild(''),
workspaceRoot: i.workspaceRoot,
currentDirectory: i.currentDirectory,
});
Expand All @@ -122,18 +131,22 @@ export function createBuilder<

return run;
},
async getTargetOptions(target: Target) {
return scheduler.schedule<Target, json.JsonValue, json.JsonObject>(
'..getTargetOptions', target).output.toPromise();
},
reportRunning() {
switch (currentState) {
case BuilderProgressState.Waiting:
case BuilderProgressState.Stopped:
progress({state: BuilderProgressState.Running, current: 0, total}, context);
progress({ state: BuilderProgressState.Running, current: 0, total }, context);
break;
}
},
reportStatus(status: string) {
switch (currentState) {
case BuilderProgressState.Running:
progress({ state: currentState, status, current, total }, context);
progress({ state: currentState, status, current, total }, context);
break;
case BuilderProgressState.Waiting:
progress({ state: currentState, status }, context);
Expand Down
39 changes: 39 additions & 0 deletions packages/angular_devkit/architect/src/index2_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { BuilderOutput, BuilderRun } from './api';
import { Architect } from './architect';
import { createBuilder } from './create-builder';

// tslint:disable-next-line:no-big-function
describe('architect', () => {
let testArchitectHost: TestingArchitectHost;
let architect: Architect;
Expand Down Expand Up @@ -185,4 +186,42 @@ describe('architect', () => {
await run.stop();
}
});

it('exposes getTargetOptions() properly', async () => {
const goldenOptions = {
value: 'value',
};
let options = {} as object;

const target = {
project: 'project',
target: 'target',
};
testArchitectHost.addTarget(target, 'package:target', goldenOptions);

testArchitectHost.addBuilder('package:getTargetOptions', createBuilder(async (_, context) => {
options = await context.getTargetOptions(target);

return { success: true };
}));

const run = await architect.scheduleBuilder('package:getTargetOptions', {});
const output = await run.output.toPromise();
expect(output.success).toBe(true);
expect(options).toEqual(goldenOptions);
await run.stop();

// Use an invalid target and check for error.
target.target = 'invalid';
options = {};

// This should not error.
const run2 = await architect.scheduleBuilder('package:getTargetOptions', {});

// But this should.
try {
await run2.output.toPromise();
} catch {}
await run2.stop();
});
});
22 changes: 15 additions & 7 deletions packages/angular_devkit/build_angular/src/tslint/index2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,17 @@ async function _loadTslint() {
}


async function _run(config: TslintBuilderOptions, context: BuilderContext): Promise<BuilderOutput> {
async function _run(
options: TslintBuilderOptions,
context: BuilderContext,
): Promise<BuilderOutput> {
const systemRoot = context.workspaceRoot;
process.chdir(context.currentDirectory);
const options = config;
const projectName = context.target && context.target.project || '<???>';
const projectName = (context.target && context.target.project) || '<???>';

// Print formatter output only for non human-readable formats.
const printInfo = ['prose', 'verbose', 'stylish'].includes(options.format || '')
&& !options.silent;
const printInfo =
['prose', 'verbose', 'stylish'].includes(options.format || '') && !options.silent;

context.reportStatus(`Linting ${JSON.stringify(projectName)}...`);
if (printInfo) {
Expand All @@ -72,8 +74,14 @@ async function _run(config: TslintBuilderOptions, context: BuilderContext): Prom

let i = 0;
for (const program of allPrograms) {
const partial
= await _lint(projectTslint, systemRoot, tslintConfigPath, options, program, allPrograms);
const partial = await _lint(
projectTslint,
systemRoot,
tslintConfigPath,
options,
program,
allPrograms,
);
if (result === undefined) {
result = partial;
} else {
Expand Down