1 | "use strict";
|
---|
2 | /**
|
---|
3 | * @license
|
---|
4 | * Copyright Google LLC All Rights Reserved.
|
---|
5 | *
|
---|
6 | * Use of this source code is governed by an MIT-style license that can be
|
---|
7 | * found in the LICENSE file at https://angular.io/license
|
---|
8 | */
|
---|
9 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
10 | exports.BaseWorkflow = void 0;
|
---|
11 | const core_1 = require("@angular-devkit/core");
|
---|
12 | const rxjs_1 = require("rxjs");
|
---|
13 | const operators_1 = require("rxjs/operators");
|
---|
14 | const engine_1 = require("../engine");
|
---|
15 | const exception_1 = require("../exception/exception");
|
---|
16 | const formats_1 = require("../formats");
|
---|
17 | const dryrun_1 = require("../sink/dryrun");
|
---|
18 | const host_1 = require("../sink/host");
|
---|
19 | const host_tree_1 = require("../tree/host-tree");
|
---|
20 | /**
|
---|
21 | * Base class for workflows. Even without abstract methods, this class should not be used without
|
---|
22 | * surrounding some initialization for the registry and host. This class only adds life cycle and
|
---|
23 | * dryrun/force support. You need to provide any registry and task executors that you need to
|
---|
24 | * support.
|
---|
25 | * See {@see NodeWorkflow} implementation for how to make a specialized subclass of this.
|
---|
26 | * TODO: add default set of CoreSchemaRegistry transforms. Once the job refactor is done, use that
|
---|
27 | * as the support for tasks.
|
---|
28 | *
|
---|
29 | * @public
|
---|
30 | */
|
---|
31 | class BaseWorkflow {
|
---|
32 | constructor(options) {
|
---|
33 | this._reporter = new rxjs_1.Subject();
|
---|
34 | this._lifeCycle = new rxjs_1.Subject();
|
---|
35 | this._host = options.host;
|
---|
36 | this._engineHost = options.engineHost;
|
---|
37 | if (options.registry) {
|
---|
38 | this._registry = options.registry;
|
---|
39 | }
|
---|
40 | else {
|
---|
41 | this._registry = new core_1.schema.CoreSchemaRegistry(formats_1.standardFormats);
|
---|
42 | this._registry.addPostTransform(core_1.schema.transforms.addUndefinedDefaults);
|
---|
43 | }
|
---|
44 | this._engine = new engine_1.SchematicEngine(this._engineHost, this);
|
---|
45 | this._context = [];
|
---|
46 | this._force = options.force || false;
|
---|
47 | this._dryRun = options.dryRun || false;
|
---|
48 | }
|
---|
49 | get context() {
|
---|
50 | const maybeContext = this._context[this._context.length - 1];
|
---|
51 | if (!maybeContext) {
|
---|
52 | throw new Error('Cannot get context when workflow is not executing...');
|
---|
53 | }
|
---|
54 | return maybeContext;
|
---|
55 | }
|
---|
56 | get engine() {
|
---|
57 | return this._engine;
|
---|
58 | }
|
---|
59 | get engineHost() {
|
---|
60 | return this._engineHost;
|
---|
61 | }
|
---|
62 | get registry() {
|
---|
63 | return this._registry;
|
---|
64 | }
|
---|
65 | get reporter() {
|
---|
66 | return this._reporter.asObservable();
|
---|
67 | }
|
---|
68 | get lifeCycle() {
|
---|
69 | return this._lifeCycle.asObservable();
|
---|
70 | }
|
---|
71 | _createSinks() {
|
---|
72 | let error = false;
|
---|
73 | const dryRunSink = new dryrun_1.DryRunSink(this._host, this._force);
|
---|
74 | const dryRunSubscriber = dryRunSink.reporter.subscribe((event) => {
|
---|
75 | this._reporter.next(event);
|
---|
76 | error = error || event.kind == 'error';
|
---|
77 | });
|
---|
78 | // We need two sinks if we want to output what will happen, and actually do the work.
|
---|
79 | return [
|
---|
80 | dryRunSink,
|
---|
81 | // Add a custom sink that clean ourselves and throws an error if an error happened.
|
---|
82 | {
|
---|
83 | commit() {
|
---|
84 | dryRunSubscriber.unsubscribe();
|
---|
85 | if (error) {
|
---|
86 | return rxjs_1.throwError(new exception_1.UnsuccessfulWorkflowExecution());
|
---|
87 | }
|
---|
88 | return rxjs_1.of();
|
---|
89 | },
|
---|
90 | },
|
---|
91 | // Only add a HostSink if this is not a dryRun.
|
---|
92 | ...(!this._dryRun ? [new host_1.HostSink(this._host, this._force)] : []),
|
---|
93 | ];
|
---|
94 | }
|
---|
95 | execute(options) {
|
---|
96 | const parentContext = this._context[this._context.length - 1];
|
---|
97 | if (!parentContext) {
|
---|
98 | this._lifeCycle.next({ kind: 'start' });
|
---|
99 | }
|
---|
100 | /** Create the collection and the schematic. */
|
---|
101 | const collection = this._engine.createCollection(options.collection);
|
---|
102 | // Only allow private schematics if called from the same collection.
|
---|
103 | const allowPrivate = options.allowPrivate || (parentContext && parentContext.collection === options.collection);
|
---|
104 | const schematic = collection.createSchematic(options.schematic, allowPrivate);
|
---|
105 | const sinks = this._createSinks();
|
---|
106 | this._lifeCycle.next({ kind: 'workflow-start' });
|
---|
107 | const context = {
|
---|
108 | ...options,
|
---|
109 | debug: options.debug || false,
|
---|
110 | logger: options.logger || (parentContext && parentContext.logger) || new core_1.logging.NullLogger(),
|
---|
111 | parentContext,
|
---|
112 | };
|
---|
113 | this._context.push(context);
|
---|
114 | return schematic
|
---|
115 | .call(options.options, rxjs_1.of(new host_tree_1.HostTree(this._host)), { logger: context.logger })
|
---|
116 | .pipe(operators_1.concatMap((tree) => {
|
---|
117 | // Process all sinks.
|
---|
118 | return rxjs_1.concat(rxjs_1.from(sinks).pipe(operators_1.concatMap((sink) => sink.commit(tree)), operators_1.ignoreElements()), rxjs_1.of(tree));
|
---|
119 | }), operators_1.concatMap(() => {
|
---|
120 | if (this._dryRun) {
|
---|
121 | return rxjs_1.EMPTY;
|
---|
122 | }
|
---|
123 | this._lifeCycle.next({ kind: 'post-tasks-start' });
|
---|
124 | return this._engine
|
---|
125 | .executePostTasks()
|
---|
126 | .pipe(operators_1.tap({ complete: () => this._lifeCycle.next({ kind: 'post-tasks-end' }) }), operators_1.defaultIfEmpty(), operators_1.last());
|
---|
127 | }), operators_1.tap({
|
---|
128 | complete: () => {
|
---|
129 | this._lifeCycle.next({ kind: 'workflow-end' });
|
---|
130 | this._context.pop();
|
---|
131 | if (this._context.length == 0) {
|
---|
132 | this._lifeCycle.next({ kind: 'end' });
|
---|
133 | }
|
---|
134 | },
|
---|
135 | }));
|
---|
136 | }
|
---|
137 | }
|
---|
138 | exports.BaseWorkflow = BaseWorkflow;
|
---|