Skip to content

Commit

Permalink
fix(core): fix detection of references in Fn.join (#3569)
Browse files Browse the repository at this point in the history
References used in Fn.join() will now be properly substituted if
they're cross-stack references.

Fixes #3554.
  • Loading branch information
rix0rrr authored and mergify[bot] committed Aug 7, 2019
1 parent 4e11d86 commit 0a2540b
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 9 deletions.
9 changes: 3 additions & 6 deletions packages/@aws-cdk/core/lib/cfn-fn.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ICfnConditionExpression } from './cfn-condition';
import { minimalCloudFormationJoin } from './private/cloudformation-lang';
import { Intrinsic } from './private/intrinsic';
import { Reference } from './reference';
import { IResolvable, IResolveContext } from './resolvable';
import { captureStackTrace } from './stack-trace';
import { Token } from './token';
Expand Down Expand Up @@ -637,8 +638,6 @@ class FnJoin implements IResolvable {

private readonly delimiter: string;
private readonly listOfValues: any[];
// Cache for the result of resolveValues() - since it otherwise would be computed several times
private _resolvedValues?: any[];

/**
* Creates an ``Fn::Join`` function.
Expand Down Expand Up @@ -682,9 +681,7 @@ class FnJoin implements IResolvable {
* generate shorter output.
*/
private resolveValues(context: IResolveContext) {
if (this._resolvedValues) { return this._resolvedValues; }

const resolvedValues = this.listOfValues.map(context.resolve);
return this._resolvedValues = minimalCloudFormationJoin(this.delimiter, resolvedValues);
const resolvedValues = this.listOfValues.map(x => Reference.isReference(x) ? x : context.resolve(x));
return minimalCloudFormationJoin(this.delimiter, resolvedValues);
}
}
4 changes: 2 additions & 2 deletions packages/@aws-cdk/core/lib/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ export abstract class Resource extends Construct implements IResource {
* @experimental
*/
protected getResourceNameAttribute(nameAttr: string) {
return Token.asString({
resolve: (context: IResolveContext) => {
return Lazy.stringValue({
produce: (context: IResolveContext) => {
const consumingStack = Stack.of(context.scope);

if (this.stack.environment !== consumingStack.environment) {
Expand Down
30 changes: 29 additions & 1 deletion packages/@aws-cdk/core/test/test.fn.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fc = require('fast-check');
import _ = require('lodash');
import nodeunit = require('nodeunit');
import { Fn, Stack, Token } from '../lib';
import { App, CfnOutput, Fn, Stack, Token } from '../lib';
import { Intrinsic } from '../lib/private/intrinsic';

function asyncTest(cb: (test: nodeunit.Test) => Promise<void>): (test: nodeunit.Test) => void {
Expand Down Expand Up @@ -139,6 +139,34 @@ export = nodeunit.testCase({
]
});
}),

'cross-stack FnJoin elements are properly resolved': asyncTest(async (test) => {
// GIVEN
const app = new App();
const stack1 = new Stack(app, 'Stack1');
const stack2 = new Stack(app, 'Stack2');

// WHEN
new CfnOutput(stack2, 'Stack1Id', {
value: Fn.join(' = ', [ 'Stack1Id', stack1.stackId ])
});

// THEN
const template = app.synth().getStack('Stack2').template;

test.deepEqual(template, {
Outputs: {
Stack1Id: {
Value: {
'Fn::Join': [' = ', [
'Stack1Id',
{ 'Fn::ImportValue': 'Stack1:ExportsOutputRefAWSStackIdB2DD5BAA' }
]]
}
}
}
});
}),
},
});

Expand Down

0 comments on commit 0a2540b

Please sign in to comment.