@atomist/sdm-core
Version:
Atomist Software Delivery Machine - Implementation
236 lines • 12.9 kB
JavaScript
/*
* Copyright © 2019 Atomist, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const automation_client_1 = require("@atomist/automation-client");
const decorators_1 = require("@atomist/automation-client/lib/decorators");
const sdm_1 = require("@atomist/sdm");
const SdmGoalMessage_1 = require("@atomist/sdm/lib/api/goal/SdmGoalMessage");
const os = require("os");
const goalCaching_1 = require("../../../../goal/cache/goalCaching");
const validateGoal_1 = require("../../../../internal/delivery/goals/support/validateGoal");
const goalSigning_1 = require("../../../../internal/signing/goalSigning");
const array_1 = require("../../../../util/misc/array");
const time_1 = require("../../../../util/misc/time");
/**
* Handle an SDM request goal. Used for many implementation types.
*/
let FulfillGoalOnRequested = class FulfillGoalOnRequested {
constructor(implementationMapper, goalExecutionListeners) {
this.implementationMapper = implementationMapper;
this.goalExecutionListeners = goalExecutionListeners;
}
/* tslint:disable:cyclomatic-complexity */
handle(event, ctx) {
return __awaiter(this, void 0, void 0, function* () {
const sdmGoal = event.data.SdmGoal[0];
if (!validateGoal_1.shouldFulfill(sdmGoal)) {
automation_client_1.logger.debug(`Goal ${sdmGoal.uniqueName} skipped because not fulfilled by this SDM`);
return automation_client_1.Success;
}
yield goalSigning_1.verifyGoal(sdmGoal, this.configuration.sdm.goalSigning, ctx);
if ((yield sdm_1.cancelableGoal(sdmGoal, this.configuration)) && (yield sdm_1.isGoalCanceled(sdmGoal, ctx))) {
automation_client_1.logger.debug(`Goal ${sdmGoal.uniqueName} has been canceled. Not fulfilling`);
return automation_client_1.Success;
}
if (sdmGoal.fulfillment.method === SdmGoalMessage_1.SdmGoalFulfillmentMethod.SideEffect &&
sdmGoal.fulfillment.registration !== this.configuration.name) {
automation_client_1.logger.debug("Not fulfilling side-effected goal '%s' with method '%s/%s'", sdmGoal.uniqueName, sdmGoal.fulfillment.method, sdmGoal.fulfillment.name);
return automation_client_1.Success;
}
else if (sdmGoal.fulfillment.method === SdmGoalMessage_1.SdmGoalFulfillmentMethod.Other) {
// fail goal with neither Sdm nor SideEffect fulfillment
yield sdm_1.updateGoal(ctx, sdmGoal, {
state: sdm_1.SdmGoalState.failure,
description: `No fulfillment for ${sdmGoal.uniqueName}`,
});
return automation_client_1.Success;
}
const id = this.configuration.sdm.repoRefResolver.repoRefFromSdmGoal(sdmGoal);
const credentials = yield sdm_1.resolveCredentialsPromise(this.configuration.sdm.credentialsResolver.eventHandlerCredentials(ctx, id));
const addressChannels = sdm_1.addressChannelsFor(sdmGoal.push.repo, ctx);
const preferences = this.configuration.sdm.preferenceStoreFactory(ctx);
const implementation = this.implementationMapper.findImplementationBySdmGoal(sdmGoal);
const { goal } = implementation;
const progressLog = new sdm_1.WriteToAllProgressLog(sdmGoal.name, new sdm_1.LoggingProgressLog(sdmGoal.name, "debug"), yield this.configuration.sdm.logFactory(ctx, sdmGoal));
const goalInvocation = {
configuration: this.configuration,
sdmGoal,
goalEvent: sdmGoal,
goal,
progressLog,
context: ctx,
addressChannels,
preferences,
id,
credentials,
parameters: !!event.data.SdmGoal[0].parameters ? JSON.parse(event.data.SdmGoal[0].parameters) : {},
};
const goalScheduler = yield findGoalScheduler(goalInvocation, this.configuration);
if (!!goalScheduler) {
const start = Date.now();
const result = yield goalScheduler.schedule(goalInvocation);
if (!!result && result.code !== undefined && result.code !== 0) {
yield sdm_1.updateGoal(ctx, sdmGoal, {
state: sdm_1.SdmGoalState.failure,
description: `Failed to schedule goal`,
url: progressLog.url,
});
yield reportEndAndClose(result, start, progressLog);
}
else {
yield sdm_1.updateGoal(ctx, sdmGoal, {
state: !!result && !!result.state ? result.state : sdm_1.SdmGoalState.in_process,
phase: !!result && !!result.phase ? result.phase : "scheduled",
description: !!result && !!result.description ? result.description : sdm_1.descriptionFromState(goal, sdm_1.SdmGoalState.in_process, sdmGoal),
url: progressLog.url,
externalUrls: !!result ? result.externalUrls : undefined,
});
}
return Object.assign(Object.assign({}, result), {
// successfully handled event even if goal failed
code: 0 });
}
else {
delete sdmGoal.id;
const listeners = [];
// Prepare cache project listeners for parameters
if (!!goalInvocation.parameters) {
if (!!goalInvocation.parameters[goalCaching_1.CacheInputGoalDataKey]) {
const input = goalInvocation.parameters[goalCaching_1.CacheInputGoalDataKey];
if (!!input && input.length > 0) {
listeners.push(goalCaching_1.cacheRestore({ entries: input }));
}
}
if (!!goalInvocation.parameters[goalCaching_1.CacheOutputGoalDataKey]) {
const output = goalInvocation.parameters[goalCaching_1.CacheOutputGoalDataKey];
if (!!output && output.length > 0) {
listeners.push(goalCaching_1.cachePut({ entries: output }));
}
}
}
yield reportStart(sdmGoal, progressLog);
const start = Date.now();
try {
const result = yield sdm_1.executeGoal({
projectLoader: this.configuration.sdm.projectLoader,
goalExecutionListeners: this.goalExecutionListeners,
}, Object.assign(Object.assign({}, implementation), { projectListeners: [...array_1.toArray(implementation.projectListeners || []), ...listeners] }), goalInvocation);
const terminatingStates = [
sdm_1.SdmGoalState.canceled,
sdm_1.SdmGoalState.failure,
sdm_1.SdmGoalState.skipped,
sdm_1.SdmGoalState.stopped,
sdm_1.SdmGoalState.success,
sdm_1.SdmGoalState.waiting_for_approval,
];
if (!result || !result.state || terminatingStates.includes(result.state)) {
yield reportEndAndClose(result, start, progressLog);
}
return Object.assign(Object.assign({}, result), {
// successfully handled event even if goal failed
code: 0 });
}
catch (e) {
e.message = `Goal executor threw exception: ${e.message}`;
const egr = {
code: 1,
message: e.message,
state: sdm_1.SdmGoalState.failure,
};
yield reportEndAndClose(egr, start, progressLog);
throw e;
}
}
});
}
};
__decorate([
automation_client_1.Value("") // empty path returns the entire configuration
,
__metadata("design:type", Object)
], FulfillGoalOnRequested.prototype, "configuration", void 0);
FulfillGoalOnRequested = __decorate([
decorators_1.EventHandler("Fulfill a goal when it reaches 'requested' state", automation_client_1.GraphQL.subscription("OnAnyRequestedSdmGoal")),
__metadata("design:paramtypes", [Object, Array])
], FulfillGoalOnRequested);
exports.FulfillGoalOnRequested = FulfillGoalOnRequested;
function findGoalScheduler(gi, configuration) {
return __awaiter(this, void 0, void 0, function* () {
let goalSchedulers;
if (!configuration.sdm.goalScheduler) {
return undefined;
}
else if (!Array.isArray(configuration.sdm.goalScheduler)) {
goalSchedulers = [configuration.sdm.goalScheduler];
}
else {
goalSchedulers = configuration.sdm.goalScheduler;
}
for (const gl of goalSchedulers) {
if (yield gl.supports(gi)) {
return gl;
}
}
return undefined;
});
}
function reportStart(sdmGoal, progressLog) {
return __awaiter(this, void 0, void 0, function* () {
progressLog.write(`/--`);
progressLog.write(`Start: ${sdm_1.formatDate(new Date(), "yyyy-mm-dd HH:MM:ss.l")}`);
progressLog.write(`Repository: ${sdmGoal.push.repo.owner}/${sdmGoal.push.repo.name}/${sdmGoal.branch}`);
progressLog.write(`Sha: ${sdmGoal.sha}`);
progressLog.write(`Goal: ${sdmGoal.name} (${sdmGoal.uniqueName})`);
progressLog.write(`Environment: ${sdmGoal.environment.slice(2)}`);
progressLog.write(`GoalSet: ${sdmGoal.goalSet} - ${sdmGoal.goalSetId}`);
progressLog.write(`Host: ${os.hostname()}`);
progressLog.write(`SDM: ${automation_client_1.automationClientInstance().configuration.name}:${automation_client_1.automationClientInstance().configuration.version}`);
progressLog.write("\\--");
yield progressLog.flush();
});
}
exports.reportStart = reportStart;
function reportEndAndClose(result, start, progressLog) {
return __awaiter(this, void 0, void 0, function* () {
progressLog.write(`/--`);
progressLog.write(`Result: ${sdm_1.serializeResult(result)}`);
progressLog.write(`Duration: ${time_1.formatDuration(Date.now() - start)}`);
progressLog.write(`Finish: ${sdm_1.formatDate(new Date(), "yyyy-mm-dd HH:MM:ss.l")}`);
progressLog.write("\\--");
yield progressLog.close();
});
}
exports.reportEndAndClose = reportEndAndClose;
//# sourceMappingURL=FulfillGoalOnRequested.js.map
;