@atomist/sdm-pack-fingerprints
Version:
an Atomist SDM Extension Pack for fingerprinting code
298 lines (294 loc) • 13.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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(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 sdm_1 = require("@atomist/sdm");
const slack_messages_1 = require("@atomist/slack-messages");
const fingerprints_1 = require("../../adhoc/fingerprints");
const preferences_1 = require("../../adhoc/preferences");
const Aspects_1 = require("../../machine/Aspects");
const messages_1 = require("../../support/messages");
/**
* Call relevant apply functions from Registrations for a Fingerprint
* This happens in the context of an an editable Project
*/
function pushFingerprint(p, aspects, fp) {
return __awaiter(this, void 0, void 0, function* () {
const aspect = Aspects_1.aspectOf(fp, aspects);
if (!!aspect && !!aspect.apply) {
const result = yield aspect.apply(p, fp);
if (result) {
automation_client_1.logger.info(`Successfully applied policy ${fp.name}`);
}
return result;
}
return false;
});
}
/**
* Create a CodeTransform that can be used to apply a Fingerprint to a Project
* This CodeTransform is takes one target Fingerprint in it's set of parameters.
*/
function runAllFingerprintAppliers(aspects) {
return (p, cli) => __awaiter(this, void 0, void 0, function* () {
const { type, name } = preferences_1.fromName(cli.parameters.targetfingerprint);
const aspect = Aspects_1.aspectOf({ type }, aspects);
let details;
if (!!aspect && !!aspect.toDisplayableFingerprintName) {
details = `${slack_messages_1.italic(aspect.displayName)} ${slack_messages_1.codeLine(aspect.toDisplayableFingerprintName(name))}`;
}
else {
details = slack_messages_1.codeLine(cli.parameters.targetfingerprint);
}
const message = sdm_1.slackInfoMessage("Apply Policy", `Applying policy to ${slack_messages_1.bold(`${p.id.owner}/${p.id.repo}/${p.id.branch}:`)}
${details}`);
yield cli.addressChannels(message, { id: cli.parameters.msgId });
const fingerprint = yield preferences_1.queryPreferences(cli.context.graphClient, type, name);
const result = yield pushFingerprint(p, aspects, fingerprint);
if (!cli.parameters.title) {
cli.parameters.title = messages_1.applyFingerprintTitle(fingerprint, aspects);
}
if (!cli.parameters.body) {
cli.parameters.body = messages_1.prBodyFromFingerprint(fingerprint, aspects);
}
if (result) {
return p;
}
else {
return { edited: false, success: true, target: p };
}
});
}
exports.runAllFingerprintAppliers = runAllFingerprintAppliers;
function runFingerprintAppliersBySha(aspects) {
return (p, cli) => __awaiter(this, void 0, void 0, function* () {
const { type, name } = preferences_1.fromName(cli.parameters.targetfingerprint);
const aspect = Aspects_1.aspectOf({ type }, aspects);
let details;
if (!!aspect && !!aspect.toDisplayableFingerprintName) {
details = `${slack_messages_1.italic(aspect.displayName)} ${slack_messages_1.codeLine(aspect.toDisplayableFingerprintName(name))}`;
}
else {
details = slack_messages_1.codeLine(cli.parameters.targetfingerprint);
}
const message = sdm_1.slackInfoMessage("Apply Policy", `Applying policy to ${slack_messages_1.bold(`${p.id.owner}/${p.id.repo}/${p.id.branch}:`)}
${details}`);
yield cli.addressChannels(message, { id: cli.parameters.msgId });
const fp = yield cli.context.graphClient.query({
name: "GetFpBySha",
variables: {
type,
name,
sha: cli.parameters.sha,
},
options: automation_client_1.QueryNoCacheOptions,
});
const fingerprint = {
type,
name,
data: JSON.parse(fp.SourceFingerprint.data),
sha: fp.SourceFingerprint.sha,
};
const result = yield pushFingerprint(p, aspects, fingerprint);
if (!cli.parameters.title) {
cli.parameters.title = messages_1.applyFingerprintTitle(fingerprint, aspects);
}
if (!cli.parameters.body) {
cli.parameters.body = messages_1.prBodyFromFingerprint(fingerprint, aspects);
}
if (result) {
return p;
}
else {
return { edited: false, success: true, target: p };
}
});
}
exports.runFingerprintAppliersBySha = runFingerprintAppliersBySha;
/**
* Create a CodeTransform that can be used to apply a Fingerprint to a Project
* This CodeTransform takes a set of Fingerprints in it's set of parameters
*/
function runEveryFingerprintApplication(aspects) {
return (p, cli) => __awaiter(this, void 0, void 0, function* () {
const fingerprints = cli.parameters.fingerprints.split(",").map(fp => fp.trim());
const details = fingerprints.map(f => {
const { type, name } = preferences_1.fromName(f);
const aspect = Aspects_1.aspectOf({ type }, aspects);
let detail;
if (!!aspect && !!aspect.toDisplayableFingerprintName) {
detail = `${slack_messages_1.italic(aspect.displayName)} ${slack_messages_1.codeLine(aspect.toDisplayableFingerprintName(name))}`;
}
else {
detail = slack_messages_1.codeLine(f);
}
return detail;
});
const message = sdm_1.slackInfoMessage("Apply Policies", `Applying policies to ${slack_messages_1.bold(`${p.id.owner}/${p.id.repo}/${p.id.branch}`)}:
${details.join("\n")}`);
yield cli.addressChannels(message, { id: cli.parameters.msgId });
for (const fpName of fingerprints) {
const { type, name } = preferences_1.fromName(fpName.trim());
const result = yield pushFingerprint(p, aspects, yield preferences_1.queryPreferences(cli.context.graphClient, type, name));
if (!result) {
return { edited: false, success: true, target: p };
}
}
return p;
});
}
exports.ApplyTargetFingerprintName = "ApplyTargetFingerprint";
function applyTarget(sdm, aspects, presentation) {
return {
name: exports.ApplyTargetFingerprintName,
intent: [
`apply fingerprint target ${sdm.configuration.name.replace("@", "")}`,
`applyFingerprint ${sdm.configuration.name.replace("@", "")}`,
],
description: "choose to raise a PR on the current project to apply a target fingerprint",
parameters: {
msgId: { required: false, displayable: false },
targetfingerprint: { required: true },
body: { required: false, displayable: true, control: "textarea", pattern: /[\S\s]*/ },
title: { required: false, displayable: true, control: "textarea", pattern: /[\S\s]*/ },
branch: { required: false, displayable: false },
},
transformPresentation: presentation,
transform: runAllFingerprintAppliers(aspects),
autoSubmit: true,
};
}
exports.applyTarget = applyTarget;
exports.ApplyTargetFingerprintByShaName = "ApplyTargetFingerprintBySha";
function applyTargetBySha(sdm, aspects, presentation) {
return {
name: exports.ApplyTargetFingerprintByShaName,
intent: [
`apply fingerprint target by sha ${sdm.configuration.name.replace("@", "")}`,
],
description: "Apply a fingerprint target identified by the fingerprint's sha and type",
parameters: {
msgId: { required: false, displayable: false },
targetfingerprint: { required: true },
sha: { required: true },
body: { required: false, displayable: true, control: "textarea", pattern: /[\S\s]*/ },
title: { required: false, displayable: true, control: "textarea", pattern: /[\S\s]*/ },
branch: { required: false, displayable: false },
},
transformPresentation: presentation,
transform: runFingerprintAppliersBySha(aspects),
autoSubmit: true,
};
}
exports.applyTargetBySha = applyTargetBySha;
// use where ApplyTargetFingerprints was used
exports.ApplyAllFingerprintsName = "ApplyAllFingerprints";
function applyTargets(sdm, registrations, presentation) {
return {
name: exports.ApplyAllFingerprintsName,
description: "apply a bunch of fingerprints",
transform: runEveryFingerprintApplication(registrations),
transformPresentation: presentation,
parameters: {
msgId: { required: false, displayable: false },
fingerprints: { required: true },
body: { required: false, displayable: true, control: "textarea", pattern: /[\S\s]*/ },
title: { required: false, displayable: true, control: "textarea", pattern: /[\S\s]*/ },
branch: { required: false, displayable: false },
},
autoSubmit: true,
};
}
exports.applyTargets = applyTargets;
exports.BroadcastFingerprintMandateName = "BroadcastFingerprintMandate";
function broadcastFingerprintMandate(sdm, aspects) {
return {
name: exports.BroadcastFingerprintMandateName,
description: "create a PR in many Repos",
listener: (i) => __awaiter(this, void 0, void 0, function* () {
const refs = [];
const { type, name } = preferences_1.fromName(i.parameters.fingerprint);
const fp = yield preferences_1.queryPreferences(i.context.graphClient, type, name);
const data = yield (fingerprints_1.findTaggedRepos(i.context.graphClient))(fp.type, fp.name);
// TODO does the analysis only have the matching tagged repos or all of them?
if (!!data.headCommitsWithFingerprint) {
refs.push(...data.headCommitsWithFingerprint
.filter(head => !!head.branch && !!head.branch.name && head.branch.name === "master")
.filter(head => head.analysis.some(x => {
return x.type === fp.type &&
x.name === fp.name &&
x.sha !== fp.sha;
}))
.map(x => {
return {
owner: x.repo.owner,
repo: x.repo.name,
url: "url",
branch: "master",
};
}));
}
const aspect = Aspects_1.aspectOf({ type }, aspects);
let details;
if (!!aspect && !!aspect.toDisplayableFingerprintName) {
details = `${slack_messages_1.italic(aspect.displayName)} ${slack_messages_1.codeLine(aspect.toDisplayableFingerprintName(name))}`;
}
else {
details = slack_messages_1.codeLine(i.parameters.fingerprint);
}
yield sdm_1.createJob({
command: exports.ApplyTargetFingerprintName,
description: `Applying policy:
${details}`,
name: `ApplyPolicy/${i.parameters.fingerprint}`,
parameters: refs.map(r => ({
title: i.parameters.title,
body: i.parameters.body,
branch: r.branch,
targetfingerprint: i.parameters.fingerprint,
targets: {
owner: r.owner,
repo: r.repo,
branch: r.branch,
},
})),
}, i.context);
const message = sdm_1.slackSuccessMessage("Boardcast Policy Update", `Successfully scheduled job to apply target for fingerprint ${slack_messages_1.codeLine(i.parameters.fingerprint)} to $
refs.length} ${refs.length > 1 ? "repositories" : "repository"}`);
// replace the previous message where we chose this action
yield i.addressChannels(message, { id: i.parameters.msgId });
}),
parameters: {
msgId: { required: false, displayable: false },
fingerprint: { required: true },
body: { required: false, displayable: true, control: "textarea", pattern: /[\S\s]*/ },
title: { required: false, displayable: true, control: "textarea", pattern: /[\S\s]*/ },
branch: { required: false, displayable: false },
},
autoSubmit: true,
};
}
exports.broadcastFingerprintMandate = broadcastFingerprintMandate;
//# sourceMappingURL=applyFingerprint.js.map