opinionated-ci-pipeline
Version:
CI/CD on AWS with feature-branch builds, developer-environment deployments, and build status notifications.
135 lines • 22.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FeatureBranchBuilds = void 0;
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_codebuild_1 = require("aws-cdk-lib/aws-codebuild");
const targets = require("aws-cdk-lib/aws-events-targets");
const constructs_1 = require("constructs");
const customNodejsFunction_1 = require("./customNodejsFunction");
const path = require("path");
const notificationsTopic_1 = require("./notificationsTopic");
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
const context_1 = require("../util/context");
const checkout_1 = require("../util/checkout");
class FeatureBranchBuilds extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
const deployProject = this.createDeployProject(props.sourceBucket, props.codeBuild, props.commands);
this.createDeployNotifications(deployProject, props.repository, props.repositoryTokenParam);
this.failuresTopic = this.createBuildFailuresTopic(deployProject);
this.createDestroyProject(props.sourceBucket, props.codeBuild, props.commands);
}
createDeployProject(sourceBucket, codeBuild, commands) {
const deployProject = new aws_codebuild_1.Project(this, 'DeployProject', {
projectName: `${aws_cdk_lib_1.Stack.of(this).stackName}-featureBranch-deploy`,
source: aws_codebuild_1.Source.s3({
bucket: sourceBucket,
path: 'repository-file-placeholder-to-override.zip',
}),
...codeBuild,
environment: codeBuild.buildEnvironment,
buildSpec: aws_codebuild_1.BuildSpec.fromObject({
version: '0.2',
phases: {
install: {
commands: [
...checkout_1.checkoutCommands,
'git checkout ${BRANCH_NAME}',
'ENV_NAME=$(echo ${BRANCH_NAME} | awk \'{ gsub("/", "-", $0); print tolower($0); }\')',
...(commands.preInstall || []),
...(commands.install || []),
],
},
build: {
commands: [
...(commands.buildAndTest || []),
...(commands.preDeployEnvironment || []),
...commands.deployEnvironment,
...(commands.postDeployEnvironment || []),
],
},
},
}),
});
codeBuild.rolePolicy?.forEach(policy => deployProject.addToRolePolicy(policy));
sourceBucket.grantRead(deployProject);
this.grantAssumeCDKRoles(deployProject);
return deployProject;
}
createDeployNotifications(deployProject, repository, repoTokenParam) {
const deployStatusFunction = new customNodejsFunction_1.CustomNodejsFunction(this, 'DeployStatus', {
code: aws_lambda_1.Code.fromAsset(path.join(__dirname, '..', 'lambda', 'featureBranchDeployStatus')),
environment: {
REPOSITORY_HOST: repository.host,
REPOSITORY_NAME: repository.name,
REPOSITORY_TOKEN_PARAM_NAME: repoTokenParam.parameterName,
},
});
repoTokenParam.grantRead(deployStatusFunction);
deployProject.onStateChange('OnDeployStateChange', {
target: new targets.LambdaFunction(deployStatusFunction),
});
}
createBuildFailuresTopic(deployProject) {
const failuresTopic = new notificationsTopic_1.NotificationsTopic(this, 'FeatureBranchBuildFailuresTopic', {
projectName: (0, context_1.getProjectName)(this),
notificationName: 'featureBranchBuildFailures',
});
deployProject.notifyOnBuildFailed('NotifyOnFeatureBuildFailure', failuresTopic.topic, {
notificationRuleName: `${aws_cdk_lib_1.Stack.of(this).stackName}-featureBuildFailure`, // ensure unique name
});
return failuresTopic.topic;
}
createDestroyProject(sourceBucket, codeBuild, commands) {
const destroyProject = new aws_codebuild_1.Project(this, 'DestroyProject', {
projectName: `${aws_cdk_lib_1.Stack.of(this).stackName}-featureBranch-destroy`,
source: aws_codebuild_1.Source.s3({
bucket: sourceBucket,
path: 'repository-file-placeholder-to-override.zip',
}),
...codeBuild,
environment: codeBuild.buildEnvironment,
buildSpec: aws_codebuild_1.BuildSpec.fromObject({
version: '0.2',
phases: {
install: {
commands: [
...checkout_1.checkoutCommands,
'ENV_NAME=$(echo ${BRANCH_NAME} | awk \'{ gsub("/", "-", $0); print tolower($0); }\')',
...(commands.preInstall || []),
...(commands.install || []),
],
},
build: {
commands: [
...(commands.preDestroyEnvironment || []),
...commands.destroyEnvironment,
...(commands.postDestroyEnvironment || []),
'aws s3 rm s3://${CODEBUILD_SOURCE_REPO_URL}',
],
},
},
}),
});
codeBuild.rolePolicy?.forEach(policy => destroyProject.addToRolePolicy(policy));
sourceBucket.grantRead(destroyProject);
sourceBucket.grantDelete(destroyProject);
this.grantAssumeCDKRoles(destroyProject);
return destroyProject;
}
grantAssumeCDKRoles(project) {
const qualifier = aws_cdk_lib_1.Stack.of(this).synthesizer.bootstrapQualifier || 'hnb659fds';
project.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: ['sts:AssumeRole'],
resources: [
`arn:aws:iam::${aws_cdk_lib_1.Aws.ACCOUNT_ID}:role/cdk-${qualifier}-deploy-role-${aws_cdk_lib_1.Aws.ACCOUNT_ID}-${aws_cdk_lib_1.Aws.REGION}`,
`arn:aws:iam::${aws_cdk_lib_1.Aws.ACCOUNT_ID}:role/cdk-${qualifier}-file-publishing-role-${aws_cdk_lib_1.Aws.ACCOUNT_ID}-${aws_cdk_lib_1.Aws.REGION}`,
`arn:aws:iam::${aws_cdk_lib_1.Aws.ACCOUNT_ID}:role/cdk-${qualifier}-image-publishing-role-${aws_cdk_lib_1.Aws.ACCOUNT_ID}-${aws_cdk_lib_1.Aws.REGION}`,
`arn:aws:iam::${aws_cdk_lib_1.Aws.ACCOUNT_ID}:role/cdk-${qualifier}-lookup-role-${aws_cdk_lib_1.Aws.ACCOUNT_ID}-${aws_cdk_lib_1.Aws.REGION}`,
],
}));
}
}
exports.FeatureBranchBuilds = FeatureBranchBuilds;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmVhdHVyZUJyYW5jaEJ1aWxkcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb25zdHJ1Y3RzL2ZlYXR1cmVCcmFuY2hCdWlsZHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkNBQXVDO0FBQ3ZDLDZEQUFxRTtBQUNyRSwwREFBMEQ7QUFDMUQsMkNBQXFDO0FBQ3JDLGlFQUE0RDtBQUM1RCw2QkFBNkI7QUFDN0IsNkRBQXdEO0FBRXhELGlEQUFvRDtBQUNwRCx1REFBNEM7QUFFNUMsNkNBQStDO0FBRy9DLCtDQUFrRDtBQVNsRCxNQUFhLG1CQUFvQixTQUFRLHNCQUFTO0lBSTlDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBK0I7UUFDckUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQzFDLEtBQUssQ0FBQyxZQUFZLEVBQUUsS0FBSyxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsUUFBUSxDQUN0RCxDQUFDO1FBQ0YsSUFBSSxDQUFDLHlCQUF5QixDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBRTVGLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRWxFLElBQUksQ0FBQyxvQkFBb0IsQ0FDckIsS0FBSyxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxRQUFRLENBQ3RELENBQUM7SUFDTixDQUFDO0lBRU8sbUJBQW1CLENBQ3ZCLFlBQXdCLEVBQ3hCLFNBQWdELEVBQ2hELFFBQThDO1FBRTlDLE1BQU0sYUFBYSxHQUFHLElBQUksdUJBQU8sQ0FBQyxJQUFJLEVBQUUsZUFBZSxFQUFFO1lBQ3JELFdBQVcsRUFBRSxHQUFHLG1CQUFLLENBQUMsRUFBRSxD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QWMsQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUV6QyxPQUFPLGNBQWMsQ0FBQztJQUMxQixDQUFDO0lBRU8sbUJBQW1CLENBQUMsT0FBZ0I7UUFDeEMsTUFBTSxTQUFTLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsV0FBVyxDQUFDLGtCQUFrQixJQUFJLFdBQVcsQ0FBQztRQUMvRSxPQUFPLENBQUMsZUFBZSxDQUFDLElBQUkseUJBQWUsQ0FBQztZQUN4QyxPQUFPLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztZQUMzQixTQUFTLEVBQUU7Z0JBQ1AsZ0JBQWdCLGlCQUFHLENBQUMsVUFBVSxhQUFhLFNBQVMsZ0JBQWdCLGlCQUFHLENBQUMsVUFBVSxJQUFJLGlCQUFHLENBQUMsTUFBTSxFQUFFO2dCQUNsRyxnQkFBZ0IsaUJBQUcsQ0FBQyxVQUFVLGFBQWEsU0FBUyx5QkFBeUIsaUJBQUcsQ0FBQyxVQUFVLElBQUksaUJBQUcsQ0FBQyxNQUFNLEVBQUU7Z0JBQzNHLGdCQUFnQixpQkFBRyxDQUFDLFVBQVUsYUFBYSxTQUFTLDBCQUEwQixpQkFBRyxDQUFDLFVBQVUsSUFBSSxpQkFBRyxDQUFDLE1BQU0sRUFBRTtnQkFDNUcsZ0JBQWdCLGlCQUFHLENBQUMsVUFBVSxhQUFhLFNBQVMsZ0JBQWdCLGlCQUFHLENBQUMsVUFBVSxJQUFJLGlCQUFHLENBQUMsTUFBTSxFQUFFO2FBQ3JHO1NBQ0osQ0FBQyxDQUFDLENBQUM7SUFDUixDQUFDO0NBQ0o7QUFwSkQsa0RBb0pDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtBd3MsIFN0YWNrfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQge0J1aWxkU3BlYywgUHJvamVjdCwgU291cmNlfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY29kZWJ1aWxkJztcbmltcG9ydCAqIGFzIHRhcmdldHMgZnJvbSAnYXdzLWNkay1saWIvYXdzLWV2ZW50cy10YXJnZXRzJztcbmltcG9ydCB7Q29uc3RydWN0fSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7Q3VzdG9tTm9kZWpzRnVuY3Rpb259IGZyb20gJy4vY3VzdG9tTm9kZWpzRnVuY3Rpb24nO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7Tm90aWZpY2F0aW9uc1RvcGljfSBmcm9tICcuL25vdGlmaWNhdGlvbnNUb3BpYyc7XG5pbXBvcnQge0FwcGxpY2F0aW9uUHJvcHMsIFJlc29sdmVkQXBwbGljYXRpb25Qcm9wc30gZnJvbSAnLi4vYXBwbGljYXRpb25Qcm9wcyc7XG5pbXBvcnQge1BvbGljeVN0YXRlbWVudH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQge0NvZGV9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHtUb3BpY30gZnJvbSAnYXdzLWNkay1saWIvYXdzLXNucyc7XG5pbXBvcnQge2dldFByb2plY3ROYW1lfSBmcm9tICcuLi91dGlsL2NvbnRleHQnO1xuaW1wb3J0IHtJU3RyaW5nUGFyYW1ldGVyfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc3NtJztcbmltcG9ydCAqIGFzIHMzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQge2NoZWNrb3V0Q29tbWFuZHN9IGZyb20gJy4uL3V0aWwvY2hlY2tvdXQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEZlYXR1cmVCcmFuY2hCdWlsZHNQcm9wcyBleHRlbmRzIFBpY2s8UmVzb2x2ZWRBcHBsaWNhdGlvblByb3BzLFxuICAgICdyZXBvc2l0b3J5JyB8ICdjb21tYW5kcycgfCAnY29kZUJ1aWxkJ1xuPiB7XG4gICAgc291cmNlQnVja2V0OiBzMy5JQnVja2V0O1xuICAgIHJlcG9zaXRvcnlUb2tlblBhcmFtOiBJU3RyaW5nUGFyYW1ldGVyO1xufVxuXG5leHBvcnQgY2xhc3MgRmVhdHVyZUJyYW5jaEJ1aWxkcyBleHRlbmRzIENvbnN0cnVjdCB7XG5cbiAgICByZWFkb25seSBmYWlsdXJlc1RvcGljOiBUb3BpYztcblxuICAgIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBGZWF0dXJlQnJhbmNoQnVpbGRzUHJvcHMpIHtcbiAgICAgICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgICAgICBjb25zdCBkZXBsb3lQcm9qZWN0ID0gdGhpcy5jcmVhdGVEZXBsb3lQcm9qZWN0KFxuICAgICAgICAgICAgcHJvcHMuc291cmNlQnVja2V0LCBwcm9wcy5jb2RlQnVpbGQsIHByb3BzLmNvbW1hbmRzLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmNyZWF0ZURlcGxveU5vdGlmaWNhdGlvbnMoZGVwbG95UHJvamVjdCwgcHJvcHMucmVwb3NpdG9yeSwgcHJvcHMucmVwb3NpdG9yeVRva2VuUGFyYW0pO1xuXG4gICAgICAgIHRoaXMuZmFpbHVyZXNUb3BpYyA9IHRoaXMuY3JlYXRlQnVpbGRGYWlsdXJlc1RvcGljKGRlcGxveVByb2plY3QpO1xuXG4gICAgICAgIHRoaXMuY3JlYXRlRGVzdHJveVByb2plY3QoXG4gICAgICAgICAgICBwcm9wcy5zb3VyY2VCdWNrZXQsIHByb3BzLmNvZGVCdWlsZCwgcHJvcHMuY29tbWFuZHMsXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjcmVhdGVEZXBsb3lQcm9qZWN0KFxuICAgICAgICBzb3VyY2VCdWNrZXQ6IHMzLklCdWNrZXQsXG4gICAgICAgIGNvZGVCdWlsZDogRmVhdHVyZUJyYW5jaEJ1aWxkc1Byb3BzWydjb2RlQnVpbGQnXSxcbiAgICAgICAgY29tbWFuZHM6IEZlYXR1cmVCcmFuY2hCdWlsZHNQcm9wc1snY29tbWFuZHMnXSxcbiAgICApOiBQcm9qZWN0IHtcbiAgICAgICAgY29uc3QgZGVwbG95UHJvamVjdCA9IG5ldyBQcm9qZWN0KHRoaXMsICdEZXBsb3lQcm9qZWN0Jywge1xuICAgICAgICAgICAgcHJvamVjdE5hbWU6IGAke1N0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZX0tZmVhdHVyZUJyYW5jaC1kZXBsb3lgLFxuICAgICAgICAgICAgc291cmNlOiBTb3VyY2UuczMoe1xuICAgICAgICAgICAgICAgIGJ1Y2tldDogc291cmNlQnVja2V0LFxuICAgICAgICAgICAgICAgIHBhdGg6ICdyZXBvc2l0b3J5LWZpbGUtcGxhY2Vob2xkZXItdG8tb3ZlcnJpZGUuemlwJyxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgLi4uY29kZUJ1aWxkLFxuICAgICAgICAgICAgZW52aXJvbm1lbnQ6IGNvZGVCdWlsZC5idWlsZEVudmlyb25tZW50LFxuICAgICAgICAgICAgYnVpbGRTcGVjOiBCdWlsZFNwZWMuZnJvbU9iamVjdCh7XG4gICAgICAgICAgICAgICAgdmVyc2lvbjogJzAuMicsXG4gICAgICAgICAgICAgICAgcGhhc2VzOiB7XG4gICAgICAgICAgICAgICAgICAgIGluc3RhbGw6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uY2hlY2tvdXRDb21tYW5kcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnZ2l0IGNoZWNrb3V0ICR7QlJBTkNIX05BTUV9JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRU5WX05BTUU9JChlY2hvICR7QlJBTkNIX05BTUV9IHwgYXdrIFxcJ3sgZ3N1YihcIi9cIiwgXCItXCIsICQwKTsgcHJpbnQgdG9sb3dlcigkMCk7IH1cXCcpJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4oY29tbWFuZHMucHJlSW5zdGFsbCB8fCBbXSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKGNvbW1hbmRzLmluc3RhbGwgfHwgW10pLFxuICAgICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgYnVpbGQ6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKGNvbW1hbmRzLmJ1aWxkQW5kVGVzdCB8fCBbXSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKGNvbW1hbmRzLnByZURlcGxveUVudmlyb25tZW50IHx8IFtdKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5jb21tYW5kcy5kZXBsb3lFbnZpcm9ubWVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4oY29tbWFuZHMucG9zdERlcGxveUVudmlyb25tZW50IHx8IFtdKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICB9KTtcblxuICAgICAgICBjb2RlQnVpbGQucm9sZVBvbGljeT8uZm9yRWFjaChwb2xpY3kgPT4gZGVwbG95UHJvamVjdC5hZGRUb1JvbGVQb2xpY3kocG9saWN5KSk7XG4gICAgICAgIHNvdXJjZUJ1Y2tldC5ncmFudFJlYWQoZGVwbG95UHJvamVjdCk7XG4gICAgICAgIHRoaXMuZ3JhbnRBc3N1bWVDREtSb2xlcyhkZXBsb3lQcm9qZWN0KTtcblxuICAgICAgICByZXR1cm4gZGVwbG95UHJvamVjdDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNyZWF0ZURlcGxveU5vdGlmaWNhdGlvbnMoZGVwbG95UHJvamVjdDogUHJvamVjdCwgcmVwb3NpdG9yeTogQXBwbGljYXRpb25Qcm9wc1sncmVwb3NpdG9yeSddLCByZXBvVG9rZW5QYXJhbTogSVN0cmluZ1BhcmFtZXRlcikge1xuICAgICAgICBjb25zdCBkZXBsb3lTdGF0dXNGdW5jdGlvbiA9IG5ldyBDdXN0b21Ob2RlanNGdW5jdGlvbih0aGlzLCAnRGVwbG95U3RhdHVzJywge1xuICAgICAgICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQocGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJ2xhbWJkYScsICdmZWF0dXJlQnJhbmNoRGVwbG95U3RhdHVzJykpLFxuICAgICAgICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgICAgICAgICBSRVBPU0lUT1JZX0hPU1Q6IHJlcG9zaXRvcnkuaG9zdCxcbiAgICAgICAgICAgICAgICBSRVBPU0lUT1JZX05BTUU6IHJlcG9zaXRvcnkubmFtZSxcbiAgICAgICAgICAgICAgICBSRVBPU0lUT1JZX1RPS0VOX1BBUkFNX05BTUU6IHJlcG9Ub2tlblBhcmFtLnBhcmFtZXRlck5hbWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgICAgcmVwb1Rva2VuUGFyYW0uZ3JhbnRSZWFkKGRlcGxveVN0YXR1c0Z1bmN0aW9uKTtcblxuICAgICAgICBkZXBsb3lQcm9qZWN0Lm9uU3RhdGVDaGFuZ2UoJ09uRGVwbG95U3RhdGVDaGFuZ2UnLCB7XG4gICAgICAgICAgICB0YXJnZXQ6IG5ldyB0YXJnZXRzLkxhbWJkYUZ1bmN0aW9uKGRlcGxveVN0YXR1c0Z1bmN0aW9uKSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjcmVhdGVCdWlsZEZhaWx1cmVzVG9waWMoZGVwbG95UHJvamVjdDogUHJvamVjdCk6IFRvcGljIHtcbiAgICAgICAgY29uc3QgZmFpbHVyZXNUb3BpYyA9IG5ldyBOb3RpZmljYXRpb25zVG9waWModGhpcywgJ0ZlYXR1cmVCcmFuY2hCdWlsZEZhaWx1cmVzVG9waWMnLCB7XG4gICAgICAgICAgICBwcm9qZWN0TmFtZTogZ2V0UHJvamVjdE5hbWUodGhpcyksXG4gICAgICAgICAgICBub3RpZmljYXRpb25OYW1lOiAnZmVhdHVyZUJyYW5jaEJ1aWxkRmFpbHVyZXMnLFxuICAgICAgICB9KTtcblxuICAgICAgICBkZXBsb3lQcm9qZWN0Lm5vdGlmeU9uQnVpbGRGYWlsZWQoJ05vdGlmeU9uRmVhdHVyZUJ1aWxkRmFpbHVyZScsIGZhaWx1cmVzVG9waWMudG9waWMsIHtcbiAgICAgICAgICAgIG5vdGlmaWNhdGlvblJ1bGVOYW1lOiBgJHtTdGFjay5vZih0aGlzKS5zdGFja05hbWV9LWZlYXR1cmVCdWlsZEZhaWx1cmVgLCAvLyBlbnN1cmUgdW5pcXVlIG5hbWVcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGZhaWx1cmVzVG9waWMudG9waWM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjcmVhdGVEZXN0cm95UHJvamVjdChcbiAgICAgICAgc291cmNlQnVja2V0OiBzMy5JQnVja2V0LFxuICAgICAgICBjb2RlQnVpbGQ6IEZlYXR1cmVCcmFuY2hCdWlsZHNQcm9wc1snY29kZUJ1aWxkJ10sXG4gICAgICAgIGNvbW1hbmRzOiBGZWF0dXJlQnJhbmNoQnVpbGRzUHJvcHNbJ2NvbW1hbmRzJ10sXG4gICAgKTogUHJvamVjdCB7XG4gICAgICAgIGNvbnN0IGRlc3Ryb3lQcm9qZWN0ID0gbmV3IFByb2plY3QodGhpcywgJ0Rlc3Ryb3lQcm9qZWN0Jywge1xuICAgICAgICAgICAgcHJvamVjdE5hbWU6IGAke1N0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZX0tZmVhdHVyZUJyYW5jaC1kZXN0cm95YCxcbiAgICAgICAgICAgIHNvdXJjZTogU291cmNlLnMzKHtcbiAgICAgICAgICAgICAgICBidWNrZXQ6IHNvdXJjZUJ1Y2tldCxcbiAgICAgICAgICAgICAgICBwYXRoOiAncmVwb3NpdG9yeS1maWxlLXBsYWNlaG9sZGVyLXRvLW92ZXJyaWRlLnppcCcsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIC4uLmNvZGVCdWlsZCxcbiAgICAgICAgICAgIGVudmlyb25tZW50OiBjb2RlQnVpbGQuYnVpbGRFbnZpcm9ubWVudCxcbiAgICAgICAgICAgIGJ1aWxkU3BlYzogQnVpbGRTcGVjLmZyb21PYmplY3Qoe1xuICAgICAgICAgICAgICAgIHZlcnNpb246ICcwLjInLFxuICAgICAgICAgICAgICAgIHBoYXNlczoge1xuICAgICAgICAgICAgICAgICAgICBpbnN0YWxsOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb21tYW5kczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLmNoZWNrb3V0Q29tbWFuZHMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0VOVl9OQU1FPSQoZWNobyAke0JSQU5DSF9OQU1FfSB8IGF3ayBcXCd7IGdzdWIoXCIvXCIsIFwiLVwiLCAkMCk7IHByaW50IHRvbG93ZXIoJDApOyB9XFwnKScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKGNvbW1hbmRzLnByZUluc3RhbGwgfHwgW10pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLihjb21tYW5kcy5pbnN0YWxsIHx8IFtdKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGJ1aWxkOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb21tYW5kczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLihjb21tYW5kcy5wcmVEZXN0cm95RW52aXJvbm1lbnQgfHwgW10pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLmNvbW1hbmRzLmRlc3Ryb3lFbnZpcm9ubWVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4oY29tbWFuZHMucG9zdERlc3Ryb3lFbnZpcm9ubWVudCB8fCBbXSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2F3cyBzMyBybSBzMzovLyR7Q09ERUJVSUxEX1NPVVJDRV9SRVBPX1VSTH0nLFxuICAgICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSksXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvZGVCdWlsZC5yb2xlUG9saWN5Py5mb3JFYWNoKHBvbGljeSA9PiBkZXN0cm95UHJvamVjdC5hZGRUb1JvbGVQb2xpY3kocG9saWN5KSk7XG4gICAgICAgIHNvdXJjZUJ1Y2tldC5ncmFudFJlYWQoZGVzdHJveVByb2plY3QpO1xuICAgICAgICBzb3VyY2VCdWNrZXQuZ3JhbnREZWxldGUoZGVzdHJveVByb2plY3QpO1xuICAgICAgICB0aGlzLmdyYW50QXNzdW1lQ0RLUm9sZXMoZGVzdHJveVByb2plY3QpO1xuXG4gICAgICAgIHJldHVybiBkZXN0cm95UHJvamVjdDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdyYW50QXNzdW1lQ0RLUm9sZXMocHJvamVjdDogUHJvamVjdCkge1xuICAgICAgICBjb25zdCBxdWFsaWZpZXIgPSBTdGFjay5vZih0aGlzKS5zeW50aGVzaXplci5ib290c3RyYXBRdWFsaWZpZXIgfHwgJ2huYjY1OWZkcyc7XG4gICAgICAgIHByb2plY3QuYWRkVG9Sb2xlUG9saWN5KG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgYWN0aW9uczogWydzdHM6QXNzdW1lUm9sZSddLFxuICAgICAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgICAgICAgYGFybjphd3M6aWFtOjoke0F3cy5BQ0NPVU5UX0lEfTpyb2xlL2Nkay0ke3F1YWxpZmllcn0tZGVwbG95LXJvbGUtJHtBd3MuQUNDT1VOVF9JRH0tJHtBd3MuUkVHSU9OfWAsXG4gICAgICAgICAgICAgICAgYGFybjphd3M6aWFtOjoke0F3cy5BQ0NPVU5UX0lEfTpyb2xlL2Nkay0ke3F1YWxpZmllcn0tZmlsZS1wdWJsaXNoaW5nLXJvbGUtJHtBd3MuQUNDT1VOVF9JRH0tJHtBd3MuUkVHSU9OfWAsXG4gICAgICAgICAgICAgICAgYGFybjphd3M6aWFtOjoke0F3cy5BQ0NPVU5UX0lEfTpyb2xlL2Nkay0ke3F1YWxpZmllcn0taW1hZ2UtcHVibGlzaGluZy1yb2xlLSR7QXdzLkFDQ09VTlRfSUR9LSR7QXdzLlJFR0lPTn1gLFxuICAgICAgICAgICAgICAgIGBhcm46YXdzOmlhbTo6JHtBd3MuQUNDT1VOVF9JRH06cm9sZS9jZGstJHtxdWFsaWZpZXJ9LWxvb2t1cC1yb2xlLSR7QXdzLkFDQ09VTlRfSUR9LSR7QXdzLlJFR0lPTn1gLFxuICAgICAgICAgICAgXSxcbiAgICAgICAgfSkpO1xuICAgIH1cbn1cbiJdfQ==