@atomist/sdm
Version:
Atomist Software Delivery Machine SDK
245 lines • 10.3 kB
JavaScript
;
/*
* Copyright © 2020 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.configureYaml = exports.Target = void 0;
const configuration_1 = require("@atomist/automation-client/lib/configuration");
const changeCase = require("change-case");
const fg = require("fast-glob");
const fs = require("fs-extra");
const yaml = require("js-yaml");
const stringify = require("json-stringify-safe");
const _ = require("lodash");
const path = require("path");
const trace = require("stack-trace");
const github_1 = require("../../../pack/github-goal-status/github");
const goalState_1 = require("../../../pack/goal-state/goalState");
const array_1 = require("../../util/misc/array");
const configure_1 = require("../configure");
const mapCommand_1 = require("./mapCommand");
const mapGoals_1 = require("./mapGoals");
const mapRules_1 = require("./mapRules");
const util_1 = require("./util");
var Target;
(function (Target) {
Target["SDM"] = "sdm";
Target["Skill"] = "skill";
})(Target = exports.Target || (exports.Target = {}));
async function createExtensions(cwd, options, cfg, sdm) {
var _a, _b, _c, _d, _e, _f;
const commandCallback = async (c, k) => {
let registration;
try {
const makerResult = await c(sdm);
registration = Object.assign({ name: k }, makerResult);
}
catch (e) {
e.message = `Failed to make command using CommandMaker ${k}: ${e.message}`;
throw e;
}
try {
sdm.addCommand(registration);
}
catch (e) {
e.message = `Failed to add command ${k} '${stringify(registration)}': ${e.message}`;
throw e;
}
};
if (!((_a = options === null || options === void 0 ? void 0 : options.makers) === null || _a === void 0 ? void 0 : _a.commands)) {
await awaitIterable(await requireCommands(cwd, (_b = options === null || options === void 0 ? void 0 : options.patterns) === null || _b === void 0 ? void 0 : _b.commands), commandCallback);
}
else {
await awaitIterable(options.makers.commands, commandCallback);
}
const eventCallback = async (e, k) => {
let registration;
try {
const makerResult = await e(sdm);
registration = Object.assign({ name: k }, makerResult);
}
catch (e) {
e.message = `Failed to make event using EventMaker ${k}: ${e.message}`;
throw e;
}
try {
sdm.addEvent(registration);
}
catch (e) {
e.message = `Failed to add event ${k} '${stringify(registration)}': ${e.message}`;
throw e;
}
};
if (!((_c = options.makers) === null || _c === void 0 ? void 0 : _c.events)) {
await awaitIterable(await requireEvents(cwd, (_d = options === null || options === void 0 ? void 0 : options.patterns) === null || _d === void 0 ? void 0 : _d.events), eventCallback);
}
else {
await awaitIterable(options.makers.events, eventCallback);
}
await requireIngesters(cwd, (_e = options === null || options === void 0 ? void 0 : options.patterns) === null || _e === void 0 ? void 0 : _e.ingesters);
sdm.addExtensionPacks(...(((_f = sdm.configuration.sdm) === null || _f === void 0 ? void 0 : _f.extensionPacks) || [
goalState_1.goalStateSupport({
cancellation: {
enabled: true,
},
}),
github_1.githubGoalStatusSupport(),
]));
}
/**
* Load one or more yaml files to create goal sets
*
* When providing more than one yaml file, files are being loaded
* in provided order with later files overwriting earlier ones.
*/
async function configureYaml(patterns, options = {}) {
// Get the caller of this function to determine the cwd for resolving glob patterns
const callerCallSite = trace
.get()
.filter(t => t.getFileName() !== __filename)
.filter(t => !!t.getFileName())[0];
const cwd = options.cwd || path.dirname(callerCallSite.getFileName());
const cfg = await createConfiguration(cwd, options);
return configure_1.configure(async (sdm) => {
let sdmToUse = sdm;
if (options.target === Target.Skill) {
sdmToUse = mapCommand_1.decorateSoftwareDeliveryMachine(sdm);
}
await createExtensions(cwd, options, cfg, sdmToUse);
return createGoalData(patterns, cwd, options, cfg, sdmToUse);
}, options.options || {});
}
exports.configureYaml = configureYaml;
async function createConfiguration(cwd, options) {
var _a, _b;
const cfg = {};
if (!((_a = options === null || options === void 0 ? void 0 : options.makers) === null || _a === void 0 ? void 0 : _a.configurations)) {
await awaitIterable(await requireConfiguration(cwd, (_b = options === null || options === void 0 ? void 0 : options.patterns) === null || _b === void 0 ? void 0 : _b.configurations), async (v) => {
const c = await v(cfg);
configuration_1.deepMergeConfigs(cfg, c);
});
}
else {
await awaitIterable(options.makers.configurations, async (v) => {
const c = await v(cfg);
configuration_1.deepMergeConfigs(cfg, c);
});
}
_.update(options, "options.preProcessors", old => (!!old ? old : []));
options.options.preProcessors = [
async (c) => configuration_1.deepMergeConfigs(c, cfg),
...array_1.toArray(options.options.preProcessors),
];
return cfg;
}
// tslint:disable-next-line:cyclomatic-complexity
async function createGoalData(patterns, cwd, options, cfg, sdm) {
var _a, _b;
const additionalGoals = options.goals ? await sdm.createGoals(options.goals, options.configurers) : {};
const goalMakers = !!((_a = options.makers) === null || _a === void 0 ? void 0 : _a.goals)
? options.makers.goals
: await requireGoals(cwd, _.get(cfg, "extensions.goals"));
const testMakers = !!((_b = options.makers) === null || _b === void 0 ? void 0 : _b.tests)
? options.makers.tests
: await requireTests(cwd, _.get(cfg, "extensions.tests"));
const files = await resolvePaths(cwd, patterns, true);
const goalData = {};
for (const file of files) {
const configs = yaml.safeLoadAll(await fs.readFile(path.join(cwd, file), { encoding: "UTF-8" }));
for (const config of configs) {
if (!!config.configuration) {
_.merge(sdm.configuration, util_1.camelCase(config.configuration));
}
if (!!config.skill) {
_.merge(sdm.configuration, util_1.camelCase(config.skill));
sdm.configuration.name = config.skill.name;
sdm.name = config.skill.title || config.skill.name;
}
for (const k in config) {
if (config.hasOwnProperty(k)) {
const value = config[k];
// Ignore two special keys used to set up the SDM
if (k === "name" || k === "configuration" || k === "skill") {
continue;
}
// Just create goals and register with SDM
if (k === "goals") {
await mapGoals_1.mapGoals(sdm, util_1.camelCase(value), additionalGoals, goalMakers, options.tests || {}, testMakers);
}
if (k === "rules") {
await mapRules_1.mapRules(value, goalData, sdm, options, additionalGoals, goalMakers, testMakers);
}
}
}
}
}
return goalData;
}
async function requireExtensions(cwd, pattern, cb = () => { }) {
if (pattern.length === 0) {
return {};
}
const extensions = {};
const files = await resolvePaths(cwd, pattern);
for (const file of files) {
const testJs = require(`${cwd}/${file}`);
_.forEach(testJs, (v, k) => {
if (!!cb) {
cb(v, k, extensions);
}
extensions[k] = v;
});
}
return extensions;
}
async function requireTests(cwd, pattern = ["tests/**.js", "lib/tests/**.js"]) {
return requireExtensions(cwd, pattern, (v, k, e) => (e[changeCase.snake(k)] = v));
}
async function requireGoals(cwd, pattern = ["goals/**.js", "lib/goals/**.js"]) {
return requireExtensions(cwd, pattern, (v, k, e) => (e[changeCase.snake(k)] = v));
}
async function requireCommands(cwd, pattern = ["commands/**.js", "lib/commands/**.js"]) {
return requireExtensions(cwd, pattern);
}
async function requireEvents(cwd, pattern = ["events/**.js", "lib/events/**.js"]) {
return requireExtensions(cwd, pattern);
}
async function requireConfiguration(cwd, pattern = ["config.js", "lib/config.js"]) {
return requireExtensions(cwd, pattern);
}
async function requireIngesters(cwd, pattern = ["ingesters/**.graphql", "lib/graphql/ingester/**.graphql"]) {
const ingesters = [];
const files = await resolvePaths(cwd, pattern);
for (const file of files) {
ingesters.push((await fs.readFile(file)).toString());
}
return ingesters;
}
async function awaitIterable(elems, cb) {
for (const k in elems) {
if (elems.hasOwnProperty(k)) {
const v = elems[k];
await cb(v, k);
}
}
}
async function resolvePaths(cwd, patterns, watch = false) {
const paths = await fg(array_1.toArray(patterns), { ignore: [`**/{.git,node_modules}/**`], cwd });
if (watch) {
util_1.watchPaths(paths);
}
return paths;
}
//# sourceMappingURL=configureYaml.js.map