Skip to content

Commit 1d85a9f

Browse files
author
Elad Ben-Israel
authored
feat(core): implicit app for root stacks (#9342)
When a stack is created as the root of the construct tree, we now implicitly create an `App` that serves as its parent scope. The root stack is created with the ID `Default`, which ensures that `node.uniqueId` of constructs within that stack is preserved. BREAKING CHANGE: in unit tests, the `node.path` of constructs within stacks created the root of the tree via `new Stack()` will now have a prefix `Default/` which represents an implicit `App` root. Related: aws/aws-cdk-rfcs#192 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 5e087e5 commit 1d85a9f

39 files changed

+227
-202
lines changed

packages/@aws-cdk/assert/lib/synth-utils.ts

+23-9
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import * as core from '@aws-cdk/core';
44
import * as cxapi from '@aws-cdk/cx-api';
55

66
export class SynthUtils {
7+
/**
8+
* Returns the cloud assembly template artifact for a stack.
9+
*/
710
public static synthesize(stack: core.Stack, options: core.SynthesisOptions = { }): cxapi.CloudFormationStackArtifact {
811
// always synthesize against the root (be it an App or whatever) so all artifacts will be included
9-
const root = stack.node.root;
10-
11-
// if the root is an app, invoke "synth" to avoid double synthesis
12-
const assembly = root instanceof core.App ? root.synth() : core.ConstructNode.synth(root.node, options);
13-
12+
const assembly = synthesizeApp(stack, options);
1413
return assembly.getStackArtifact(stack.artifactId);
1514
}
1615

@@ -51,10 +50,7 @@ export class SynthUtils {
5150
*/
5251
public static _synthesizeWithNested(stack: core.Stack, options: core.SynthesisOptions = { }): cxapi.CloudFormationStackArtifact | object {
5352
// always synthesize against the root (be it an App or whatever) so all artifacts will be included
54-
const root = stack.node.root;
55-
56-
// if the root is an app, invoke "synth" to avoid double synthesis
57-
const assembly = root instanceof core.App ? root.synth() : core.ConstructNode.synth(root.node, options);
53+
const assembly = synthesizeApp(stack, options);
5854

5955
// if this is a nested stack (it has a parent), then just read the template as a string
6056
if (stack.nestedStackParent) {
@@ -65,6 +61,24 @@ export class SynthUtils {
6561
}
6662
}
6763

64+
/**
65+
* Synthesizes the app in which a stack resides and returns the cloud assembly object.
66+
*/
67+
function synthesizeApp(stack: core.Stack, options: core.SynthesisOptions) {
68+
const root = stack.node.root;
69+
if (!core.Stage.isStage(root)) {
70+
throw new Error('unexpected: all stacks must be part of a Stage or an App');
71+
}
72+
73+
// to support incremental assertions (i.e. "expect(stack).toNotContainSomething(); doSomething(); expect(stack).toContainSomthing()")
74+
const force = true;
75+
76+
return root.synth({
77+
force,
78+
...options,
79+
});
80+
}
81+
6882
export interface SubsetOptions {
6983
/**
7084
* Match all resources of the given type

packages/@aws-cdk/aws-apigateway/test/authorizers/integ.request-authorizer.expected.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"Properties": {
3737
"Code": {
3838
"S3Bucket": {
39-
"Ref": "AssetParameterse7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0S3Bucket316B0B52"
39+
"Ref": "AssetParameters3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0S3BucketD7637C1B"
4040
},
4141
"S3Key": {
4242
"Fn::Join": [
@@ -49,7 +49,7 @@
4949
"Fn::Split": [
5050
"||",
5151
{
52-
"Ref": "AssetParameterse7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0S3VersionKey4A4C6C19"
52+
"Ref": "AssetParameters3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0S3VersionKeyC19FD924"
5353
}
5454
]
5555
}
@@ -62,7 +62,7 @@
6262
"Fn::Split": [
6363
"||",
6464
{
65-
"Ref": "AssetParameterse7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0S3VersionKey4A4C6C19"
65+
"Ref": "AssetParameters3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0S3VersionKeyC19FD924"
6666
}
6767
]
6868
}
@@ -272,17 +272,17 @@
272272
}
273273
},
274274
"Parameters": {
275-
"AssetParameterse7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0S3Bucket316B0B52": {
275+
"AssetParameters3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0S3BucketD7637C1B": {
276276
"Type": "String",
277-
"Description": "S3 bucket for asset \"e7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0\""
277+
"Description": "S3 bucket for asset \"3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0\""
278278
},
279-
"AssetParameterse7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0S3VersionKey4A4C6C19": {
279+
"AssetParameters3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0S3VersionKeyC19FD924": {
280280
"Type": "String",
281-
"Description": "S3 key for asset version \"e7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0\""
281+
"Description": "S3 key for asset version \"3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0\""
282282
},
283-
"AssetParameterse7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0ArtifactHash2FE6C4D8": {
283+
"AssetParameters3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0ArtifactHash9DF43F02": {
284284
"Type": "String",
285-
"Description": "Artifact hash for asset \"e7d4044be8659ef3bb40a53a69846d7ca1b2d8e4e4bd36ad8c9d8e69fe3b68a0\""
285+
"Description": "Artifact hash for asset \"3dc8c5549b88fef617feef923524902b3650973ae1159c9489ee8405344dd5a0\""
286286
}
287287
},
288288
"Outputs": {
@@ -313,4 +313,4 @@
313313
}
314314
}
315315
}
316-
}
316+
}

packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer-iam-role.expected.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"Properties": {
3737
"Code": {
3838
"S3Bucket": {
39-
"Ref": "AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3Bucket4E51347F"
39+
"Ref": "AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3Bucket2E551A38"
4040
},
4141
"S3Key": {
4242
"Fn::Join": [
@@ -49,7 +49,7 @@
4949
"Fn::Split": [
5050
"||",
5151
{
52-
"Ref": "AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3VersionKey707D1166"
52+
"Ref": "AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3VersionKeyE54FD621"
5353
}
5454
]
5555
}
@@ -62,7 +62,7 @@
6262
"Fn::Split": [
6363
"||",
6464
{
65-
"Ref": "AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3VersionKey707D1166"
65+
"Ref": "AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3VersionKeyE54FD621"
6666
}
6767
]
6868
}
@@ -281,17 +281,17 @@
281281
}
282282
},
283283
"Parameters": {
284-
"AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3Bucket4E51347F": {
284+
"AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3Bucket2E551A38": {
285285
"Type": "String",
286-
"Description": "S3 bucket for asset \"4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181e\""
286+
"Description": "S3 bucket for asset \"fec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3\""
287287
},
288-
"AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3VersionKey707D1166": {
288+
"AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3VersionKeyE54FD621": {
289289
"Type": "String",
290-
"Description": "S3 key for asset version \"4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181e\""
290+
"Description": "S3 key for asset version \"fec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3\""
291291
},
292-
"AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eArtifactHash267391ED": {
292+
"AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3ArtifactHashD7A29DA9": {
293293
"Type": "String",
294-
"Description": "Artifact hash for asset \"4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181e\""
294+
"Description": "Artifact hash for asset \"fec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3\""
295295
}
296296
},
297297
"Outputs": {
@@ -322,4 +322,4 @@
322322
}
323323
}
324324
}
325-
}
325+
}

packages/@aws-cdk/aws-apigateway/test/authorizers/integ.token-authorizer.expected.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"Properties": {
3737
"Code": {
3838
"S3Bucket": {
39-
"Ref": "AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3Bucket4E51347F"
39+
"Ref": "AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3Bucket2E551A38"
4040
},
4141
"S3Key": {
4242
"Fn::Join": [
@@ -49,7 +49,7 @@
4949
"Fn::Split": [
5050
"||",
5151
{
52-
"Ref": "AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3VersionKey707D1166"
52+
"Ref": "AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3VersionKeyE54FD621"
5353
}
5454
]
5555
}
@@ -62,7 +62,7 @@
6262
"Fn::Split": [
6363
"||",
6464
{
65-
"Ref": "AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3VersionKey707D1166"
65+
"Ref": "AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3VersionKeyE54FD621"
6666
}
6767
]
6868
}
@@ -272,17 +272,17 @@
272272
}
273273
},
274274
"Parameters": {
275-
"AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3Bucket4E51347F": {
275+
"AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3Bucket2E551A38": {
276276
"Type": "String",
277-
"Description": "S3 bucket for asset \"4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181e\""
277+
"Description": "S3 bucket for asset \"fec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3\""
278278
},
279-
"AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eS3VersionKey707D1166": {
279+
"AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3S3VersionKeyE54FD621": {
280280
"Type": "String",
281-
"Description": "S3 key for asset version \"4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181e\""
281+
"Description": "S3 key for asset version \"fec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3\""
282282
},
283-
"AssetParameters4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181eArtifactHash267391ED": {
283+
"AssetParametersfec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3ArtifactHashD7A29DA9": {
284284
"Type": "String",
285-
"Description": "Artifact hash for asset \"4e547bc3a1a10467cf6503c7845fe1a857e509746b927699a9e3bea8b802181e\""
285+
"Description": "Artifact hash for asset \"fec8e8354e12687c5a4b843b4e269741f53dec634946869b276f7fd1017845c3\""
286286
}
287287
},
288288
"Outputs": {
@@ -313,4 +313,4 @@
313313
}
314314
}
315315
}
316-
}
316+
}

packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json

+9-9
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@
528528
"Properties": {
529529
"Code": {
530530
"S3Bucket": {
531-
"Ref": "AssetParameters41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7S3Bucket763974CB"
531+
"Ref": "AssetParametersc7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4fS3BucketE85F411C"
532532
},
533533
"S3Key": {
534534
"Fn::Join": [
@@ -541,7 +541,7 @@
541541
"Fn::Split": [
542542
"||",
543543
{
544-
"Ref": "AssetParameters41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7S3VersionKey57F05589"
544+
"Ref": "AssetParametersc7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4fS3VersionKeyF02404BC"
545545
}
546546
]
547547
}
@@ -554,7 +554,7 @@
554554
"Fn::Split": [
555555
"||",
556556
{
557-
"Ref": "AssetParameters41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7S3VersionKey57F05589"
557+
"Ref": "AssetParametersc7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4fS3VersionKeyF02404BC"
558558
}
559559
]
560560
}
@@ -607,17 +607,17 @@
607607
}
608608
},
609609
"Parameters": {
610-
"AssetParameters41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7S3Bucket763974CB": {
610+
"AssetParametersc7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4fS3BucketE85F411C": {
611611
"Type": "String",
612-
"Description": "S3 bucket for asset \"41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7\""
612+
"Description": "S3 bucket for asset \"c7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4f\""
613613
},
614-
"AssetParameters41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7S3VersionKey57F05589": {
614+
"AssetParametersc7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4fS3VersionKeyF02404BC": {
615615
"Type": "String",
616-
"Description": "S3 key for asset version \"41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7\""
616+
"Description": "S3 key for asset version \"c7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4f\""
617617
},
618-
"AssetParameters41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7ArtifactHash9CD65872": {
618+
"AssetParametersc7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4fArtifactHash6742F1C9": {
619619
"Type": "String",
620-
"Description": "Artifact hash for asset \"41bb2d4a81eb782e91694a93a5e13f3e4a4ed3148bdb066856d1e5275b593cd7\""
620+
"Description": "Artifact hash for asset \"c7bba0d9d477c86c6dc2adb0eb95842634a1c040dd3a66b42eec2bb604644d4f\""
621621
}
622622
}
623623
}

packages/@aws-cdk/aws-autoscaling/test/auto-scaling-group.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ nodeunitShim({
3232
'MyFleetInstanceSecurityGroup774E8234': {
3333
'Type': 'AWS::EC2::SecurityGroup',
3434
'Properties': {
35-
'GroupDescription': 'MyFleet/InstanceSecurityGroup',
35+
'GroupDescription': 'TestStack/MyFleet/InstanceSecurityGroup',
3636
'SecurityGroupEgress': [
3737
{
3838
'CidrIp': '0.0.0.0/0',
@@ -43,7 +43,7 @@ nodeunitShim({
4343
'Tags': [
4444
{
4545
'Key': 'Name',
46-
'Value': 'MyFleet',
46+
'Value': 'TestStack/MyFleet',
4747
},
4848
],
4949

@@ -68,7 +68,7 @@ nodeunitShim({
6868
'Tags': [
6969
{
7070
'Key': 'Name',
71-
'Value': 'MyFleet',
71+
'Value': 'TestStack/MyFleet',
7272
},
7373
],
7474
},
@@ -122,7 +122,7 @@ nodeunitShim({
122122
{
123123
'Key': 'Name',
124124
'PropagateAtLaunch': true,
125-
'Value': 'MyFleet',
125+
'Value': 'TestStack/MyFleet',
126126
},
127127
],
128128

@@ -520,7 +520,7 @@ nodeunitShim({
520520
{
521521
Key: 'Name',
522522
PropagateAtLaunch: true,
523-
Value: 'MyFleet',
523+
Value: 'TestStack/MyFleet',
524524
},
525525
{
526526
Key: 'notsuper',

packages/@aws-cdk/aws-autoscaling/test/scheduled-action.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ nodeunitShim({
6969
{
7070
Key: 'Name',
7171
PropagateAtLaunch: true,
72-
Value: 'ASG',
72+
Value: 'Default/ASG',
7373
},
7474
],
7575
VPCZoneIdentifier: [

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,9 @@ export = {
209209
const nested2 = new NestedStack(nested1, 'Nested2');
210210

211211
// THEN
212-
test.throws(() => nested1.addDependency(root), /Nested stack 'Nested1' cannot depend on a parent stack ''/);
213-
test.throws(() => nested2.addDependency(nested1), /Nested stack 'Nested1\/Nested2' cannot depend on a parent stack 'Nested1'/);
214-
test.throws(() => nested2.addDependency(root), /Nested stack 'Nested1\/Nested2' cannot depend on a parent stack ''/);
212+
test.throws(() => nested1.addDependency(root), /Nested stack 'Default\/Nested1' cannot depend on a parent stack 'Default'/);
213+
test.throws(() => nested2.addDependency(nested1), /Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default\/Nested1'/);
214+
test.throws(() => nested2.addDependency(root), /Nested stack 'Default\/Nested1\/Nested2' cannot depend on a parent stack 'Default'/);
215215
test.done();
216216
},
217217

packages/@aws-cdk/aws-codecommit/test/test.codecommit.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export = {
2929
'all',
3030
],
3131
DestinationArn: 'arn:aws:sns:*:123456789012:my_topic',
32-
Name: 'MyRepository/arn:aws:sns:*:123456789012:my_topic',
32+
Name: 'Default/MyRepository/arn:aws:sns:*:123456789012:my_topic',
3333
},
3434
],
3535
},

packages/@aws-cdk/aws-dynamodb/test/dynamodb.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ test('if an encryption key is included, encrypt/decrypt permissions are also add
721721
],
722722
'Version': '2012-10-17',
723723
},
724-
'Description': 'Customer-managed key auto-created for encrypting DynamoDB table at Table A',
724+
'Description': 'Customer-managed key auto-created for encrypting DynamoDB table at Default/Table A',
725725
'EnableKeyRotation': true,
726726
},
727727
'UpdateReplacePolicy': 'Retain',
@@ -1758,7 +1758,7 @@ describe('grants', () => {
17581758
const user = new iam.User(stack, 'user');
17591759

17601760
// WHEN
1761-
expect(() => table.grantTableListStreams(user)).toThrow(/DynamoDB Streams must be enabled on the table my-table/);
1761+
expect(() => table.grantTableListStreams(user)).toThrow(/DynamoDB Streams must be enabled on the table Default\/my-table/);
17621762
});
17631763

17641764
test('"grantTableListStreams" allows principal to list all streams for this table', () => {
@@ -1804,7 +1804,7 @@ describe('grants', () => {
18041804
const user = new iam.User(stack, 'user');
18051805

18061806
// WHEN
1807-
expect(() => table.grantStreamRead(user)).toThrow(/DynamoDB Streams must be enabled on the table my-table/);
1807+
expect(() => table.grantStreamRead(user)).toThrow(/DynamoDB Streams must be enabled on the table Default\/my-table/);
18081808
});
18091809

18101810
test('"grantStreamRead" allows principal to read and describe the table stream"', () => {

0 commit comments

Comments
 (0)