diff --git a/packages/@aws-cdk/cdk/lib/stack.ts b/packages/@aws-cdk/cdk/lib/stack.ts index 25452e6e1d991..fae7728df7f73 100644 --- a/packages/@aws-cdk/cdk/lib/stack.ts +++ b/packages/@aws-cdk/cdk/lib/stack.ts @@ -22,6 +22,11 @@ export interface StackProps { * Optional. If not supplied, the HashedNamingScheme will be used. */ namingScheme?: IAddressingScheme; + + /** + * @default false + */ + ephemeral?: boolean; } /** @@ -79,6 +84,8 @@ export class Stack extends Construct { */ public readonly name: string; + public readonly ephemeral: boolean; + /* * Used to determine if this construct is a stack. */ @@ -113,6 +120,7 @@ export class Stack extends Construct { this.logicalIds = new LogicalIDs(props && props.namingScheme ? props.namingScheme : new HashedAddressingScheme()); this.name = this.node.id; + this.ephemeral = props && props.ephemeral === true ? true : false; } /** @@ -453,7 +461,8 @@ export class Stack extends Construct { environment: this.environment, properties: { templateFile: template, - } + }, + ephemeral: this.ephemeral, }; if (Object.keys(this.parameterValues).length > 0) { diff --git a/packages/@aws-cdk/cdk/lib/synthesis.ts b/packages/@aws-cdk/cdk/lib/synthesis.ts index 9b5d95d3ae1ae..271b81f2481aa 100644 --- a/packages/@aws-cdk/cdk/lib/synthesis.ts +++ b/packages/@aws-cdk/cdk/lib/synthesis.ts @@ -354,6 +354,7 @@ function renderLegacyStacks(artifacts: { [id: string]: cxapi.Artifact }, store: environment: { name: artifact.environment.substr('aws://'.length), account: match[1], region: match[2] }, template, metadata: artifact.metadata || {}, + ephemeral: artifact.ephemeral, }; if (artifact.dependencies && artifact.dependencies.length > 0) { @@ -369,4 +370,4 @@ function renderLegacyStacks(artifacts: { [id: string]: cxapi.Artifact }, store: } return stacks; -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/cx-api/lib/artifacts.ts b/packages/@aws-cdk/cx-api/lib/artifacts.ts index 133027dfe04b1..db80719575454 100644 --- a/packages/@aws-cdk/cx-api/lib/artifacts.ts +++ b/packages/@aws-cdk/cx-api/lib/artifacts.ts @@ -13,10 +13,11 @@ export interface Artifact { dependencies?: string[]; missing?: { [key: string]: any }; properties?: { [name: string]: any }; + ephemeral?: boolean; } export function validateArtifact(artifcat: Artifact) { if (!AWS_ENV_REGEX.test(artifcat.environment)) { throw new Error(`Artifact "environment" must conform to ${AWS_ENV_REGEX}: ${artifcat.environment}`); } -} \ No newline at end of file +} diff --git a/packages/@aws-cdk/cx-api/lib/cxapi.ts b/packages/@aws-cdk/cx-api/lib/cxapi.ts index 8bbbdcf9340bb..f7f0fe5095016 100644 --- a/packages/@aws-cdk/cx-api/lib/cxapi.ts +++ b/packages/@aws-cdk/cx-api/lib/cxapi.ts @@ -81,6 +81,7 @@ export interface SynthesizedStack { missing?: { [key: string]: MissingContext }; metadata: StackMetadata; template: any; + ephemeral?: boolean; /** * Other stacks this stack depends on diff --git a/packages/aws-cdk/lib/api/cxapp/stacks.ts b/packages/aws-cdk/lib/api/cxapp/stacks.ts index 7578717093553..6575346603e25 100644 --- a/packages/aws-cdk/lib/api/cxapp/stacks.ts +++ b/packages/aws-cdk/lib/api/cxapp/stacks.ts @@ -87,8 +87,10 @@ export class AppStacks { } if (selectors.length === 0) { - debug('Stack name not specified, so defaulting to all available stacks: ' + listStackNames(stacks)); - return this.applyRenames(stacks); + // filter out ephemeral Stacks + const nonEphemeralStacks = stacks.filter(s => s.ephemeral !== true); + debug('Stack name not specified, so defaulting to all available stacks: ' + listStackNames(nonEphemeralStacks)); + return this.applyRenames(nonEphemeralStacks); } const allStacks = new Map(); diff --git a/packages/aws-cdk/test/api/test.stacks.ts b/packages/aws-cdk/test/api/test.stacks.ts index 55aefd18d7a4d..d17eedbfb57d1 100644 --- a/packages/aws-cdk/test/api/test.stacks.ts +++ b/packages/aws-cdk/test/api/test.stacks.ts @@ -86,4 +86,62 @@ export = { test.done(); }, -}; \ No newline at end of file + + async 'does not return ephemeral Stacks when called without any selectors'(test: Test) { + // GIVEN + const result: cxapi.SynthesizeResponse = { + version: '1', + stacks: [ + { + name: 'EphemeralStack', + template: { resource: 'Resource' }, + environment: { name: 'dev', account: '12345', region: 'here' }, + metadata: {}, + ephemeral: true, + }, + ], + }; + const stacks = new AppStacks({ + configuration: new Configuration(), + aws: new SDK(), + synthesizer: async () => result, + }); + + // WHEN + const synthed = await stacks.selectStacks([], ExtendedStackSelection.None); + + // THEN + test.equal(synthed.length, 0); + + test.done(); + }, + + async 'does return ephemeral Stacks when called with selectors matching it'(test: Test) { + // GIVEN + const result: cxapi.SynthesizeResponse = { + version: '1', + stacks: [ + { + name: 'EphemeralStack', + template: { resource: 'Resource' }, + environment: { name: 'dev', account: '12345', region: 'here' }, + metadata: {}, + ephemeral: true, + }, + ], + }; + const stacks = new AppStacks({ + configuration: new Configuration(), + aws: new SDK(), + synthesizer: async () => result, + }); + + // WHEN + const synthed = await stacks.selectStacks(['EphemeralStack'], ExtendedStackSelection.None); + + // THEN + test.equal(synthed.length, 1); + + test.done(); + }, +};