Skip to content

Commit 2af2426

Browse files
authored
feat(cdk): treat the "fake" CFN intrinsics (Fn::GetArtifactAtt, Fn::GetParam) specially when stringifying JSON. (#1605)
Fn::GetArtifactAtt and Fn::GetParam are not really intrinsics, they're functions that can be used only in CodePipeline CFN Actions, in the `parameterOverride` property. More information: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/continuous-delivery-codepipeline-parameter-override-functions.html Fixes #1588
1 parent f997fd2 commit 2af2426

File tree

5 files changed

+43
-3
lines changed

5 files changed

+43
-3
lines changed

packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-cfn.expected.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@
207207
"CfnChangeSetRole6F05F6FC",
208208
"Arn"
209209
]
210-
}
210+
},
211+
"ParameterOverrides": "{\"BucketName\":{\"Fn::GetArtifactAtt\":[\"SourceArtifact\",\"BucketName\"]},\"ObjectKey\":{\"Fn::GetArtifactAtt\":[\"SourceArtifact\",\"ObjectKey\"]},\"Url\":{\"Fn::GetArtifactAtt\":[\"SourceArtifact\",\"URL\"]},\"OtherParam\":{\"Fn::GetParam\":[\"SourceArtifact\",\"params.json\",\"OtherParam\"]}}"
211212
},
212213
"InputArtifacts": [
213214
{

packages/@aws-cdk/aws-codepipeline/test/integ.pipeline-cfn.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ new cfn.PipelineCreateReplaceChangeSetAction(stack, 'DeployCFN', {
3939
role,
4040
templatePath: source.outputArtifact.atPath('test.yaml'),
4141
adminPermissions: false,
42+
parameterOverrides: {
43+
BucketName: source.outputArtifact.bucketName,
44+
ObjectKey: source.outputArtifact.objectKey,
45+
Url: source.outputArtifact.url,
46+
OtherParam: source.outputArtifact.getParam('params.json', 'OtherParam'),
47+
},
4248
});
4349

4450
app.run();

packages/@aws-cdk/cdk/lib/cloudformation/instrinsics.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ export function isIntrinsic(x: any) {
3737
const keys = Object.keys(x);
3838
if (keys.length !== 1) { return false; }
3939

40-
return keys[0] === 'Ref' || keys[0].startsWith('Fn::');
40+
return keys[0] === 'Ref' || isNameOfCloudFormationIntrinsic(keys[0]);
41+
}
42+
43+
export function isNameOfCloudFormationIntrinsic(name: string): boolean {
44+
if (!name.startsWith('Fn::')) {
45+
return false;
46+
}
47+
// these are 'fake' intrinsics, only usable inside the parameter overrides of a CFN CodePipeline Action
48+
return name !== 'Fn::GetArtifactAtt' && name !== 'Fn::GetParam';
4149
}
4250

4351
/**

packages/@aws-cdk/cdk/test/cloudformation/evaluate-cfn.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*
44
* Note that this function is not production quality, it exists to support tests.
55
*/
6+
import { isNameOfCloudFormationIntrinsic } from '../../lib/cloudformation/instrinsics';
7+
68
export function evaluateCFN(object: any, context: {[key: string]: string} = {}): any {
79
const intrinsics: any = {
810
'Fn::Join'(separator: string, args: string[]) {
@@ -34,7 +36,7 @@ export function evaluateCFN(object: any, context: {[key: string]: string} = {}):
3436

3537
if (typeof obj === 'object') {
3638
const keys = Object.keys(obj);
37-
if (keys.length === 1 && (keys[0].startsWith('Fn::') || keys[0] === 'Ref')) {
39+
if (keys.length === 1 && (isNameOfCloudFormationIntrinsic(keys[0]) || keys[0] === 'Ref')) {
3840
return evaluateIntrinsic(keys[0], obj[keys[0]]);
3941
}
4042

packages/@aws-cdk/cdk/test/cloudformation/test.cloudformation-json.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,29 @@ export = {
9292
test.done();
9393
},
9494

95+
'fake intrinsics are serialized to objects'(test: Test) {
96+
const stack = new Stack();
97+
const fakeIntrinsics = new Token(() => ({
98+
a: {
99+
'Fn::GetArtifactAtt': {
100+
key: 'val',
101+
},
102+
},
103+
b: {
104+
'Fn::GetParam': [
105+
'val1',
106+
'val2',
107+
],
108+
},
109+
}));
110+
111+
const stringified = CloudFormationJSON.stringify(fakeIntrinsics, stack);
112+
test.equal(evaluateCFN(stack.node.resolve(stringified)),
113+
'{"a":{"Fn::GetArtifactAtt":{"key":"val"}},"b":{"Fn::GetParam":["val1","val2"]}}');
114+
115+
test.done();
116+
},
117+
95118
'embedded string literals in intrinsics are escaped when calling TokenJSON.stringify()'(test: Test) {
96119
// GIVEN
97120
const stack = new Stack();

0 commit comments

Comments
 (0)