UNPKG

@atomist/sdm

Version:

Atomist Software Delivery Machine SDK

158 lines (144 loc) 6.3 kB
/* * 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. */ import { SeedDrivenGeneratorParameters } from "@atomist/automation-client/lib/operations/generate/SeedDrivenGeneratorParameters"; import { Project } from "@atomist/automation-client/lib/project/Project"; import { NoParameters } from "@atomist/automation-client/lib/SmartParameters"; import * as _ from "lodash"; import { computeStartingPoint } from "../../api-helper/command/generator/generatorCommand"; import { projectLoaderRepoLoader } from "../../api-helper/machine/projectLoaderRepoLoader"; import { toMachineOptions } from "../../api-helper/machine/toMachineOptions"; import { CachingProjectLoader } from "../../api-helper/project/CachingProjectLoader"; import { CommandListenerInvocation } from "../../api/listener/CommandListener"; import { SoftwareDeliveryMachine } from "../../api/machine/SoftwareDeliveryMachine"; import { CodeTransform, TransformResult, TransformReturnable, } from "../../api/registration/CodeTransform"; import { GeneratorRegistration } from "../../api/registration/GeneratorRegistration"; import { ParametersObject } from "../../api/registration/ParametersDefinition"; import { toArray } from "../../core/util/misc/array"; import { UniversalTransform } from "./generatorSupport"; /** * Wrap provided generator to execute additional transformsAndParameters */ export function universalGenerator<P extends SeedDrivenGeneratorParameters = any>( sdm: SoftwareDeliveryMachine, generator: GeneratorRegistration<any>, transforms: Array<UniversalTransform<any>>, ): GeneratorRegistration<P> { return { ...generator, startingPoint: async pi => { const repoLoader = (p: SeedDrivenGeneratorParameters) => projectLoaderRepoLoader( sdm.configuration.sdm.projectLoader || new CachingProjectLoader(), p.target.credentials, true, ); const project = await computeStartingPoint( pi.parameters as any, pi.context, repoLoader(pi.parameters as any), { ...(generator as any), redirecter: () => undefined }, generator.startingPoint, generator, toMachineOptions(sdm), ); const transformsToApply = []; for (const transform of transforms) { if (!!transform.test) { if (await transform.test(project)) { transformsToApply.push(transform); } } else { transformsToApply.push(transform); } } await enhanceWithSpecificParameters(transformsToApply, pi as any); // Safe the transformsAndParameters to invoke on the invocation to re-use later (pi as any).parameters.__transforms = transformsToApply; return project; }, transform: async (p, pi) => { const universalTransforms = (pi.parameters as any).__transforms as Array<UniversalTransform<any>>; const computedTransforms = _.flatten(universalTransforms.map(t => toArray(t.transforms))); const trans = chainTransforms(...toArray(generator.transform || []), ...computedTransforms); return trans(p, pi, pi.parameters); }, }; } /** * Enrich parameters with the extras if needed */ async function enhanceWithSpecificParameters<P>( universalTransforms: Array<UniversalTransform<any>>, ctx: CommandListenerInvocation<any>, ): Promise<void> { const unsatisfiedParameters: ParametersObject<any> = {}; for (const universalTransform of universalTransforms) { let params: ParametersObject<any>; if (typeof universalTransform.parameters === "function") { const paramsValues: any = await ctx.promptFor<P>(unsatisfiedParameters); params = await universalTransform.parameters({ ...ctx.parameters, ...paramsValues }); } else { params = universalTransform.parameters; } _.forEach(params, (v, k) => { if (ctx.parameters[k] === undefined) { unsatisfiedParameters[k] = v; } }); } const newParams: any = await ctx.promptFor<P>(unsatisfiedParameters); for (const name of Object.getOwnPropertyNames(newParams)) { ctx.parameters[name] = newParams[name]; } } function chainTransforms<P = NoParameters>(...transforms: Array<CodeTransform<any>>): CodeTransform<P> { return async (p, sdmc, params) => { let cumulativeResult: TransformResult = { target: p, success: true, edited: false, }; try { for (const t of transforms) { const lastResult = await t(p, sdmc, params); cumulativeResult = combineResults(toTransformResult(p, lastResult), cumulativeResult); } return cumulativeResult; } catch (error) { return { target: p, edited: cumulativeResult.edited, success: false, error }; } }; } function toTransformResult(p: Project, tr: TransformReturnable): TransformResult { const maybe = tr as TransformResult; if (maybe && maybe.success !== undefined) { return maybe; } else { return { target: p, success: true, edited: undefined }; } } function combineResults(r1: TransformResult, r2: TransformResult): TransformResult { return { ...r1, ...r2, edited: r1.edited || r2.edited ? true : r1.edited === false && r2.edited === false ? false : undefined, success: r1.success && r2.success, }; }