Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core): misc cleanups to App-related APIs #2731

Merged
merged 20 commits into from
Jun 5, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/@aws-cdk/assert/lib/inspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ export class StackPathInspector extends Inspector {
// The names of paths in metadata in tests are very ill-defined. Try with the full path first,
// then try with the stack name preprended for backwards compat with most tests that happen to give
// their stack an ID that's the same as the stack name.
const md = this.stack.metadata[this.path] || this.stack.metadata[`/${this.stack.name}${this.path}`];
const metadata = this.stack.manifest.metadata || {};
const md = metadata[this.path] || metadata[`/${this.stack.name}${this.path}`];
if (md === undefined) { return undefined; }
const resourceMd = md.find(entry => entry.type === 'aws:cdk:logicalId');
const resourceMd = md.find(entry => entry.type === api.LOGICAL_ID_METADATA_KEY);
if (resourceMd === undefined) { return undefined; }
const logicalId = resourceMd.data;
return this.stack.template.Resources[logicalId];
Expand Down
9 changes: 5 additions & 4 deletions packages/@aws-cdk/assets/lib/staging.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Construct } from '@aws-cdk/cdk';
import { Construct, ISynthesisSession, ISynthesizable } from '@aws-cdk/cdk';
import cxapi = require('@aws-cdk/cx-api');
import fs = require('fs');
import path = require('path');
Expand Down Expand Up @@ -26,7 +26,7 @@ export interface StagingProps extends CopyOptions {
* The file/directory are staged based on their content hash (fingerprint). This
* means that only if content was changed, copy will happen.
*/
export class Staging extends Construct {
export class Staging extends Construct implements ISynthesizable {

/**
* The path to the asset (stringinfied token).
Expand Down Expand Up @@ -66,12 +66,13 @@ export class Staging extends Construct {
}
}

protected synthesize(session: cxapi.CloudAssemblyBuilder) {
public synthesize(session: ISynthesisSession) {
const assembly = session.assembly;
eladb marked this conversation as resolved.
Show resolved Hide resolved
if (!this.relativePath) {
return;
}

const targetPath = path.join(session.outdir, this.relativePath);
const targetPath = path.join(assembly.outdir, this.relativePath);

// asset already staged
if (fs.existsSync(targetPath)) {
Expand Down
5 changes: 3 additions & 2 deletions packages/@aws-cdk/assets/test/test.asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ export = {
});

const synth = app.run().getStack(stack.name);
test.deepEqual(synth.metadata['/my-stack/MyAsset'][0].data, {
const meta = synth.manifest.metadata || {};
test.deepEqual(meta['/my-stack/MyAsset'][0].data, {
eladb marked this conversation as resolved.
Show resolved Hide resolved
path: 'asset.6b84b87243a4a01c592d78e1fd3855c4bfef39328cd0a450cc97e81717fea2a2',
id: "mystackMyAssetD6B1B593",
packaging: "zip",
Expand Down Expand Up @@ -343,7 +344,7 @@ export = {
const session = app.run();
const artifact = session.getStack(stack.name);

const md = Object.values(artifact.metadata)[0][0].data;
const md = Object.values(artifact.manifest.metadata || {})[0][0].data;
eladb marked this conversation as resolved.
Show resolved Hide resolved
test.deepEqual(md.path, 'asset.6b84b87243a4a01c592d78e1fd3855c4bfef39328cd0a450cc97e81717fea2a2');
test.done();
}
Expand Down
48 changes: 33 additions & 15 deletions packages/@aws-cdk/cdk/lib/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { Synthesizer } from './synthesis';
const APP_SYMBOL = Symbol.for('@aws-cdk/cdk.App');

/**
* Custom construction properties for a CDK program
* Initialization props for apps.
*/
export interface AppProps {
/**
* Automatically call run before the application exits
*
* If you set this, you don't have to call `run()` anymore.
*
* @default true if running via CDK toolkit (CDK_OUTDIR is set), false otherwise
* @default true if running via CDK toolkit (`CDK_OUTDIR` is set), false otherwise
*/
readonly autoRun?: boolean;

Expand All @@ -29,29 +29,48 @@ export interface AppProps {

/**
* Include stack traces in construct metadata entries.
* @default true stack traces are included
* @default true stack traces are included unless `aws:cdk:disable-stack-trace` is set in the context.
RomainMuller marked this conversation as resolved.
Show resolved Hide resolved
*/
readonly stackTraces?: boolean;

/**
* Include runtime versioning information in cloud assembly manifest
* @default true runtime info is included
* @default true runtime info is included unless `aws:cdk:disable-runtime-info` is set in the context.
*/
readonly runtimeInfo?: boolean;

/**
* Additional context values for the application
* Additional context values for the application.
*
* @default No additional context
* Context can be read from any construct using `node.getContext(key)`.
*
* @default - no additional context
*/
readonly context?: { [key: string]: string };
}

/**
* Represents a CDK program.
* A construct which represents an entire CDK app. This construct is normally
* the root of the construct tree.
*
* You would normally define an `App` instance in your program's entrypoint,
* then define constructs where the app is used as the parent scope.
*
* After all the child constructs are defined within the app, you should call
* `app.synth()` which will emit a "cloud assembly" from this app into the
RomainMuller marked this conversation as resolved.
Show resolved Hide resolved
* directory specified by `outdir`. Cloud assemblies includes artifacts such as
* CloudFormation templates and assets that are needed to deploy this app into
* the AWS cloud.
*
* @see https://docs.aws.amazon.com/cdk/latest/guide/apps_and_stacks.html
*/
export class App extends Construct {

/**
* Checks if an object is an instance of the `App` class.
* @returns `true` if `obj` is an `App`.
* @param obj The object to evaluate
*/
public static isApp(obj: any): obj is App {
return APP_SYMBOL in obj;
}
Expand All @@ -62,7 +81,7 @@ export class App extends Construct {

/**
* Initializes a CDK application.
* @param request Optional toolkit request (e.g. for tests)
* @param props initialization properties
*/
constructor(props: AppProps = {}) {
super(undefined as any, '');
Expand All @@ -84,20 +103,19 @@ export class App extends Construct {
this.outdir = props.outdir || process.env[cxapi.OUTDIR_ENV];

const autoRun = props.autoRun !== undefined ? props.autoRun : cxapi.OUTDIR_ENV in process.env;

if (autoRun) {
// run() guarantuees it will only execute once, so a default of 'true' doesn't bite manual calling
// of the function.
// run() guarantuees it will only execute once, so a default of 'true'
// doesn't bite manual calling of the function.
process.once('beforeExit', () => this.run());
}
}

/**
* Runs the program. Output is written to output directory as specified in the
* request.
* Synthesizes a cloud assembly for this app. Emits it to the directory
* specified by `outdir`.
*
* @returns a `CloudAssembly` which includes all the synthesized artifacts
* such as CloudFormation templates and assets.
* @returns a `CloudAssembly` which can be used to inspect synthesized
* artifacts such as CloudFormation templates and assets.
*/
public run(): CloudAssembly {
// this app has already been executed, no-op for you
Expand Down
7 changes: 3 additions & 4 deletions packages/@aws-cdk/cdk/lib/cfn-element.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import cxapi = require('@aws-cdk/cx-api');
import { Construct, IConstruct, PATH_SEP } from "./construct";
import { Token } from './token';

const LOGICAL_ID_MD = 'aws:cdk:logicalId';

/**
* An element of a CloudFormation stack.
*/
Expand Down Expand Up @@ -43,7 +42,7 @@ export abstract class CfnElement extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);

this.node.addMetadata(LOGICAL_ID_MD, new (require("./token").Token)(() => this.logicalId), this.constructor);
this.node.addMetadata(cxapi.LOGICAL_ID_METADATA_KEY, new (require("./token").Token)(() => this.logicalId), this.constructor);

this._logicalId = this.node.stack.logicalIds.getLogicalId(this);
this.logicalId = new Token(() => this._logicalId, `${notTooLong(this.node.path)}.LogicalID`).toString();
Expand All @@ -63,7 +62,7 @@ export abstract class CfnElement extends Construct {
* node +internal+ entries filtered.
*/
public get creationStackTrace(): string[] | undefined {
const trace = this.node.metadata.find(md => md.type === LOGICAL_ID_MD)!.trace;
const trace = this.node.metadata.find(md => md.type === cxapi.LOGICAL_ID_METADATA_KEY)!.trace;
if (!trace) {
return undefined;
}
Expand Down
41 changes: 23 additions & 18 deletions packages/@aws-cdk/cdk/lib/stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { CfnParameter } from './cfn-parameter';
import { Construct, IConstruct, PATH_SEP } from './construct';
import { Environment } from './environment';
import { HashedAddressingScheme, IAddressingScheme, LogicalIDs } from './logical-id';
import { ISynthesisSession } from './synthesis';
import { makeUniqueId } from './uniqueid';

export interface StackProps {
/**
* The AWS environment (account/region) where this stack will be deployed.
Expand All @@ -31,15 +33,16 @@ export interface StackProps {
readonly namingScheme?: IAddressingScheme;

/**
* Should the Stack be deployed when running `cdk deploy` without arguments
* (and listed when running `cdk synth` without arguments).
* Setting this to `false` is useful when you have a Stack in your CDK app
* that you don't want to deploy using the CDK toolkit -
* for example, because you're planning on deploying it through CodePipeline.
* Indicates if this stack is hidden, which means that it won't be
eladb marked this conversation as resolved.
Show resolved Hide resolved
* automatically deployed when running `cdk deploy` without arguments.
*
* Setting this to `true` is useful when you have a stack in your CDK app
* which you don't want to deploy using the CDK toolkit. For example, because
* you're planning on deploying it through a deployment pipeline.
*
* @default true
* @default false
*/
readonly autoDeploy?: boolean;
readonly hidden?: boolean;

/**
* Stack tags that will be applied to all the taggable resources and the stack itself.
Expand Down Expand Up @@ -116,15 +119,16 @@ export class Stack extends Construct implements ITaggable {
public readonly name: string;

/**
* Should the Stack be deployed when running `cdk deploy` without arguments
* (and listed when running `cdk synth` without arguments).
* Setting this to `false` is useful when you have a Stack in your CDK app
* that you don't want to deploy using the CDK toolkit -
* for example, because you're planning on deploying it through CodePipeline.
* Indicates if this stack is hidden, which means that it won't be
* automatically deployed when running `cdk deploy` without arguments.
*
* Setting this to `true` is useful when you have a stack in your CDK app
* which you don't want to deploy using the CDK toolkit. For example, because
* you're planning on deploying it through a deployment pipeline.
*
* By default, this is `true`.
* By default, all stacks are visible (this will be false).
eladb marked this conversation as resolved.
Show resolved Hide resolved
*/
public readonly autoDeploy: boolean;
public readonly hidden: boolean;

/**
* Other stacks this stack depends on
Expand Down Expand Up @@ -159,9 +163,9 @@ export class Stack extends Construct implements ITaggable {
this.configuredEnv = props.env || {};
this.env = this.parseEnvironment(props.env);

this.logicalIds = new LogicalIDs(props && props.namingScheme ? props.namingScheme : new HashedAddressingScheme());
this.logicalIds = new LogicalIDs(props.namingScheme ? props.namingScheme : new HashedAddressingScheme());
this.name = props.stackName !== undefined ? props.stackName : this.calculateStackName();
this.autoDeploy = props && props.autoDeploy === false ? false : true;
this.hidden = props.hidden === undefined ? false : true;
this.tags = new TagManager(TagType.KeyValue, "aws:cdk:stack", props.tags);

if (!Stack.VALID_STACK_NAME_REGEX.test(this.name)) {
Expand Down Expand Up @@ -509,7 +513,8 @@ export class Stack extends Construct implements ITaggable {
}
}

protected synthesize(builder: cxapi.CloudAssemblyBuilder): void {
protected synthesize(session: ISynthesisSession): void {
const builder = session.assembly;
const template = `${this.name}.template.json`;

// write the CloudFormation template as a JSON file
Expand All @@ -529,7 +534,7 @@ export class Stack extends Construct implements ITaggable {
type: cxapi.ArtifactType.AwsCloudFormationStack,
environment: this.environment,
properties,
autoDeploy: this.autoDeploy ? undefined : false,
hidden: this.hidden ? true : undefined, // omit if stack is visible
dependencies: deps.length > 0 ? deps : undefined,
metadata: Object.keys(meta).length > 0 ? meta : undefined,
missing: this.missingContext && Object.keys(this.missingContext).length > 0 ? this.missingContext : undefined
Expand Down
15 changes: 11 additions & 4 deletions packages/@aws-cdk/cdk/lib/synthesis.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { BuildOptions, CloudAssembly, CloudAssemblyBuilder } from '@aws-cdk/cx-api';
import { ConstructOrder, IConstruct } from './construct';

export interface ISynthesisSession {
eladb marked this conversation as resolved.
Show resolved Hide resolved
/**
* The cloud assembly being synthesized.
*/
assembly: CloudAssemblyBuilder;
}

export interface ISynthesizable {
synthesize(session: CloudAssemblyBuilder): void;
synthesize(session: ISynthesisSession): void;
}

export interface SynthesisOptions extends BuildOptions {
Expand All @@ -21,7 +28,7 @@ export interface SynthesisOptions extends BuildOptions {

export class Synthesizer {
public synthesize(root: IConstruct, options: SynthesisOptions = { }): CloudAssembly {
const session = new CloudAssemblyBuilder(options.outdir);
const builder = new CloudAssemblyBuilder(options.outdir);

// the three holy phases of synthesis: prepare, validate and synthesize

Expand All @@ -41,12 +48,12 @@ export class Synthesizer {
// synthesize (leaves first)
for (const c of root.node.findAll(ConstructOrder.PostOrder)) {
if (isSynthesizable(c)) {
c.synthesize(session);
c.synthesize({ assembly: builder });
}
}

// write session manifest and lock store
return session.build(options);
return builder.build(options);
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/cdk/test/test.app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export = {
test.deepEqual(stack1.template, { Resources:
{ s1c1: { Type: 'DummyResource', Properties: { Prop1: 'Prop1' } },
s1c2: { Type: 'DummyResource', Properties: { Foo: 123 } } } });
test.deepEqual(stack1.metadata, {
test.deepEqual(stack1.manifest.metadata, {
'/stack1': [{ type: 'meta', data: 111 }],
'/stack1/s1c1': [{ type: 'aws:cdk:logicalId', data: 's1c1' }],
'/stack1/s1c2':
Expand All @@ -77,7 +77,7 @@ export = {
{ s2c1: { Type: 'DummyResource', Properties: { Prog2: 'Prog2' } },
s1c2r1D1791C01: { Type: 'ResourceType1' },
s1c2r25F685FFF: { Type: 'ResourceType2' } } });
test.deepEqual(stack2.metadata, {
test.deepEqual(stack2.manifest.metadata, {
'/stack2/s2c1': [{ type: 'aws:cdk:logicalId', data: 's2c1' }],
'/stack2/s1c2': [{ type: 'meta', data: { key: 'value' } }],
'/stack2/s1c2/r1':
Expand Down Expand Up @@ -193,7 +193,7 @@ export = {
new MyStack(app, 'MyStack');
});

test.deepEqual(response.stacks[0].missing, {
test.deepEqual(response.missing, {
"missing-context-key": {
provider: 'fake',
props: {
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/cdk/test/test.context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export = {

const assembly = app.run();
const output = assembly.getStack('test-stack');
const metadata = output.metadata;
const metadata = output.manifest.metadata || {};
const azError: cxapi.MetadataEntry | undefined = metadata['/test-stack'].find(x => x.type === cxapi.ERROR_METADATA_KEY);
const ssmError: cxapi.MetadataEntry | undefined = metadata['/test-stack/ChildConstruct'].find(x => x.type === cxapi.ERROR_METADATA_KEY);

Expand Down
Loading