From 336d096558c4c7b24402bba8d7b438217bba671a Mon Sep 17 00:00:00 2001 From: mrgrain Date: Mon, 26 Oct 2020 12:23:11 +0000 Subject: [PATCH] fix(core): make Stage compatible to instances from other copies of code A recent change surfaces an issue where Stage objects from different code copies don't recognize each other as a Stage. This paht aligns the way how a Stage determines if something is a Stage to the same mechanism that App and Stack use. Thanks to @Shogan and @jogold to narrowing the issue down fixes #10314 --- packages/@aws-cdk/core/lib/stage.ts | 6 ++++- packages/@aws-cdk/core/test/stage.test.ts | 29 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/core/lib/stage.ts b/packages/@aws-cdk/core/lib/stage.ts index 072a4b9cc34c3..8dfa18834604c 100644 --- a/packages/@aws-cdk/core/lib/stage.ts +++ b/packages/@aws-cdk/core/lib/stage.ts @@ -7,6 +7,8 @@ import { synthesize } from './private/synthesis'; // eslint-disable-next-line import { Construct as CoreConstruct } from './construct-compat'; +const STAGE_SYMBOL = Symbol.for('@aws-cdk/core.Stage'); + /** * Initialization props for a stage. */ @@ -85,7 +87,7 @@ export class Stage extends CoreConstruct { * @experimental */ public static isStage(x: any ): x is Stage { - return x !== null && x instanceof Stage; + return x !== null && typeof(x) === 'object' && STAGE_SYMBOL in x; } /** @@ -137,6 +139,8 @@ export class Stage extends CoreConstruct { throw new Error(`invalid stage name "${id}". Stage name must start with a letter and contain only alphanumeric characters, hypens ('-'), underscores ('_') and periods ('.')`); } + Object.defineProperty(this, STAGE_SYMBOL, { value: true }); + this.parentStage = Stage.of(this); this.region = props.env?.region ?? this.parentStage?.region; diff --git a/packages/@aws-cdk/core/test/stage.test.ts b/packages/@aws-cdk/core/test/stage.test.ts index c878c1485d6ce..8a4b27a4d412a 100644 --- a/packages/@aws-cdk/core/test/stage.test.ts +++ b/packages/@aws-cdk/core/test/stage.test.ts @@ -280,6 +280,35 @@ nodeunitShim({ test.throws(() => new Stage(app, 'mystage', { outdir: '/tmp/foo/bar' }), /"outdir" cannot be specified for nested stages/); test.done(); }, + + 'Stage.isStage indicates that a construct is a stage'(test: Test) { + // WHEN + const app = new App(); + const stack = new Stack(); + const stage = new Stage(app, 'Stage'); + + // THEN + test.ok(Stage.isStage(stage)); + test.ok(Stage.isStage(app)); + test.ok(!Stage.isStage(stack)); + test.done(); + }, + + 'Stage.isStage indicates that a construct is a stage based on symbol'(test: Test) { + // WHEN + const app = new App(); + const stage = new Stage(app, 'Stage'); + + const externalStage = {}; + const STAGE_SYMBOL = Symbol.for('@aws-cdk/core.Stage'); + Object.defineProperty(externalStage, STAGE_SYMBOL, { value: true }); + + // THEN + test.ok(Stage.isStage(stage)); + test.ok(Stage.isStage(app)); + test.ok(Stage.isStage(externalStage)); + test.done(); + }, }); class TouchingAspect implements IAspect {