UNPKG

gitlab-ci-local

Version:

Tired of pushing to test your .gitlab-ci.yml?

151 lines (150 loc) 26.1 kB
import Ajv from "ajv"; import assert from "assert"; import chalk from "chalk"; import schema from "./schema/index.js"; import { betterAjvErrors } from "./schema-error.js"; import terminalLink from "terminal-link"; const MAX_ERRORS = 5; export class Validator { static jsonSchemaValidation({ pathToExpandedGitLabCi, gitLabCiConfig, argv }) { const ajv = new Ajv({ verbose: true, allErrors: true, allowUnionTypes: true, validateFormats: false, strictTypes: false, // to suppress the missing types defined in the gitlab-ci json schema keywords: ["markdownDescription"], }); const validate = ajv.compile(schema); const valid = validate(gitLabCiConfig); if (valid) return; const betterErrors = betterAjvErrors({ data: gitLabCiConfig, errors: validate.errors, }).filter(betterError => !argv.ignoreSchemaPaths.includes(betterError.schemaPath)); let e = ""; for (let i = 0, len = betterErrors.length; i < len; i++) { if (i + 1 > MAX_ERRORS) { e += `\t... and ${len - MAX_ERRORS} more`; break; } e += chalk `\t• {redBright ${betterErrors[i].message}} at {blueBright ${betterErrors[i].path}} {grey [${betterErrors[i].schemaPath}]}\n`; } assert(valid || betterErrors.length == 0, chalk ` {reset Invalid .gitlab-ci.yml configuration! ${e.trimEnd()} For further troubleshooting, consider either of the following: \t• Copy the content of {blueBright ${terminalLink(".gitlab-ci-local/expanded-gitlab-ci.yml", pathToExpandedGitLabCi)}} to the ${terminalLink("pipeline editor", "https://docs.gitlab.com/ee/ci/pipeline_editor/")} to debug it \t• Use --ignore-schema-paths= "#/definitions/tags/minItems" --ignore-schema-paths "#/additionalProperties" to partially disable certain validation rule \t• Use --json-schema-validation=false to disable schema validation (not recommended)} `); } static needs(jobs, stages) { const warnings = []; for (const job of jobs) { if (job.needs === null || job.needs.length === 0) continue; for (const [i, need] of job.needs.entries()) { if (need.pipeline) { warnings.push(`${job.name}.needs[${i}].job:${need.job} ignored, pipeline key not supported`); continue; } if (need.project) { warnings.push(`${job.name}.needs[${i}] ignored, project key not supported`); continue; } const needJob = jobs.find(j => j.baseName === need.job); if (need.optional && !needJob) continue; assert(needJob != null, chalk `needs: [{blueBright ${need.job}}] for {blueBright ${job.baseName}} could not be found`); const needJobStageIndex = stages.indexOf(needJob.stage); const jobStageIndex = stages.indexOf(job.stage); assert(needJobStageIndex <= jobStageIndex, chalk `needs: [{blueBright ${needJob.name}}] for {blueBright ${job.name}} is in a future stage`); } } return warnings; } static dependencies(jobs, stages) { for (const job of jobs) { if (job.dependencies === null || job.dependencies.length === 0) continue; const undefDeps = job.dependencies.filter((j) => !jobs.some(n => n.baseName === j)); assert(undefDeps.length !== job.dependencies.length, chalk `dependencies: [{blueBright ${undefDeps.join(",")}}] for {blueBright ${job.name}} cannot be found`); for (const dep of job.dependencies) { const depJob = jobs.find(j => j.baseName === dep); assert(depJob != null, chalk `dependencies: [{blueBright ${dep}}] for {blueBright ${job.baseName}} could not be found`); const depJobStageIndex = stages.indexOf(depJob.stage); const jobStageIndex = stages.indexOf(job.stage); assert(depJobStageIndex <= jobStageIndex, chalk `dependencies: [{blueBright ${depJob.name}}] for {blueBright ${job.name}} is in a future stage`); } } } static dependenciesContainment(jobs) { for (const job of jobs) { const needs = job.needs; const dependencies = job.dependencies; if (needs && needs.length === 0) continue; if (!dependencies || !needs) continue; const everyIncluded = dependencies.every((dep) => { return needs.some(n => n.job === dep); }); const assertMsg = `${job.formattedJobName} needs: '${needs.map(n => n.job).join(",")}' doesn't fully contain dependencies: '${dependencies.join(",")}'`; assert(everyIncluded, assertMsg); } } /** * These jobs named are reserved keywords in GitLab CI but does not prevent the pipeline from running * https://github.com/firecow/gitlab-ci-local/issues/1263 * @param jobsNames * @private */ static potentialIllegalJobName(jobsNames) { const warnings = []; for (const jobName of jobsNames) { if (new Set(["types", "true", "false", "nil"]).has(jobName)) { warnings.push(`Job name "${jobName}" is a reserved keyword. (https://docs.gitlab.com/ee/ci/jobs/#job-name-limitations)`); } } return warnings; } static scriptBlank(jobs) { for (const job of jobs) { if (job.trigger) continue; // Jobs with trigger are allowed to have empty script assert(job.scripts.length > 0, chalk `{blue ${job.name}} has empty script`); } } static arrayOfStrings(jobs) { for (const job of jobs) { if (job.trigger) continue; job.beforeScripts.forEach((s) => assert(typeof s === "string", chalk `{blue ${job.name}} before_script contains non string value`)); job.afterScripts.forEach((s) => assert(typeof s === "string", chalk `{blue ${job.name}} after_script contains non string value`)); job.scripts.forEach((s) => assert(typeof s === "string", chalk `{blue ${job.name}} script contains non string value`)); } } static async run(jobs, stages) { const warnings = []; this.scriptBlank(jobs); this.arrayOfStrings(jobs); warnings.push(...this.needs(jobs, stages)); this.dependencies(jobs, stages); this.dependenciesContainment(jobs); warnings.push(...this.potentialIllegalJobName(jobs.map(j => j.baseName))); warnings.push(...this.artifacts(jobs)); return warnings; } static artifacts(jobs) { const warnings = []; for (const job of jobs) { if (job.artifacts === null) { warnings.push(`${job.name}.artifacts is null, ignoring.`); } } return warnings; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sR0FBRyxNQUFNLEtBQUssQ0FBQztBQUV0QixPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sTUFBTSxNQUFNLG1CQUFtQixDQUFDO0FBQ3ZDLE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUNsRCxPQUFPLFlBQVksTUFBTSxlQUFlLENBQUM7QUFHekMsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFDO0FBRXJCLE1BQU0sT0FBTyxTQUFTO0lBQ2xCLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBRSxFQUFDLHNCQUFzQixFQUFFLGNBQWMsRUFBRSxJQUFJLEVBSXpFO1FBQ0csTUFBTSxHQUFHLEdBQUcsSUFBSSxHQUFHLENBQUM7WUFDaEIsT0FBTyxFQUFFLElBQUk7WUFDYixTQUFTLEVBQUUsSUFBSTtZQUNmLGVBQWUsRUFBRSxJQUFJO1lBQ3JCLGVBQWUsRUFBRSxLQUFLO1lBQ3RCLFdBQVcsRUFBRSxLQUFLLEVBQUUscUVBQXFFO1lBQ3pGLFFBQVEsRUFBRSxDQUFDLHFCQUFxQixDQUFDO1NBQ3BDLENBQUMsQ0FBQztRQUNILE1BQU0sUUFBUSxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDckMsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ3ZDLElBQUksS0FBSztZQUFFLE9BQU87UUFDbEIsTUFBTSxZQUFZLEdBQUcsZUFBZSxDQUFDO1lBQ2pDLElBQUksRUFBRSxjQUFjO1lBQ3BCLE1BQU0sRUFBRSxRQUFRLENBQUMsTUFBTTtTQUMxQixDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMs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QztZQUM5RCxDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ3BCLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBBanYgZnJvbSBcImFqdlwiO1xuaW1wb3J0IHtKb2J9IGZyb20gXCIuL2pvYi5qc1wiO1xuaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgY2hhbGsgZnJvbSBcImNoYWxrXCI7XG5pbXBvcnQgc2NoZW1hIGZyb20gXCIuL3NjaGVtYS9pbmRleC5qc1wiO1xuaW1wb3J0IHtiZXR0ZXJBanZFcnJvcnN9IGZyb20gXCIuL3NjaGVtYS1lcnJvci5qc1wiO1xuaW1wb3J0IHRlcm1pbmFsTGluayBmcm9tIFwidGVybWluYWwtbGlua1wiO1xuaW1wb3J0IHtBcmd2fSBmcm9tIFwiLi9hcmd2LmpzXCI7XG5cbmNvbnN0IE1BWF9FUlJPUlMgPSA1O1xuXG5leHBvcnQgY2xhc3MgVmFsaWRhdG9yIHtcbiAgICBzdGF0aWMganNvblNjaGVtYVZhbGlkYXRpb24gKHtwYXRoVG9FeHBhbmRlZEdpdExhYkNpLCBnaXRMYWJDaUNvbmZpZywgYXJndn06IHtcbiAgICAgICAgcGF0aFRvRXhwYW5kZWRHaXRMYWJDaTogc3RyaW5nO1xuICAgICAgICBnaXRMYWJDaUNvbmZpZzogb2JqZWN0O1xuICAgICAgICBhcmd2OiBBcmd2O1xuICAgIH0pIHtcbiAgICAgICAgY29uc3QgYWp2ID0gbmV3IEFqdih7XG4gICAgICAgICAgICB2ZXJib3NlOiB0cnVlLFxuICAgICAgICAgICAgYWxsRXJyb3JzOiB0cnVlLFxuICAgICAgICAgICAgYWxsb3dVbmlvblR5cGVzOiB0cnVlLFxuICAgICAgICAgICAgdmFsaWRhdGVGb3JtYXRzOiBmYWxzZSxcbiAgICAgICAgICAgIHN0cmljdFR5cGVzOiBmYWxzZSwgLy8gdG8gc3VwcHJlc3MgdGhlIG1pc3NpbmcgdHlwZXMgZGVmaW5lZCBpbiB0aGUgZ2l0bGFiLWNpIGpzb24gc2NoZW1hXG4gICAgICAgICAgICBrZXl3b3JkczogW1wibWFya2Rvd25EZXNjcmlwdGlvblwiXSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHZhbGlkYXRlID0gYWp2LmNvbXBpbGUoc2NoZW1hKTtcbiAgICAgICAgY29uc3QgdmFsaWQgPSB2YWxpZGF0ZShnaXRMYWJDaUNvbmZpZyk7XG4gICAgICAgIGlmICh2YWxpZCkgcmV0dXJuO1xuICAgICAgICBjb25zdCBiZXR0ZXJFcnJvcnMgPSBiZXR0ZXJBanZFcnJvcnMoe1xuICAgICAgICAgICAgZGF0YTogZ2l0TGFiQ2lDb25maWcsXG4gICAgICAgICAgICBlcnJvcnM6IHZhbGlkYXRlLmVycm9ycyxcbiAgICAgICAgfSkuZmlsdGVyKGJldHRlckVycm9yID0+ICFhcmd2Lmlnbm9yZVNjaGVtYVBhdGhzLmluY2x1ZGVzKGJldHRlckVycm9yLnNjaGVtYVBhdGgpKTtcblxuICAgICAgICBsZXQgZTogc3RyaW5nID0gXCJcIjtcbiAgICAgICAgZm9yIChsZXQgaSA9IDAsIGxlbiA9IGJldHRlckVycm9ycy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgICAgICAgaWYgKGkgKyAxID4gTUFYX0VSUk9SUykge1xuICAgICAgICAgICAgICAgIGUgKz0gYFxcdC4uLiBhbmQgJHtsZW4gLSBNQVhfRVJST1JTfSBtb3JlYDtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGUgKz0gY2hhbGtgXFx04oCiIHtyZWRCcmlnaHQgJHtiZXR0ZXJFcnJvcnNbaV0ubWVzc2FnZX19IGF0IHtibHVlQnJpZ2h0ICR7YmV0dGVyRXJyb3JzW2ldLnBhdGh9fSB7Z3JleSBbJHtiZXR0ZXJFcnJvcnNbaV0uc2NoZW1hUGF0aH1dfVxcbmA7XG4gICAgICAgIH1cblxuICAgICAgICBhc3NlcnQodmFsaWQgfHwgYmV0dGVyRXJyb3JzLmxlbmd0aCA9PSAwLCBjaGFsa2BcbntyZXNldCBJbnZhbGlkIC5naXRsYWItY2kueW1sIGNvbmZpZ3VyYXRpb24hXG4ke2UudHJpbUVuZCgpfVxuXG5Gb3IgZnVydGhlciB0cm91Ymxlc2hvb3RpbmcsIGNvbnNpZGVyIGVpdGhlciBvZiB0aGUgZm9sbG93aW5nOlxuXFx04oCiIENvcHkgdGhlIGNvbnRlbnQgb2Yge2JsdWVCcmlnaHQgJHt0ZXJtaW5hbExpbmsoXCIuZ2l0bGFiLWNpLWxvY2FsL2V4cGFuZGVkLWdpdGxhYi1jaS55bWxcIiwgcGF0aFRvRXhwYW5kZWRHaXRMYWJDaSl9fSB0byB0aGUgJHt0ZXJtaW5hbExpbmsoXCJwaXBlbGluZSBlZGl0b3JcIiwgXCJodHRwczovL2RvY3MuZ2l0bGFiLmNvbS9lZS9jaS9waXBlbGluZV9lZGl0b3IvXCIpfSB0byBkZWJ1ZyBpdFxuXFx04oCiIFVzZSAtLWlnbm9yZS1zY2hlbWEtcGF0aHM9IFwiIy9kZWZpbml0aW9ucy90YWdzL21pbkl0ZW1zXCIgLS1pZ25vcmUtc2NoZW1hLXBhdGhzIFwiIy9hZGRpdGlvbmFsUHJvcGVydGllc1wiIHRvIHBhcnRpYWxseSBkaXNhYmxlIGNlcnRhaW4gdmFsaWRhdGlvbiBydWxlXG5cXHTigKIgVXNlIC0tanNvbi1zY2hlbWEtdmFsaWRhdGlvbj1mYWxzZSB0byBkaXNhYmxlIHNjaGVtYSB2YWxpZGF0aW9uIChub3QgcmVjb21tZW5kZWQpfVxuYCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgbmVlZHMgKGpvYnM6IFJlYWRvbmx5QXJyYXk8Sm9iPiwgc3RhZ2VzOiByZWFkb25seSBzdHJpbmdbXSk6IHN0cmluZ1tdIHtcbiAgICAgICAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGZvciAoY29uc3Qgam9iIG9mIGpvYnMpIHtcbiAgICAgICAgICAgIGlmIChqb2IubmVlZHMgPT09IG51bGwgfHwgam9iLm5lZWRzLmxlbmd0aCA9PT0gMCkgY29udGludWU7XG5cbiAgICAgICAgICAgIGZvciAoY29uc3QgW2ksIG5lZWRdIG9mIGpvYi5uZWVkcy5lbnRyaWVzKCkpIHtcbiAgICAgICAgICAgICAgICBpZiAobmVlZC5waXBlbGluZSkge1xuICAgICAgICAgICAgICAgICAgICB3YXJuaW5ncy5wdXNoKGAke2pvYi5uYW1lfS5uZWVkc1ske2l9XS5qb2I6JHtuZWVkLmpvYn0gaWdub3JlZCwgcGlwZWxpbmUga2V5IG5vdCBzdXBwb3J0ZWRgKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChuZWVkLnByb2plY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgd2FybmluZ3MucHVzaChgJHtqb2IubmFtZX0ubmVlZHNbJHtpfV0gaWdub3JlZCwgcHJvamVjdCBrZXkgbm90IHN1cHBvcnRlZGApO1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY29uc3QgbmVlZEpvYiA9IGpvYnMuZmluZChqID0+IGouYmFzZU5hbWUgPT09IG5lZWQuam9iKTtcbiAgICAgICAgICAgICAgICBpZiAobmVlZC5vcHRpb25hbCAmJiAhbmVlZEpvYikgY29udGludWU7XG4gICAgICAgICAgICAgICAgYXNzZXJ0KG5lZWRKb2IgIT0gbnVsbCwgY2hhbGtgbmVlZHM6IFt7Ymx1ZUJyaWdodCAke25lZWQuam9ifX1dIGZvciB7Ymx1ZUJyaWdodCAke2pvYi5iYXNlTmFtZX19IGNvdWxkIG5vdCBiZSBmb3VuZGApO1xuICAgICAgICAgICAgICAgIGNvbnN0IG5lZWRKb2JTdGFnZUluZGV4ID0gc3RhZ2VzLmluZGV4T2YobmVlZEpvYi5zdGFnZSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgam9iU3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGpvYi5zdGFnZSk7XG4gICAgICAgICAgICAgICAgYXNzZXJ0KG5lZWRKb2JTdGFnZUluZGV4IDw9IGpvYlN0YWdlSW5kZXgsIGNoYWxrYG5lZWRzOiBbe2JsdWVCcmlnaHQgJHtuZWVkSm9iLm5hbWV9fV0gZm9yIHtibHVlQnJpZ2h0ICR7am9iLm5hbWV9fSBpcyBpbiBhIGZ1dHVyZSBzdGFnZWApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHdhcm5pbmdzO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIGRlcGVuZGVuY2llcyAoam9iczogUmVhZG9ubHlBcnJheTxKb2I+LCBzdGFnZXM6IHJlYWRvbmx5IHN0cmluZ1tdKSB7XG4gICAgICAgIGZvciAoY29uc3Qgam9iIG9mIGpvYnMpIHtcbiAgICAgICAgICAgIGlmIChqb2IuZGVwZW5kZW5jaWVzID09PSBudWxsIHx8IGpvYi5kZXBlbmRlbmNpZXMubGVuZ3RoID09PSAwKSBjb250aW51ZTtcblxuICAgICAgICAgICAgY29uc3QgdW5kZWZEZXBzID0gam9iLmRlcGVuZGVuY2llcy5maWx0ZXIoKGopID0+ICFqb2JzLnNvbWUobiA9PiBuLmJhc2VOYW1lID09PSBqKSk7XG4gICAgICAgICAgICBhc3NlcnQodW5kZWZEZXBzLmxlbmd0aCAhPT0gam9iLmRlcGVuZGVuY2llcy5sZW5ndGgsIGNoYWxrYGRlcGVuZGVuY2llczogW3tibHVlQnJpZ2h0ICR7dW5kZWZEZXBzLmpvaW4oXCIsXCIpfX1dIGZvciB7Ymx1ZUJyaWdodCAke2pvYi5uYW1lfX0gY2Fubm90IGJlIGZvdW5kYCk7XG5cbiAgICAgICAgICAgIGZvciAoY29uc3QgZGVwIG9mIGpvYi5kZXBlbmRlbmNpZXMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBkZXBKb2IgPSBqb2JzLmZpbmQoaiA9PiBqLmJhc2VOYW1lID09PSBkZXApO1xuICAgICAgICAgICAgICAgIGFzc2VydChkZXBKb2IgIT0gbnVsbCwgY2hhbGtgZGVwZW5kZW5jaWVzOiBbe2JsdWVCcmlnaHQgJHtkZXB9fV0gZm9yIHtibHVlQnJpZ2h0ICR7am9iLmJhc2VOYW1lfX0gY291bGQgbm90IGJlIGZvdW5kYCk7XG4gICAgICAgICAgICAgICAgY29uc3QgZGVwSm9iU3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGRlcEpvYi5zdGFnZSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgam9iU3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGpvYi5zdGFnZSk7XG4gICAgICAgICAgICAgICAgYXNzZXJ0KGRlcEpvYlN0YWdlSW5kZXggPD0gam9iU3RhZ2VJbmRleCwgY2hhbGtgZGVwZW5kZW5jaWVzOiBbe2JsdWVCcmlnaHQgJHtkZXBKb2IubmFtZX19XSBmb3Ige2JsdWVCcmlnaHQgJHtqb2IubmFtZX19IGlzIGluIGEgZnV0dXJlIHN0YWdlYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBkZXBlbmRlbmNpZXNDb250YWlubWVudCAoam9iczogUmVhZG9ubHlBcnJheTxKb2I+KSB7XG4gICAgICAgIGZvciAoY29uc3Qgam9iIG9mIGpvYnMpIHtcbiAgICAgICAgICAgIGNvbnN0IG5lZWRzID0gam9iLm5lZWRzO1xuICAgICAgICAgICAgY29uc3QgZGVwZW5kZW5jaWVzID0gam9iLmRlcGVuZGVuY2llcztcbiAgICAgICAgICAgIGlmIChuZWVkcyAmJiBuZWVkcy5sZW5ndGggPT09IDApIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKCFkZXBlbmRlbmNpZXMgfHwgIW5lZWRzKSBjb250aW51ZTtcblxuXG4gICAgICAgICAgICBjb25zdCBldmVyeUluY2x1ZGVkID0gZGVwZW5kZW5jaWVzLmV2ZXJ5KChkZXA6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZWVkcy5zb21lKG4gPT4gbi5qb2IgPT09IGRlcCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnN0IGFzc2VydE1zZyA9IGAke2pvYi5mb3JtYXR0ZWRKb2JOYW1lfSBuZWVkczogJyR7bmVlZHMubWFwKG4gPT4gbi5qb2IpLmpvaW4oXCIsXCIpfScgZG9lc24ndCBmdWxseSBjb250YWluIGRlcGVuZGVuY2llczogJyR7ZGVwZW5kZW5jaWVzLmpvaW4oXCIsXCIpfSdgO1xuICAgICAgICAgICAgYXNzZXJ0KGV2ZXJ5SW5jbHVkZWQsIGFzc2VydE1zZyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGVzZSBqb2JzIG5hbWVkIGFyZSByZXNlcnZlZCBrZXl3b3JkcyBpbiBHaXRMYWIgQ0kgYnV0IGRvZXMgbm90IHByZXZlbnQgdGhlIHBpcGVsaW5lIGZyb20gcnVubmluZ1xuICAgICAqIGh0dHBzOi8vZ2l0aHViLmNvbS9maXJlY293L2dpdGxhYi1jaS1sb2NhbC9pc3N1ZXMvMTI2M1xuICAgICAqIEBwYXJhbSBqb2JzTmFtZXNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgc3RhdGljIHBvdGVudGlhbElsbGVnYWxKb2JOYW1lIChqb2JzTmFtZXM6IHN0cmluZ1tdKSB7XG4gICAgICAgIGNvbnN0IHdhcm5pbmdzID0gW107XG4gICAgICAgIGZvciAoY29uc3Qgam9iTmFtZSBvZiBqb2JzTmFtZXMpIHtcbiAgICAgICAgICAgIGlmIChuZXcgU2V0KFtcInR5cGVzXCIsIFwidHJ1ZVwiLCBcImZhbHNlXCIsIFwibmlsXCJdKS5oYXMoam9iTmFtZSkpIHtcbiAgICAgICAgICAgICAgICB3YXJuaW5ncy5wdXNoKGBKb2IgbmFtZSBcIiR7am9iTmFtZX1cIiBpcyBhIHJlc2VydmVkIGtleXdvcmQuIChodHRwczovL2RvY3MuZ2l0bGFiLmNvbS9lZS9jaS9qb2JzLyNqb2ItbmFtZS1saW1pdGF0aW9ucylgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gd2FybmluZ3M7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgc2NyaXB0QmxhbmsgKGpvYnM6IFJlYWRvbmx5QXJyYXk8Sm9iPikge1xuICAgICAgICBmb3IgKGNvbnN0IGpvYiBvZiBqb2JzKSB7XG4gICAgICAgICAgICBpZiAoam9iLnRyaWdnZXIpIGNvbnRpbnVlOyAvLyBKb2JzIHdpdGggdHJpZ2dlciBhcmUgYWxsb3dlZCB0byBoYXZlIGVtcHR5IHNjcmlwdFxuICAgICAgICAgICAgYXNzZXJ0KGpvYi5zY3JpcHRzLmxlbmd0aCA+IDAsIGNoYWxrYHtibHVlICR7am9iLm5hbWV9fSBoYXMgZW1wdHkgc2NyaXB0YCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBhcnJheU9mU3RyaW5ncyAoam9iczogUmVhZG9ubHlBcnJheTxKb2I+KSB7XG4gICAgICAgIGZvciAoY29uc3Qgam9iIG9mIGpvYnMpIHtcbiAgICAgICAgICAgIGlmIChqb2IudHJpZ2dlcikgY29udGludWU7XG4gICAgICAgICAgICBqb2IuYmVmb3JlU2NyaXB0cy5mb3JFYWNoKChzOiBhbnkpID0+IGFzc2VydCh0eXBlb2YgcyA9PT0gXCJzdHJpbmdcIiwgY2hhbGtge2JsdWUgJHtqb2IubmFtZX19IGJlZm9yZV9zY3JpcHQgY29udGFpbnMgbm9uIHN0cmluZyB2YWx1ZWApKTtcbiAgICAgICAgICAgIGpvYi5hZnRlclNjcmlwdHMuZm9yRWFjaCgoczogYW55KSA9PiBhc3NlcnQodHlwZW9mIHMgPT09IFwic3RyaW5nXCIsIGNoYWxrYHtibHVlICR7am9iLm5hbWV9fSBhZnRlcl9zY3JpcHQgY29udGFpbnMgbm9uIHN0cmluZyB2YWx1ZWApKTtcbiAgICAgICAgICAgIGpvYi5zY3JpcHRzLmZvckVhY2goKHM6IGFueSkgPT4gYXNzZXJ0KHR5cGVvZiBzID09PSBcInN0cmluZ1wiLCBjaGFsa2B7Ymx1ZSAke2pvYi5uYW1lfX0gc2NyaXB0IGNvbnRhaW5zIG5vbiBzdHJpbmcgdmFsdWVgKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzdGF0aWMgYXN5bmMgcnVuIChqb2JzOiBSZWFkb25seUFycmF5PEpvYj4sIHN0YWdlczogcmVhZG9ubHkgc3RyaW5nW10pIHtcbiAgICAgICAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW107XG4gICAgICAgIHRoaXMuc2NyaXB0Qmxhbmsoam9icyk7XG4gICAgICAgIHRoaXMuYXJyYXlPZlN0cmluZ3Moam9icyk7XG4gICAgICAgIHdhcm5pbmdzLnB1c2goLi4udGhpcy5uZWVkcyhqb2JzLCBzdGFnZXMpKTtcbiAgICAgICAgdGhpcy5kZXBlbmRlbmNpZXMoam9icywgc3RhZ2VzKTtcbiAgICAgICAgdGhpcy5kZXBlbmRlbmNpZXNDb250YWlubWVudChqb2JzKTtcbiAgICAgICAgd2FybmluZ3MucHVzaCguLi50aGlzLnBvdGVudGlhbElsbGVnYWxKb2JOYW1lKGpvYnMubWFwKGogPT4gai5iYXNlTmFtZSkpKTtcbiAgICAgICAgd2FybmluZ3MucHVzaCguLi50aGlzLmFydGlmYWN0cyhqb2JzKSk7XG4gICAgICAgIHJldHVybiB3YXJuaW5ncztcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBhcnRpZmFjdHMgKGpvYnM6IFJlYWRvbmx5QXJyYXk8Sm9iPikge1xuICAgICAgICBjb25zdCB3YXJuaW5nczogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgZm9yIChjb25zdCBqb2Igb2Ygam9icykge1xuICAgICAgICAgICAgaWYgKGpvYi5hcnRpZmFjdHMgPT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICB3YXJuaW5ncy5wdXNoKGAke2pvYi5uYW1lfS5hcnRpZmFjdHMgaXMgbnVsbCwgaWdub3JpbmcuYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHdhcm5pbmdzO1xuICAgIH1cbn1cbiJdfQ==