Skip to content

Commit

Permalink
feat(core): add description to exportValue and `exportStringListV…
Browse files Browse the repository at this point in the history
…alue` methods (#29150)

### Issue # (if applicable)

Closes #29092.

### Reason for this change

To be able to set the description of the `CfnOutput` created when using `exportValue` and `exportStringListValue`.

### Description of changes

Add property `description` to `ExportValueOptions` interface.

### Description of how you validated changes

Both unit and integ tests

### Checklist
- [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
go-to-k committed Feb 23, 2024
1 parent ea201d0 commit 2e080fe
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 24 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -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<String>",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -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] });
11 changes: 11 additions & 0 deletions packages/aws-cdk-lib/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions packages/aws-cdk-lib/core/lib/stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -1215,6 +1216,7 @@ export class Stack extends Construct implements ITaggable {
new CfnOutput(exportsScope, id, {
value: Token.asString(exportable),
exportName,
description: options.description,
});
}

Expand Down Expand Up @@ -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));
}
Expand All @@ -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,
});
}

Expand Down Expand Up @@ -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<string, number> {
Expand Down
77 changes: 77 additions & 0 deletions packages/aws-cdk-lib/core/test/stack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit 2e080fe

Please sign in to comment.