UNPKG

@atomist/sdm-core

Version:

Atomist Software Delivery Machine - Implementation

236 lines 12.9 kB
"use strict"; /* * 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