UNPKG

12.3 kBJavaScriptView Raw
1"use strict";
2/*
3 * Copyright © 2020 Atomist, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17Object.defineProperty(exports, "__esModule", { value: true });
18exports.mergeOptions = exports.getGoalDefinitionFrom = exports.goal = exports.GoalWithFulfillment = exports.FulfillableGoalWithRegistrationsAndListeners = exports.FulfillableGoalWithRegistrations = exports.FulfillableGoal = exports.isSideEffect = exports.isImplementation = void 0;
19const configuration_1 = require("@atomist/automation-client/lib/configuration");
20const _ = require("lodash");
21const sdmGoal_1 = require("../../api-helper/goal/sdmGoal");
22const logInterpreters_1 = require("../../api-helper/log/logInterpreters");
23const Registerable_1 = require("../machine/Registerable");
24const commonPushTests_1 = require("../mapping/support/commonPushTests");
25const ServiceRegistration_1 = require("../registration/ServiceRegistration");
26const createGoal_1 = require("./common/createGoal");
27const Goal_1 = require("./Goal");
28const GoalNameGenerator_1 = require("./GoalNameGenerator");
29const environment_1 = require("./support/environment");
30function isImplementation(f) {
31 return !!f && !!f.goalExecutor && true;
32}
33exports.isImplementation = isImplementation;
34function isSideEffect(f) {
35 return !isImplementation(f);
36}
37exports.isSideEffect = isSideEffect;
38/**
39 * Goal that registers goal implementations, side effects and callbacks on the
40 * current SDM. No additional registration with the SDM is needed.
41 */
42class FulfillableGoal extends Goal_1.GoalWithPrecondition {
43 constructor(definitionOrGoal, ...dependsOn) {
44 super(Goal_1.isGoalDefinition(definitionOrGoal) ? definitionOrGoal : definitionOrGoal.definition, ...dependsOn);
45 this.definitionOrGoal = definitionOrGoal;
46 this.fulfillments = [];
47 this.callbacks = [];
48 this.projectListeners = [];
49 this.goalListeners = [];
50 Registerable_1.registerRegistrable(this);
51 }
52 register(sdm) {
53 this.sdm = sdm;
54 this.fulfillments.forEach(f => this.registerFulfillment(f));
55 this.callbacks.forEach(cb => this.registerCallback(cb));
56 this.goalListeners.forEach(gl => sdm.addGoalExecutionListener(gl));
57 }
58 withProjectListener(listener) {
59 this.projectListeners.push(listener);
60 return this;
61 }
62 withExecutionListener(listener) {
63 const wrappedListener = async (gi) => {
64 if (gi.goalEvent.uniqueName === this.uniqueName) {
65 return listener(gi);
66 }
67 };
68 if (this.sdm) {
69 this.sdm.addGoalExecutionListener(wrappedListener);
70 }
71 this.goalListeners.push(wrappedListener);
72 return this;
73 }
74 withService(registration) {
75 this.addFulfillmentCallback({
76 goal: this,
77 callback: async (goalEvent, repoContext) => {
78 const service = await registration.service(goalEvent, repoContext);
79 if (!!service) {
80 const data = sdmGoal_1.goalData(goalEvent);
81 const servicesData = {};
82 _.set(servicesData, `${ServiceRegistration_1.ServiceRegistrationGoalDataKey}.${registration.name}`, service);
83 goalEvent.data = JSON.stringify(_.merge(data, servicesData));
84 }
85 return goalEvent;
86 },
87 });
88 return this;
89 }
90 addFulfillmentCallback(cb) {
91 if (this.sdm) {
92 this.registerCallback(cb);
93 }
94 this.callbacks.push(cb);
95 return this;
96 }
97 addFulfillment(fulfillment) {
98 if (this.sdm) {
99 this.registerFulfillment(fulfillment);
100 }
101 this.fulfillments.push(fulfillment);
102 return this;
103 }
104 registerFulfillment(fulfillment) {
105 if (isImplementation(fulfillment)) {
106 let goalExecutor = fulfillment.goalExecutor;
107 // Wrap the ExecuteGoal instance with WaitRules if provided
108 if (Goal_1.isGoalDefinition(this.definitionOrGoal) && !!this.definitionOrGoal.preCondition) {
109 goalExecutor = createGoal_1.createPredicatedGoalExecutor(this.definitionOrGoal.uniqueName, goalExecutor, this.definitionOrGoal.preCondition);
110 }
111 if (Goal_1.isGoalDefinition(this.definitionOrGoal) && !!this.definitionOrGoal.retryCondition) {
112 goalExecutor = createGoal_1.createRetryingGoalExecutor(this.definitionOrGoal.uniqueName, goalExecutor, this.definitionOrGoal.retryCondition);
113 }
114 this.sdm.addGoalImplementation(fulfillment.name, this, goalExecutor, {
115 pushTest: fulfillment.pushTest || commonPushTests_1.AnyPush,
116 progressReporter: fulfillment.progressReporter,
117 logInterpreter: fulfillment.logInterpreter,
118 projectListeners: this.projectListeners,
119 });
120 }
121 else if (isSideEffect(fulfillment)) {
122 this.sdm.addGoalSideEffect(this, fulfillment.name, fulfillment.registration, fulfillment.pushTest);
123 }
124 }
125 async plan(pli, goals) {
126 return undefined;
127 }
128 registerCallback(cb) {
129 this.sdm.goalFulfillmentMapper.addFulfillmentCallback(cb);
130 }
131}
132exports.FulfillableGoal = FulfillableGoal;
133/**
134 * Goal that accepts registrations of R.
135 */
136class FulfillableGoalWithRegistrations extends FulfillableGoal {
137 constructor(definitionOrGoal, ...dependsOn) {
138 super(definitionOrGoal, ...dependsOn);
139 this.definitionOrGoal = definitionOrGoal;
140 this.registrations = [];
141 }
142 with(registration) {
143 this.registrations.push(registration);
144 return this;
145 }
146}
147exports.FulfillableGoalWithRegistrations = FulfillableGoalWithRegistrations;
148/**
149 * Goal that accepts registrations of R and listeners of L.
150 */
151class FulfillableGoalWithRegistrationsAndListeners extends FulfillableGoalWithRegistrations {
152 constructor(definitionOrGoal, ...dependsOn) {
153 super(definitionOrGoal, ...dependsOn);
154 this.definitionOrGoal = definitionOrGoal;
155 this.listeners = [];
156 }
157 withListener(listener) {
158 this.listeners.push(listener);
159 return this;
160 }
161}
162exports.FulfillableGoalWithRegistrationsAndListeners = FulfillableGoalWithRegistrationsAndListeners;
163/**
164 * Generic goal that can be used with a GoalDefinition.
165 * Register goal implementations or side effects to this goal instance.
166 */
167class GoalWithFulfillment extends FulfillableGoal {
168 withCallback(cb) {
169 this.addFulfillmentCallback(cb);
170 return this;
171 }
172 with(fulfillment) {
173 this.addFulfillment(fulfillment);
174 return this;
175 }
176}
177exports.GoalWithFulfillment = GoalWithFulfillment;
178/**
179 * Creates a new GoalWithFulfillment instance using conventions if overwrites aren't provided
180 *
181 * Call this from your machine.ts where you configure your sdm to create a custom goal.
182 *
183 * Caution: if you wrap this in another function, then you MUST provide details.uniqueName,
184 * because the default is based on where in the code this `goal` function is called.
185 *
186 * @param details It is highly recommended that you supply at least uniqueName.
187 * @param goalExecutor
188 * @param options
189 */
190function goal(details = {}, goalExecutor, options) {
191 const def = getGoalDefinitionFrom(details, GoalNameGenerator_1.DefaultGoalNameGenerator.generateName(details.displayName || "goal"));
192 const g = new GoalWithFulfillment(def);
193 if (!!goalExecutor) {
194 const optsToUse = Object.assign({ pushTest: commonPushTests_1.AnyPush, logInterpreter: logInterpreters_1.LogSuppressor }, (!!options ? options : {}));
195 g.with(Object.assign({ name: def.uniqueName, goalExecutor }, optsToUse));
196 if (!!optsToUse.plan) {
197 g.plan = optsToUse.plan;
198 }
199 }
200 return g;
201}
202exports.goal = goal;
203/**
204 * Construct a PredicatedGoalDefinition from the provided goalDetails
205 * @param goalDetails
206 * @param uniqueName
207 * @param definition
208 */
209// tslint:disable:cyclomatic-complexity
210function getGoalDefinitionFrom(goalDetails, uniqueName, definition) {
211 if (typeof goalDetails === "string") {
212 return Object.assign(Object.assign({}, (definition || {})), { uniqueName: goalDetails || uniqueName });
213 }
214 else {
215 const defaultDefinition = Object.assign({}, (definition || {}));
216 const goalDetailsToUse = goalDetails || {};
217 if (!!goalDetailsToUse.descriptions) {
218 defaultDefinition.canceledDescription = goalDetailsToUse.descriptions.canceled || defaultDefinition.canceledDescription;
219 defaultDefinition.completedDescription = goalDetailsToUse.descriptions.completed || defaultDefinition.completedDescription;
220 defaultDefinition.failedDescription = goalDetailsToUse.descriptions.failed || defaultDefinition.failedDescription;
221 defaultDefinition.plannedDescription = goalDetailsToUse.descriptions.planned || defaultDefinition.plannedDescription;
222 defaultDefinition.requestedDescription = goalDetailsToUse.descriptions.requested || defaultDefinition.requestedDescription;
223 defaultDefinition.stoppedDescription = goalDetailsToUse.descriptions.stopped || defaultDefinition.stoppedDescription;
224 defaultDefinition.waitingForApprovalDescription =
225 goalDetailsToUse.descriptions.waitingForApproval || defaultDefinition.waitingForApprovalDescription;
226 defaultDefinition.waitingForPreApprovalDescription =
227 goalDetailsToUse.descriptions.waitingForPreApproval || defaultDefinition.waitingForPreApprovalDescription;
228 defaultDefinition.workingDescription = goalDetailsToUse.descriptions.inProcess || defaultDefinition.workingDescription;
229 }
230 return Object.assign(Object.assign({}, defaultDefinition), { displayName: goalDetailsToUse.displayName || defaultDefinition.displayName, uniqueName: goalDetailsToUse.uniqueName || uniqueName, environment: getEnvironment(goalDetailsToUse), approvalRequired: goalDetailsToUse.approval || defaultDefinition.approvalRequired, preApprovalRequired: goalDetailsToUse.preApproval || defaultDefinition.preApprovalRequired, retryFeasible: goalDetailsToUse.retry || defaultDefinition.retryFeasible, isolated: goalDetailsToUse.isolate || defaultDefinition.isolated, preCondition: goalDetailsToUse.preCondition });
231 }
232}
233exports.getGoalDefinitionFrom = getGoalDefinitionFrom;
234/**
235 * Merge Goal configuration options into a final options object.
236 * Starts off by merging the explicitly provided options over the provided defaults; finally merges the configuration
237 * values at the given configuration path (prefixed with sdm.) over the previous merge.
238 * @param defaults
239 * @param explicit
240 * @param configurationPath
241 */
242function mergeOptions(defaults, explicit, configurationPath) {
243 const options = _.merge(_.cloneDeep(defaults), explicit || {});
244 if (!!configurationPath) {
245 const configurationOptions = configuration_1.configurationValue(`sdm.${configurationPath}`, {});
246 return _.merge(options, configurationOptions);
247 }
248 return options;
249}
250exports.mergeOptions = mergeOptions;
251function getEnvironment(details) {
252 if (details && details.environment && typeof details.environment === "string") {
253 switch (details.environment) {
254 case "testing":
255 return environment_1.StagingEnvironment;
256 case "production":
257 return environment_1.ProductionEnvironment;
258 default:
259 return environment_1.IndependentOfEnvironment;
260 }
261 }
262 else if (details && typeof details.environment !== "string") {
263 return details.environment;
264 }
265 else {
266 return environment_1.IndependentOfEnvironment;
267 }
268}
269//# sourceMappingURL=GoalWithFulfillment.js.map
\No newline at end of file