aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
665 lines • 75.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const setup = require("./hotswap-test-setup");
const common_1 = require("../../../lib/api/hotswap/common");
let hotswapMockSdkProvider;
let mockUpdateProject;
beforeEach(() => {
hotswapMockSdkProvider = setup.setupHotswapTests();
mockUpdateProject = jest.fn();
hotswapMockSdkProvider.setUpdateProjectMock(mockUpdateProject);
});
describe.each([common_1.HotswapMode.FALL_BACK, common_1.HotswapMode.HOTSWAP_ONLY])('%p mode', (hotswapMode) => {
test('returns undefined when a new CodeBuild Project is added to the Stack', async () => {
// GIVEN
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
},
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mockUpdateProject).not.toHaveBeenCalled();
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(deployStackResult?.noOp).toEqual(true);
expect(mockUpdateProject).not.toHaveBeenCalled();
}
});
test('calls the updateProject() API when it receives only a source difference in a CodeBuild project', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
Name: 'my-project',
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'new-spec',
Type: 'NO_SOURCE',
},
Name: 'my-project',
},
Metadata: {
'aws:asset:path': 'new-path',
},
},
},
},
});
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mockUpdateProject).toHaveBeenCalledWith({
name: 'my-project',
source: {
type: 'NO_SOURCE',
buildspec: 'new-spec',
},
});
});
test('calls the updateProject() API when it receives only a source version difference in a CodeBuild project', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
Name: 'my-project',
SourceVersion: 'v1',
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
Name: 'my-project',
SourceVersion: 'v2',
},
Metadata: {
'aws:asset:path': 'new-path',
},
},
},
},
});
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mockUpdateProject).toHaveBeenCalledWith({
name: 'my-project',
sourceVersion: 'v2',
});
});
test('calls the updateProject() API when it receives only an environment difference in a CodeBuild project', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
Name: 'my-project',
Environment: {
ComputeType: 'BUILD_GENERAL1_SMALL',
EnvironmentVariables: [
{
Name: 'SUPER_IMPORTANT_ENV_VAR',
Type: 'PLAINTEXT',
Value: 'super cool value',
},
{
Name: 'SECOND_IMPORTANT_ENV_VAR',
Type: 'PLAINTEXT',
Value: 'yet another super cool value',
},
],
Image: 'aws/codebuild/standard:1.0',
ImagePullCredentialsType: 'CODEBUILD',
PrivilegedMode: false,
Type: 'LINUX_CONTAINER',
},
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
Name: 'my-project',
Environment: {
ComputeType: 'BUILD_GENERAL1_SMALL',
EnvironmentVariables: [
{
Name: 'SUPER_IMPORTANT_ENV_VAR',
Type: 'PLAINTEXT',
Value: 'changed value',
},
{
Name: 'NEW_IMPORTANT_ENV_VAR',
Type: 'PLAINTEXT',
Value: 'new value',
},
],
Image: 'aws/codebuild/standard:1.0',
ImagePullCredentialsType: 'CODEBUILD',
PrivilegedMode: false,
Type: 'LINUX_CONTAINER',
},
},
Metadata: {
'aws:asset:path': 'new-path',
},
},
},
},
});
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mockUpdateProject).toHaveBeenCalledWith({
name: 'my-project',
environment: {
computeType: 'BUILD_GENERAL1_SMALL',
environmentVariables: [
{
name: 'SUPER_IMPORTANT_ENV_VAR',
type: 'PLAINTEXT',
value: 'changed value',
},
{
name: 'NEW_IMPORTANT_ENV_VAR',
type: 'PLAINTEXT',
value: 'new value',
},
],
image: 'aws/codebuild/standard:1.0',
imagePullCredentialsType: 'CODEBUILD',
privilegedMode: false,
type: 'LINUX_CONTAINER',
},
});
});
test("correctly evaluates the project's name when it references a different resource from the template", async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
Bucket: {
Type: 'AWS::S3::Bucket',
},
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
Name: {
'Fn::Join': ['-', [
{ Ref: 'Bucket' },
'project',
]],
},
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
setup.pushStackResourceSummaries(setup.stackSummaryOf('Bucket', 'AWS::S3::Bucket', 'mybucket'));
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
Bucket: {
Type: 'AWS::S3::Bucket',
},
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'new-spec',
Type: 'NO_SOURCE',
},
Name: {
'Fn::Join': ['-', [
{ Ref: 'Bucket' },
'project',
]],
},
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
},
});
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mockUpdateProject).toHaveBeenCalledWith({
name: 'mybucket-project',
source: {
type: 'NO_SOURCE',
buildspec: 'new-spec',
},
});
});
test("correctly falls back to taking the project's name from the current stack if it can't evaluate it in the template", async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Parameters: {
Param1: { Type: 'String' },
AssetBucketParam: { Type: 'String' },
},
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
Name: { Ref: 'Param1' },
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
setup.pushStackResourceSummaries(setup.stackSummaryOf('CodeBuildProject', 'AWS::CodeBuild::Project', 'my-project'));
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Parameters: {
Param1: { Type: 'String' },
AssetBucketParam: { Type: 'String' },
},
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'new-spec',
Type: 'NO_SOURCE',
},
Name: { Ref: 'Param1' },
},
Metadata: {
'aws:asset:path': 'new-path',
},
},
},
},
});
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact, { AssetBucketParam: 'asset-bucket' });
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mockUpdateProject).toHaveBeenCalledWith({
name: 'my-project',
source: {
type: 'NO_SOURCE',
buildspec: 'new-spec',
},
});
});
test("will not perform a hotswap deployment if it cannot find a Ref target (outside the project's name)", async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Parameters: {
Param1: { Type: 'String' },
},
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: { 'Fn::Sub': '${Param1}' },
Type: 'NO_SOURCE',
},
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
setup.pushStackResourceSummaries(setup.stackSummaryOf('CodeBuildProject', 'AWS::CodeBuild::Project', 'my-project'));
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Parameters: {
Param1: { Type: 'String' },
},
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: { 'Fn::Sub': '${Param1}' },
Type: 'CODEPIPELINE',
},
},
Metadata: {
'aws:asset:path': 'new-path',
},
},
},
},
});
// THEN
await expect(() => hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact)).rejects.toThrow(/Parameter or resource 'Param1' could not be found for evaluation/);
});
test("will not perform a hotswap deployment if it doesn't know how to handle a specific attribute (outside the project's name)", async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
Bucket: {
Type: 'AWS::S3::Bucket',
},
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: { 'Fn::GetAtt': ['Bucket', 'UnknownAttribute'] },
Type: 'NO_SOURCE',
},
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
setup.pushStackResourceSummaries(setup.stackSummaryOf('CodeBuildProject', 'AWS::CodeBuild::Project', 'my-project'), setup.stackSummaryOf('Bucket', 'AWS::S3::Bucket', 'my-bucket'));
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
Bucket: {
Type: 'AWS::S3::Bucket',
},
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: { 'Fn::GetAtt': ['Bucket', 'UnknownAttribute'] },
Type: 'S3',
},
},
Metadata: {
'aws:asset:path': 'new-path',
},
},
},
},
});
// THEN
await expect(() => hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact)).rejects.toThrow("We don't support the 'UnknownAttribute' attribute of the 'AWS::S3::Bucket' resource. This is a CDK limitation. Please report it at https://github.com/aws/aws-cdk/issues/new/choose");
});
test('calls the updateProject() API when it receives a difference in a CodeBuild project with no name', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
},
Metadata: {
'aws:asset:path': 'current-path',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'new-spec',
Type: 'NO_SOURCE',
},
},
Metadata: {
'aws:asset:path': 'current-path',
},
},
},
},
});
// WHEN
setup.pushStackResourceSummaries(setup.stackSummaryOf('CodeBuildProject', 'AWS::CodeBuild::Project', 'mock-project-resource-id'));
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mockUpdateProject).toHaveBeenCalledWith({
name: 'mock-project-resource-id',
source: {
type: 'NO_SOURCE',
buildspec: 'new-spec',
},
});
});
test('does not call the updateProject() API when it receives a change that is not Source, SourceVersion, or Environment difference in a CodeBuild project', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
ConcurrentBuildLimit: 1,
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
ConcurrentBuildLimit: 2,
},
},
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mockUpdateProject).not.toHaveBeenCalled();
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(deployStackResult?.noOp).toEqual(true);
expect(mockUpdateProject).not.toHaveBeenCalled();
}
});
test(`when it receives a change that is not Source, SourceVersion, or Environment difference in a CodeBuild project alongside a hotswappable change,
it does not call the updateProject() API in CLASSIC mode, but it does in HOTSWAP_ONLY mode`, async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
ConcurrentBuildLimit: 1,
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
CodeBuildProject: {
Type: 'AWS::CodeBuild::Project',
Properties: {
Source: {
BuildSpec: 'new-spec',
Type: 'NO_SOURCE',
},
ConcurrentBuildLimit: 2,
},
},
},
},
});
setup.pushStackResourceSummaries(setup.stackSummaryOf('CodeBuildProject', 'AWS::CodeBuild::Project', 'mock-project-resource-id'));
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mockUpdateProject).not.toHaveBeenCalled();
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mockUpdateProject).toHaveBeenCalledWith({
name: 'mock-project-resource-id',
source: {
type: 'NO_SOURCE',
buildspec: 'new-spec',
},
});
}
});
test('does not call the updateProject() API when a resource with type that is not AWS::CodeBuild::Project but has the same properties is changed', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
CodeBuildProject: {
Type: 'AWS::NotCodeBuild::NotAProject',
Properties: {
Source: {
BuildSpec: 'current-spec',
Type: 'NO_SOURCE',
},
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
CodeBuildProject: {
Type: 'AWS::NotCodeBuild::NotAProject',
Properties: {
Source: {
BuildSpec: 'new-spec',
Type: 'NO_SOURCE',
},
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
},
});
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).toBeUndefined();
expect(mockUpdateProject).not.toHaveBeenCalled();
}
else if (hotswapMode === common_1.HotswapMode.HOTSWAP_ONLY) {
// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact);
// THEN
expect(deployStackResult).not.toBeUndefined();
expect(deployStackResult?.noOp).toEqual(true);
expect(mockUpdateProject).not.toHaveBeenCalled();
}
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29kZS1idWlsZC1wcm9qZWN0cy1ob3Rzd2FwLWRlcGxveW1lbnRzLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjb2RlLWJ1aWxkLXByb2plY3RzLWhvdHN3YXAtZGVwbG95bWVudHMudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUVBLDhDQUE4QztBQUM5Qyw0REFBOEQ7QUFFOUQsSUFBSSxzQkFBb0QsQ0FBQztBQUN6RCxJQUFJLGlCQUEwRixDQUFDO0FBRS9GLFVBQVUsQ0FBQyxHQUFHLEVBQUU7SUFDZCxzQkFBc0IsR0FBRyxLQUFLLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztJQUNuRCxpQkFBaUIsR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7SUFDOUIsc0JBQXNCLENBQUMsb0JBQW9CLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUNqRSxDQUFDLENBQUMsQ0FBQztBQUVILFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxvQkFBVyxDQUFDLFNBQVMsRUFBRSxvQkFBVyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUU7SUFDMUYsSUFBSSxDQUFDLHNFQUFzRSxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ3RGLFFBQVE7UUFDUixNQUFNLGdCQUFnQixHQUFHLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQztZQUNoRCxRQUFRLEVBQUU7Z0JBQ1IsU0FBUyxFQUFFO29CQUNULGdCQUFnQixFQUFFO3dCQUNoQixJQUFJLEVBQUUseUJBQXlCO3FCQUNoQztpQkFDRjthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsSUFBSSxXQUFXLEtBQUssb0JBQVcsQ0FBQyxTQUFTLEVBQUU7WUFDekMsT0FBTztZQUNQLE1BQU0saUJBQWlCLEdBQUcsTUFBTSxzQkFBc0IsQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztZQUUzRyxPQUFPO1lBQ1AsTUFBTSxDQUFDLGlC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SUFDSCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L29yZGVyICovXG5pbXBvcnQgeyBDb2RlQnVpbGQgfSBmcm9tICdhd3Mtc2RrJztcbmltcG9ydCAqIGFzIHNldHVwIGZyb20gJy4vaG90c3dhcC10ZXN0LXNldHVwJztcbmltcG9ydCB7IEhvdHN3YXBNb2RlIH0gZnJvbSAnLi4vLi4vLi4vbGliL2FwaS9ob3Rzd2FwL2NvbW1vbic7XG5cbmxldCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyOiBzZXR1cC5Ib3Rzd2FwTW9ja1Nka1Byb3ZpZGVyO1xubGV0IG1vY2tVcGRhdGVQcm9qZWN0OiAocGFyYW1zOiBDb2RlQnVpbGQuVXBkYXRlUHJvamVjdElucHV0KSA9PiBDb2RlQnVpbGQuVXBkYXRlUHJvamVjdE91dHB1dDtcblxuYmVmb3JlRWFjaCgoKSA9PiB7XG4gIGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIgPSBzZXR1cC5zZXR1cEhvdHN3YXBUZXN0cygpO1xuICBtb2NrVXBkYXRlUHJvamVjdCA9IGplc3QuZm4oKTtcbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlci5zZXRVcGRhdGVQcm9qZWN0TW9jayhtb2NrVXBkYXRlUHJvamVjdCk7XG59KTtcblxuZGVzY3JpYmUuZWFjaChbSG90c3dhcE1vZGUuRkFMTF9CQUNLLCBIb3Rzd2FwTW9kZS5IT1RTV0FQX09OTFldKSgnJXAgbW9kZScsIChob3Rzd2FwTW9kZSkgPT4ge1xuICB0ZXN0KCdyZXR1cm5zIHVuZGVmaW5lZCB3aGVuIGEgbmV3IENvZGVCdWlsZCBQcm9qZWN0IGlzIGFkZGVkIHRvIHRoZSBTdGFjaycsIGFzeW5jICgpID0+IHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IGNka1N0YWNrQXJ0aWZhY3QgPSBzZXR1cC5jZGtTdGFja0FydGlmYWN0T2Yoe1xuICAgICAgdGVtcGxhdGU6IHtcbiAgICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgICAgQ29kZUJ1aWxkUHJvamVjdDoge1xuICAgICAgICAgICAgVHlwZTogJ0FXUzo6Q29kZUJ1aWxkOjpQcm9qZWN0JyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGlmIChob3Rzd2FwTW9kZSA9PT0gSG90c3dhcE1vZGUuRkFMTF9CQUNLKSB7XG4gICAgICAvLyBXSEVOXG4gICAgICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoaG90c3dhcE1vZGUsIGNka1N0YWNrQXJ0aWZhY3QpO1xuXG4gICAgICAvLyBUSEVOXG4gICAgICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLnRvQmVVbmRlZmluZWQoKTtcbiAgICAgIGV4cGVjdChtb2NrVXBkYXRlUHJvamVjdCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9IGVsc2UgaWYgKGhvdHN3YXBNb2RlID09PSBIb3Rzd2FwTW9kZS5IT1RTV0FQX09OTFkpIHtcbiAgICAgIC8vIFdIRU5cbiAgICAgIGNvbnN0IGRlcGxveVN0YWNrUmVzdWx0ID0gYXdhaXQgaG90c3dhcE1vY2tTZGtQcm92aWRlci50cnlIb3Rzd2FwRGVwbG95bWVudChob3Rzd2FwTW9kZSwgY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgICAgIC8vIFRIRU5cbiAgICAgIGV4cGVjdChkZXBsb3lTdGFja1Jlc3VsdCkubm90LnRvQmVVbmRlZmluZWQoKTtcbiAgICAgIGV4cGVjdChkZXBsb3lTdGFja1Jlc3VsdD8ubm9PcCkudG9FcXVhbCh0cnVlKTtcbiAgICAgIGV4cGVjdChtb2NrVXBkYXRlUHJvamVjdCkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9XG4gIH0pO1xuXG4gIHRlc3QoJ2NhbGxzIHRoZSB1cGRhdGVQcm9qZWN0KCkgQVBJIHdoZW4gaXQgcmVjZWl2ZXMgb25seSBhIHNvdXJjZSBkaWZmZXJlbmNlIGluIGEgQ29kZUJ1aWxkIHByb2plY3QnLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gR0lWRU5cbiAgICBzZXR1cC5zZXRDdXJyZW50Q2ZuU3RhY2tUZW1wbGF0ZSh7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgQ29kZUJ1aWxkUHJvamVjdDoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkNvZGVCdWlsZDo6UHJvamVjdCcsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgU291cmNlOiB7XG4gICAgICAgICAgICAgIEJ1aWxkU3BlYzogJ2N1cnJlbnQtc3BlYycsXG4gICAgICAgICAgICAgIFR5cGU6ICdOT19TT1VSQ0UnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIE5hbWU6ICdteS1wcm9qZWN0JyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIE1ldGFkYXRhOiB7XG4gICAgICAgICAgICAnYXdzOmFzc2V0OnBhdGgnOiAnb2xkLXBhdGgnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGNvbnN0IGNka1N0YWNrQXJ0aWZhY3QgPSBzZXR1cC5jZGtTdGFja0FydGlmYWN0T2Yoe1xuICAgICAgdGVtcGxhdGU6IHtcbiAgICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgICAgQ29kZUJ1aWxkUHJvamVjdDoge1xuICAgICAgICAgICAgVHlwZTogJ0FXUzo6Q29kZUJ1aWxkOjpQcm9qZWN0JyxcbiAgICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgICAgU291cmNlOiB7XG4gICAgICAgICAgICAgICAgQnVpbGRTcGVjOiAnbmV3LXNwZWMnLFxuICAgICAgICAgICAgICAgIFR5cGU6ICdOT19TT1VSQ0UnLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBOYW1lOiAnbXktcHJvamVjdCcsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgTWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgJ2F3czphc3NldDpwYXRoJzogJ25ldy1wYXRoJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfS