@atomist/sdm
Version:
Atomist Software Delivery Machine SDK
116 lines (104 loc) • 3.92 kB
text/typescript
/*
* 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.
*/
import {
goals,
Goals,
} from "../goal/Goals";
import { PushListenerInvocation } from "../listener/PushListener";
import { wrapPredicateMapping } from "../mapping/goalTest";
import { PushTest } from "../mapping/PushTest";
import { AnyPush } from "../mapping/support/commonPushTests";
import {
PredicateMappingTerm,
toPredicateMapping,
} from "../mapping/support/PredicateMappingTerm";
import { PushRule } from "../mapping/support/PushRule";
import {
GoalComponent,
toGoals,
} from "./GoalComponent";
/**
* PushRule implementation exposed in DSL. Continues fluent API.
*/
export class GoalSetterMapping<P extends PushListenerInvocation = PushListenerInvocation> extends PushRule<Goals> {
private goalsName: string;
public get label(): string {
return this.goalsName;
}
constructor(guard1: PushTest, guards: PushTest[], reason?: string) {
super(wrapPredicateMapping(guard1), (guards || []).map(wrapPredicateMapping), reason);
}
public setGoals(goalComponent: GoalComponent): this {
if (!!goalComponent && (goalComponent as Goals).name) {
this.goalsName = (goalComponent as Goals).name;
}
if (!goalComponent) {
return this.set(goalComponent as Goals);
}
return this.set(toGoals(goalComponent));
}
/**
* Set goals dynamically, depending on this push
* @param {(inv: P) => GoalComponent} f
* @return {this}
*/
public setGoalsWhen(f: (inv: P) => GoalComponent | Promise<GoalComponent>): this {
// This is a bit devious. We override the parent mapping
this.mapping = async (pu: P) => {
// Check whether the enclosing test would have let the push through
const shouldEvaluate = await this.pushTest.mapping(pu);
if (!shouldEvaluate) {
return undefined;
}
const goalComponent = await f(pu);
if (!!goalComponent && (goalComponent as Goals).name) {
this.goalsName = (goalComponent as Goals).name;
}
if (!goalComponent) {
return goalComponent as Goals;
}
return toGoals(goalComponent);
};
return this;
}
/**
* Prevent setting any further goals on this push. Ordering matters:
* goals may previously have been set.
* @param name name of the empty Goals. Default is "No Goals"
*/
public setNoMoreGoals(name?: string): void {
this.setGoals(goals(name || "No Goals").andLock());
}
}
/**
* Simple GoalSetter DSL. Allows use of booleans and functions
* returning boolean in predicate expressions
* @param {PushTest} guard1
* @param {PushTest} guards
*/
export function whenPushSatisfies<P extends PushListenerInvocation = PushListenerInvocation>(
guard1: PredicateMappingTerm<P>,
...guards: Array<PredicateMappingTerm<P>>): GoalSetterMapping<P> {
return new GoalSetterMapping<P>(
toPredicateMapping(guard1), guards.map(toPredicateMapping));
}
/**
* PushRule that matches every push
* @type {GoalSetterMapping}
*/
export function onAnyPush<P extends PushListenerInvocation = PushListenerInvocation>(): GoalSetterMapping<P> {
return new GoalSetterMapping<P>(AnyPush, [], "On any push");
}