gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
104 lines • 18.3 kB
JavaScript
import chalk from "chalk";
import assert, { AssertionError } from "assert";
import pMap from "p-map";
export class Executor {
static async runLoop(argv, jobs, stages, potentialStarters) {
let startCandidates = [];
do {
startCandidates = Executor.getStartCandidates(jobs, stages, potentialStarters, argv.manual);
if (startCandidates.length > 0) {
const mapper = async (startCandidate) => startCandidate.start();
await pMap(startCandidates, mapper, { concurrency: argv.concurrency ?? startCandidates.length });
}
} while (startCandidates.length > 0);
}
static getStartCandidates(jobs, stages, potentialStarters, manuals) {
const startCandidates = [];
for (const job of [...new Set(potentialStarters)]) {
if (job.started)
continue;
const jobsToWaitFor = Executor.getPastToWaitFor(jobs, stages, job, manuals);
if (Executor.isNotFinished(jobsToWaitFor)) {
continue;
}
if (job.when === "on_success" && Executor.isPastFailed(jobsToWaitFor)) {
continue;
}
if (job.when === "manual" && Executor.isPastFailed(jobsToWaitFor)) {
continue;
}
if (job.when === "on_failure" && !Executor.isPastFailed(jobsToWaitFor)) {
continue;
}
startCandidates.push(job);
}
return startCandidates;
}
static isPastFailed(jobsToWaitFor) {
const failJobs = jobsToWaitFor.filter(j => {
if (j.allowFailure) {
return false;
}
return (j.preScriptsExitCode ? j.preScriptsExitCode : 0) > 0;
});
return failJobs.length > 0;
}
static isNotFinished(jobsToWaitFor) {
const notFinishedJobs = jobsToWaitFor.filter(j => !j.finished);
return notFinishedJobs.length > 0;
}
static getFailed(jobs) {
return jobs.filter(j => j.finished && !j.allowFailure && (j.preScriptsExitCode ?? 0) > 0);
}
static getPastToWaitFor(jobs, stages, job, manuals) {
const jobsToWaitForSet = new Set();
let waitForLoopArray = [job];
while (waitForLoopArray.length > 0) {
const loopJob = waitForLoopArray.pop();
assert(loopJob != null, "Job not found in getPastToWaitFor, should be impossible!");
if (loopJob.needs) {
const neededToWaitFor = this.getNeededToWaitFor(jobs, manuals, loopJob);
waitForLoopArray.push(...neededToWaitFor);
}
else {
const previousToWaitFor = this.getPreviousToWaitFor(jobs, stages, loopJob);
waitForLoopArray = waitForLoopArray.concat(previousToWaitFor);
waitForLoopArray = waitForLoopArray.filter(j => j.when !== "never");
waitForLoopArray = waitForLoopArray.filter(j => j.when !== "manual" || manuals.includes(j.name));
}
waitForLoopArray.forEach(j => jobsToWaitForSet.add(j));
}
return [...jobsToWaitForSet];
}
static getNeededToWaitFor(jobs, manuals, job) {
const toWaitFor = [];
assert(job.needs != null, chalk `${job.name}.needs cannot be null in getNeededToWaitFor`);
for (const need of job.needs) {
const baseJobs = jobs.filter(j => j.baseName === need.job);
for (const j of baseJobs) {
if (j.when === "never" && !need.optional) {
throw new AssertionError({ message: chalk `{blueBright ${j.name}} is when:never, but its needed by {blueBright ${job.name}}` });
}
if (j.when === "never" && need.optional) {
continue;
}
if (j.when === "manual" && !manuals.includes(j.name)) {
throw new AssertionError({ message: chalk `{blueBright ${j.name}} is when:manual, its needed by {blueBright ${job.name}}, and not specified in --manual` });
}
assert(job.name !== j.name, chalk `This GitLab CI configuration is invalid: The pipeline has circular dependencies: self-dependency: {blueBright ${need.job}}.`);
toWaitFor.push(j);
}
}
return toWaitFor;
}
static getPreviousToWaitFor(jobs, stages, job) {
const previousToWaitFor = [];
const stageIndex = stages.indexOf(job.stage);
const pastStages = stages.slice(0, stageIndex);
pastStages.forEach((pastStage) => {
previousToWaitFor.push(...[...jobs.values()].filter(j => j.stage === pastStage));
});
return previousToWaitFor;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhlY3V0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJleGVjdXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssTUFBTSxPQUFPLENBQUM7QUFFMUIsT0FBTyxNQUFNLEVBQUUsRUFBQyxjQUFjLEVBQUMsTUFBTSxRQUFRLENBQUM7QUFFOUMsT0FBTyxJQUFJLE1BQU0sT0FBTyxDQUFDO0FBRXpCLE1BQU0sT0FBTyxRQUFRO0lBRWpCLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFFLElBQVUsRUFBRSxJQUF3QixFQUFFLE1BQXlCLEVBQUUsaUJBQXdCO1FBQzNHLElBQUksZUFBZSxHQUFHLEVBQUUsQ0FBQztRQUV6QixHQUFHLENBQUM7WUFDQSxlQUFlLEdBQUcsUUFBUSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzVGLElBQUksZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxNQUFNLEdBQUcsS0FBSyxFQUFFLGNBQW1CLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDckUsTUFBTSxJQUFJLENBQUMsZUFBZSxFQUFFLE1BQU0sRUFBRSxFQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVyxJQUFJLGVBQWUsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxDQUFDO1lBQ25HLENBQUM7UUFDTCxDQUFDLFFBQVEsZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7SUFDekMsQ0FBQztJQUVELE1BQU0sQ0FBQyxrQkFBa0IsQ0FBRSxJQUF3QixFQUFFLE1BQXlCLEVBQUUsaUJBQWlDLEVBQUUsT0FBaUI7UUFDaEksTUFBTSxlQUFlLEdBQUcsRUFBRSxDQUFDO1FBRTNCLEtBQUssTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFNLGlCQUFp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QyxLQUFLLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQy9DLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxTQUFTLEVBQUUsRUFBRTtZQUM3QixpQkFBaUIsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQ3JGLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxpQkFBaUIsQ0FBQztJQUM3QixDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQge0pvYn0gZnJvbSBcIi4vam9iLmpzXCI7XG5pbXBvcnQgYXNzZXJ0LCB7QXNzZXJ0aW9uRXJyb3J9IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7QXJndn0gZnJvbSBcIi4vYXJndi5qc1wiO1xuaW1wb3J0IHBNYXAgZnJvbSBcInAtbWFwXCI7XG5cbmV4cG9ydCBjbGFzcyBFeGVjdXRvciB7XG5cbiAgICBzdGF0aWMgYXN5bmMgcnVuTG9vcCAoYXJndjogQXJndiwgam9iczogUmVhZG9ubHlBcnJheTxKb2I+LCBzdGFnZXM6IHJlYWRvbmx5IHN0cmluZ1tdLCBwb3RlbnRpYWxTdGFydGVyczogSm9iW10pIHtcbiAgICAgICAgbGV0IHN0YXJ0Q2FuZGlkYXRlcyA9IFtdO1xuXG4gICAgICAgIGRvIHtcbiAgICAgICAgICAgIHN0YXJ0Q2FuZGlkYXRlcyA9IEV4ZWN1dG9yLmdldFN0YXJ0Q2FuZGlkYXRlcyhqb2JzLCBzdGFnZXMsIHBvdGVudGlhbFN0YXJ0ZXJzLCBhcmd2Lm1hbnVhbCk7XG4gICAgICAgICAgICBpZiAoc3RhcnRDYW5kaWRhdGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBjb25zdCBtYXBwZXIgPSBhc3luYyAoc3RhcnRDYW5kaWRhdGU6IEpvYikgPT4gc3RhcnRDYW5kaWRhdGUuc3RhcnQoKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBwTWFwKHN0YXJ0Q2FuZGlkYXRlcywgbWFwcGVyLCB7Y29uY3VycmVuY3k6IGFyZ3YuY29uY3VycmVuY3kgPz8gc3RhcnRDYW5kaWRhdGVzLmxlbmd0aH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IHdoaWxlIChzdGFydENhbmRpZGF0ZXMubGVuZ3RoID4gMCk7XG4gICAgfVxuXG4gICAgc3RhdGljIGdldFN0YXJ0Q2FuZGlkYXRlcyAoam9iczogUmVhZG9ubHlBcnJheTxKb2I+LCBzdGFnZXM6IHJlYWRvbmx5IHN0cmluZ1tdLCBwb3RlbnRpYWxTdGFydGVyczogcmVhZG9ubHkgSm9iW10sIG1hbnVhbHM6IHN0cmluZ1tdKSB7XG4gICAgICAgIGNvbnN0IHN0YXJ0Q2FuZGlkYXRlcyA9IFtdO1xuXG4gICAgICAgIGZvciAoY29uc3Qgam9iIG9mIFsuLi5uZXcgU2V0PEpvYj4ocG90ZW50aWFsU3RhcnRlcnMpXSkge1xuICAgICAgICAgICAgaWYgKGpvYi5zdGFydGVkKSBjb250aW51ZTtcblxuICAgICAgICAgICAgY29uc3Qgam9ic1RvV2FpdEZvciA9IEV4ZWN1dG9yLmdldFBhc3RUb1dhaXRGb3Ioam9icywgc3RhZ2VzLCBqb2IsIG1hbnVhbHMpO1xuICAgICAgICAgICAgaWYgKEV4ZWN1dG9yLmlzTm90RmluaXNoZWQoam9ic1RvV2FpdEZvcikpIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChqb2Iud2hlbiA9PT0gXCJvbl9zdWNjZXNzXCIgJiYgRXhlY3V0b3IuaXNQYXN0RmFpbGVkKGpvYnNUb1dhaXRGb3IpKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoam9iLndoZW4gPT09IFwibWFudWFsXCIgJiYgRXhlY3V0b3IuaXNQYXN0RmFpbGVkKGpvYnNUb1dhaXRGb3IpKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoam9iLndoZW4gPT09IFwib25fZmFpbHVyZVwiICYmICFFeGVjdXRvci5pc1Bhc3RGYWlsZWQoam9ic1RvV2FpdEZvcikpIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc3RhcnRDYW5kaWRhdGVzLnB1c2goam9iKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3RhcnRDYW5kaWRhdGVzO1xuICAgIH1cblxuICAgIHN0YXRpYyBpc1Bhc3RGYWlsZWQgKGpvYnNUb1dhaXRGb3I6IFJlYWRvbmx5QXJyYXk8Sm9iPikge1xuICAgICAgICBjb25zdCBmYWlsSm9icyA9IGpvYnNUb1dhaXRGb3IuZmlsdGVyKGogPT4ge1xuICAgICAgICAgICAgaWYgKGouYWxsb3dGYWlsdXJlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIChqLnByZVNjcmlwdHNFeGl0Q29kZSA/IGoucHJlU2NyaXB0c0V4aXRDb2RlIDogMCkgPiAwO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGZhaWxKb2JzLmxlbmd0aCA+IDA7XG4gICAgfVxuXG4gICAgc3RhdGljIGlzTm90RmluaXNoZWQgKGpvYnNUb1dhaXRGb3I6IFJlYWRvbmx5QXJyYXk8Sm9iPikge1xuICAgICAgICBjb25zdCBub3RGaW5pc2hlZEpvYnMgPSBqb2JzVG9XYWl0Rm9yLmZpbHRlcihqID0+ICFqLmZpbmlzaGVkKTtcbiAgICAgICAgcmV0dXJuIG5vdEZpbmlzaGVkSm9icy5sZW5ndGggPiAwO1xuICAgIH1cblxuICAgIHN0YXRpYyBnZXRGYWlsZWQgKGpvYnM6IFJlYWRvbmx5QXJyYXk8Sm9iPikge1xuICAgICAgICByZXR1cm4gam9icy5maWx0ZXIoaiA9PiBqLmZpbmlzaGVkICYmICFqLmFsbG93RmFpbHVyZSAmJiAoai5wcmVTY3JpcHRzRXhpdENvZGUgPz8gMCkgPiAwKTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZ2V0UGFzdFRvV2FpdEZvciAoam9iczogUmVhZG9ubHlBcnJheTxKb2I+LCBzdGFnZXM6IHJlYWRvbmx5IHN0cmluZ1tdLCBqb2I6IEpvYiwgbWFudWFsczogc3RyaW5nW10pIHtcbiAgICAgICAgY29uc3Qgam9ic1RvV2FpdEZvclNldCA9IG5ldyBTZXQ8Sm9iPigpO1xuICAgICAgICBsZXQgd2FpdEZvckxvb3BBcnJheTogSm9iW10gPSBbam9iXTtcblxuICAgICAgICB3aGlsZSAod2FpdEZvckxvb3BBcnJheS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBsb29wSm9iID0gd2FpdEZvckxvb3BBcnJheS5wb3AoKTtcbiAgICAgICAgICAgIGFzc2VydChsb29wSm9iICE9IG51bGwsIFwiSm9iIG5vdCBmb3VuZCBpbiBnZXRQYXN0VG9XYWl0Rm9yLCBzaG91bGQgYmUgaW1wb3NzaWJsZSFcIik7XG4gICAgICAgICAgICBpZiAobG9vcEpvYi5uZWVkcykge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5lZWRlZFRvV2FpdEZvciA9IHRoaXMuZ2V0TmVlZGVkVG9XYWl0Rm9yKGpvYnMsIG1hbnVhbHMsIGxvb3BKb2IpO1xuICAgICAgICAgICAgICAgIHdhaXRGb3JMb29wQXJyYXkucHVzaCguLi5uZWVkZWRUb1dhaXRGb3IpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwcmV2aW91c1RvV2FpdEZvciA9IHRoaXMuZ2V0UHJldmlvdXNUb1dhaXRGb3Ioam9icywgc3RhZ2VzLCBsb29wSm9iKTtcbiAgICAgICAgICAgICAgICB3YWl0Rm9yTG9vcEFycmF5ID0gd2FpdEZvckxvb3BBcnJheS5jb25jYXQocHJldmlvdXNUb1dhaXRGb3IpO1xuICAgICAgICAgICAgICAgIHdhaXRGb3JMb29wQXJyYXkgPSB3YWl0Rm9yTG9vcEFycmF5LmZpbHRlcihqID0+IGoud2hlbiAhPT0gXCJuZXZlclwiKTtcbiAgICAgICAgICAgICAgICB3YWl0Rm9yTG9vcEFycmF5ID0gd2FpdEZvckxvb3BBcnJheS5maWx0ZXIoaiA9PiBqLndoZW4gIT09IFwibWFudWFsXCIgfHwgbWFudWFscy5pbmNsdWRlcyhqLm5hbWUpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHdhaXRGb3JMb29wQXJyYXkuZm9yRWFjaChqID0+IGpvYnNUb1dhaXRGb3JTZXQuYWRkKGopKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gWy4uLmpvYnNUb1dhaXRGb3JTZXRdO1xuICAgIH1cblxuICAgIHN0YXRpYyBnZXROZWVkZWRUb1dhaXRGb3IgKGpvYnM6IFJlYWRvbmx5QXJyYXk8Sm9iPiwgbWFudWFsczogc3RyaW5nW10sIGpvYjogSm9iKSB7XG4gICAgICAgIGNvbnN0IHRvV2FpdEZvciA9IFtdO1xuICAgICAgICBhc3NlcnQoam9iLm5lZWRzICE9IG51bGwsIGNoYWxrYCR7am9iLm5hbWV9Lm5lZWRzIGNhbm5vdCBiZSBudWxsIGluIGdldE5lZWRlZFRvV2FpdEZvcmApO1xuICAgICAgICBmb3IgKGNvbnN0IG5lZWQgb2Ygam9iLm5lZWRzKSB7XG4gICAgICAgICAgICBjb25zdCBiYXNlSm9icyA9IGpvYnMuZmlsdGVyKGogPT4gai5iYXNlTmFtZSA9PT0gbmVlZC5qb2IpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBqIG9mIGJhc2VKb2JzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGoud2hlbiA9PT0gXCJuZXZlclwiICYmICFuZWVkLm9wdGlvbmFsKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBBc3NlcnRpb25FcnJvcih7bWVzc2FnZTogY2hhbGtge2JsdWVCcmlnaHQgJHtqLm5hbWV9fSBpcyB3aGVuOm5ldmVyLCBidXQgaXRzIG5lZWRlZCBieSB7Ymx1ZUJyaWdodCAke2pvYi5uYW1lfX1gfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChqLndoZW4gPT09IFwibmV2ZXJcIiAmJiBuZWVkLm9wdGlvbmFsKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoai53aGVuID09PSBcIm1hbnVhbFwiICYmICFtYW51YWxzLmluY2x1ZGVzKGoubmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEFzc2VydGlvbkVycm9yKHttZXNzYWdlOiBjaGFsa2B7Ymx1ZUJyaWdodCAke2oubmFtZX19IGlzIHdoZW46bWFudWFsLCBpdHMgbmVlZGVkIGJ5IHtibHVlQnJpZ2h0ICR7am9iLm5hbWV9fSwgYW5kIG5vdCBzcGVjaWZpZWQgaW4gLS1tYW51YWxgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGFzc2VydChqb2IubmFtZSAhPT0gai5uYW1lLCBjaGFsa2BUaGlzIEdpdExhYiBDSSBjb25maWd1cmF0aW9uIGlzIGludmFsaWQ6IFRoZSBwaXBlbGluZSBoYXMgY2lyY3VsYXIgZGVwZW5kZW5jaWVzOiBzZWxmLWRlcGVuZGVuY3k6IHtibHVlQnJpZ2h0ICR7bmVlZC5qb2J9fS5gKTtcbiAgICAgICAgICAgICAgICB0b1dhaXRGb3IucHVzaChqKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdG9XYWl0Rm9yO1xuICAgIH1cblxuICAgIHN0YXRpYyBnZXRQcmV2aW91c1RvV2FpdEZvciAoam9iczogUmVhZG9ubHlBcnJheTxKb2I+LCBzdGFnZXM6IHJlYWRvbmx5IHN0cmluZ1tdLCBqb2I6IEpvYikge1xuICAgICAgICBjb25zdCBwcmV2aW91c1RvV2FpdEZvcjogSm9iW10gPSBbXTtcbiAgICAgICAgY29uc3Qgc3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGpvYi5zdGFnZSk7XG4gICAgICAgIGNvbnN0IHBhc3RTdGFnZXMgPSBzdGFnZXMuc2xpY2UoMCwgc3RhZ2VJbmRleCk7XG4gICAgICAgIHBhc3RTdGFnZXMuZm9yRWFjaCgocGFzdFN0YWdlKSA9PiB7XG4gICAgICAgICAgICBwcmV2aW91c1RvV2FpdEZvci5wdXNoKC4uLlsuLi5qb2JzLnZhbHVlcygpXS5maWx0ZXIoaiA9PiBqLnN0YWdlID09PSBwYXN0U3RhZ2UpKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBwcmV2aW91c1RvV2FpdEZvcjtcbiAgICB9XG59XG4iXX0=