diff --git a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/Stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/Stack.assets.json index 2dabbe5b2dd68..ff31ba5c3dfe8 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/Stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/Stack.assets.json @@ -1,7 +1,7 @@ { - "version": "34.0.0", + "version": "36.0.0", "files": { - "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "ada73ce032944e5c142954c37e515edb7a1b5203f3a1599365be93987f283142": { "source": { "path": "Stack.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "objectKey": "ada73ce032944e5c142954c37e515edb7a1b5203f3a1599365be93987f283142.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/Stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/Stack.template.json index ad9d0fb73d1dd..bcf6c5053f85e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/Stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/Stack.template.json @@ -1,4 +1,20 @@ { + "Outputs": { + "ExportMyExportValue": { + "Description": "This is a description for MyExportValue", + "Value": "someValue", + "Export": { + "Name": "MyExportValue" + } + }, + "ExportMyExportStringListValue": { + "Description": "This is a description for MyExportStringListValue", + "Value": "someValue||anotherValue", + "Export": { + "Name": "MyExportStringListValue" + } + } + }, "Parameters": { "BootstrapVersion": { "Type": "AWS::SSM::Parameter::Value", diff --git a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/cdk.out index 2313ab5436501..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"34.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/integ.json index d5fb120c891d1..e32db3df8bded 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "testCases": { "stack/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/manifest.json index 2630c9fb741f7..0efb002bd9459 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "artifacts": { "Stack.assets": { "type": "cdk:asset-manifest", @@ -18,7 +18,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/ada73ce032944e5c142954c37e515edb7a1b5203f3a1599365be93987f283142.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -34,6 +34,18 @@ "Stack.assets" ], "metadata": { + "/Stack/ExportMyExportValue": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportMyExportValue" + } + ], + "/Stack/ExportMyExportStringListValue": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportMyExportStringListValue" + } + ], "/Stack/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/stackDefaultTestDeployAssert0386B0AD.assets.json b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/stackDefaultTestDeployAssert0386B0AD.assets.json index 501878ac128f2..db69b4c394a5f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/stackDefaultTestDeployAssert0386B0AD.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/stackDefaultTestDeployAssert0386B0AD.assets.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/tree.json index 7499983ab0eca..cef5b75323ea7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.js.snapshot/tree.json @@ -8,26 +8,42 @@ "id": "Stack", "path": "Stack", "children": { + "ExportMyExportValue": { + "id": "ExportMyExportValue", + "path": "Stack/ExportMyExportValue", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "ExportMyExportStringListValue": { + "id": "ExportMyExportStringListValue", + "path": "Stack/ExportMyExportStringListValue", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "Stack/BootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "Stack/CheckBootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnRule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.Stack", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "stack": { @@ -43,7 +59,7 @@ "path": "stack/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } }, "DeployAssert": { @@ -54,22 +70,22 @@ "id": "BootstrapVersion", "path": "stack/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnParameter", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", "path": "stack/DefaultTest/DeployAssert/CheckBootstrapVersion", "constructInfo": { - "fqn": "aws-cdk-lib.CfnRule", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.Stack", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } }, @@ -89,13 +105,13 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.App", - "version": "0.0.0" + "fqn": "constructs.Construct", + "version": "10.3.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.ts b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.ts index f314579e7fd43..2fc4c48639346 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/core/test/integ.stack.ts @@ -9,4 +9,13 @@ const app = new cdk.App(); const stack = new cdk.Stack(app, 'Stack', { terminationProtection: false }); stack.terminationProtection = true; +stack.exportValue('someValue', { + name: 'MyExportValue', + description: 'This is a description for MyExportValue', +}); +stack.exportStringListValue(['someValue', 'anotherValue'], { + name: 'MyExportStringListValue', + description: 'This is a description for MyExportStringListValue', +}); + new IntegTest(app, 'stack', { testCases: [stack] }); diff --git a/packages/aws-cdk-lib/core/README.md b/packages/aws-cdk-lib/core/README.md index 446cb1a118976..7f6f1b486166b 100644 --- a/packages/aws-cdk-lib/core/README.md +++ b/packages/aws-cdk-lib/core/README.md @@ -836,6 +836,17 @@ new CfnOutput(this, 'OutputName', { }); ``` +You can also use the `exportValue` method to export values as stack outputs: + +```ts +declare const stack: Stack; + +stack.exportValue(myBucket.bucketName, { + name: 'TheAwesomeBucket', + description: 'The name of an S3 bucket', +}); +``` + [cfn-stack-output]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html ### Parameters diff --git a/packages/aws-cdk-lib/core/lib/stack.ts b/packages/aws-cdk-lib/core/lib/stack.ts index bea3f6814f452..b946d73974973 100644 --- a/packages/aws-cdk-lib/core/lib/stack.ts +++ b/packages/aws-cdk-lib/core/lib/stack.ts @@ -1204,6 +1204,7 @@ export class Stack extends Construct implements ITaggable { new CfnOutput(this, `Export${options.name}`, { value: exportedValue, exportName: options.name, + description: options.description, }); return Fn.importValue(options.name); } @@ -1215,6 +1216,7 @@ export class Stack extends Construct implements ITaggable { new CfnOutput(exportsScope, id, { value: Token.asString(exportable), exportName, + description: options.description, }); } @@ -1253,6 +1255,7 @@ export class Stack extends Construct implements ITaggable { new CfnOutput(this, `Export${options.name}`, { value: Fn.join(STRING_LIST_REFERENCE_DELIMITER, exportedValue), exportName: options.name, + description: options.description, }); return Fn.split(STRING_LIST_REFERENCE_DELIMITER, Fn.importValue(options.name)); } @@ -1268,6 +1271,7 @@ export class Stack extends Construct implements ITaggable { // (string lists are invalid) value: Fn.join(STRING_LIST_REFERENCE_DELIMITER, Token.asList(exportable)), exportName, + description: options.description, }); } @@ -1766,6 +1770,13 @@ export interface ExportValueOptions { * @default - A name is automatically chosen */ readonly name?: string; + + /** + * The description of the outputs + * + * @default - No description + */ + readonly description?: string; } function count(xs: string[]): Record { diff --git a/packages/aws-cdk-lib/core/test/stack.test.ts b/packages/aws-cdk-lib/core/test/stack.test.ts index b7d1e6f846daf..82be67b19499b 100644 --- a/packages/aws-cdk-lib/core/test/stack.test.ts +++ b/packages/aws-cdk-lib/core/test/stack.test.ts @@ -1489,6 +1489,83 @@ describe('stack', () => { }); }); + test('exports with name can include description', () => { + const app = new App(); + const stack = new Stack(app, 'Stack'); + + stack.exportValue('someValue', { + name: 'MyExport', + description: 'This is a description', + }); + + const template = app.synth().getStackByName(stack.stackName).template; + expect(template).toMatchObject({ + Outputs: { + ExportMyExport: { + Description: 'This is a description', + }, + }, + }); + }); + + test('list exports with name can include description', () => { + const app = new App(); + const stack = new Stack(app, 'Stack'); + + stack.exportStringListValue(['someValue', 'anotherValue'], { + name: 'MyExport', + description: 'This is a description', + }); + + const template = app.synth().getStackByName(stack.stackName).template; + expect(template).toMatchObject({ + Outputs: { + ExportMyExport: { + Description: 'This is a description', + }, + }, + }); + }); + + test('exports without name can include description', () => { + const app = new App(); + const stack = new Stack(app, 'Stack'); + + const resource = new CfnResource(stack, 'Resource', { type: 'AWS::Resource' }); + stack.exportValue(resource.getAtt('Att'), { + description: 'This is a description', + }); + + const template = app.synth().getStackByName(stack.stackName).template; + expect(template).toMatchObject({ + Outputs: { + ExportsOutputFnGetAttResourceAttB5968E71: { + Description: 'This is a description', + }, + }, + }); + }); + + test('list exports without name can include description', () => { + const app = new App(); + const stack = new Stack(app, 'Stack'); + + const resource = new CfnResource(stack, 'Resource', { type: 'AWS::Resource' }); + (resource as any).attrAtt = ['Foo', 'Bar']; + stack.exportStringListValue(resource.getAtt('Att', ResolutionTypeHint.STRING_LIST), { + description: 'This is a description', + }); + + const template = app.synth().getStackByName(stack.stackName).template; + expect(template).toMatchObject({ + Outputs: { + ExportsOutputFnGetAttResourceAttB5968E71: { + Description: 'This is a description', + }, + }, + }); + }); + test('CfnSynthesisError is ignored when preparing cross references', () => { // GIVEN const app = new App();