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

feat(cli): --all flag to select all stacks #10745

8 changes: 8 additions & 0 deletions packages/aws-cdk/README.md
Expand Up @@ -140,6 +140,14 @@ currently deployed stack to the template and tags that are about to be deployed
will skip deployment if they are identical. Use `--force` to override this behavior
and always deploy the stack.

##### Deploying multiple stacks

You can have multiple stacks in a cdk app. An example can be found in [how to create multiple stacks](https://docs.aws.amazon.com/cdk/latest/guide/stack_how_to_create_multiple_stacks.html).

In order to deploy them, you can list the stacks you want to deploy.

If you want to deploy all of them, you can use the flag `--all` or the wildcard `*` to deploy all stacks in an app.

##### Parameters

Pass parameters to your template during deployment by using `--parameters
Expand Down
25 changes: 16 additions & 9 deletions packages/aws-cdk/bin/cdk.ts
Expand Up @@ -51,9 +51,9 @@ async function parseCommandLineArguments() {
.option('verbose', { type: 'boolean', alias: 'v', desc: 'Show debug logs (specify multiple times to increase verbosity)', default: false })
.count('verbose')
.option('profile', { type: 'string', desc: 'Use the indicated AWS profile as the default environment', requiresArg: true })
.option('proxy', { type: 'string', desc: 'Use the indicated proxy. Will read from HTTPS_PROXY environment variable if not specified.', requiresArg: true })
.option('ca-bundle-path', { type: 'string', desc: 'Path to CA certificate to use when validating HTTPS requests. Will read from AWS_CA_BUNDLE environment variable if not specified.', requiresArg: true })
.option('ec2creds', { type: 'boolean', alias: 'i', default: undefined, desc: 'Force trying to fetch EC2 instance credentials. Default: guess EC2 instance status.' })
.option('proxy', { type: 'string', desc: 'Use the indicated proxy. Will read from HTTPS_PROXY environment variable if not specified', requiresArg: true })
.option('ca-bundle-path', { type: 'string', desc: 'Path to CA certificate to use when validating HTTPS requests. Will read from AWS_CA_BUNDLE environment variable if not specified', requiresArg: true })
.option('ec2creds', { type: 'boolean', alias: 'i', default: undefined, desc: 'Force trying to fetch EC2 instance credentials. Default: guess EC2 instance status' })
.option('version-reporting', { type: 'boolean', desc: 'Include the "AWS::CDK::Metadata" resource in synthesized templates (enabled by default)', default: undefined })
.option('path-metadata', { type: 'boolean', desc: 'Include "aws:cdk:path" CloudFormation metadata for each resource (enabled by default)', default: true })
.option('asset-metadata', { type: 'boolean', desc: 'Include "aws:asset:*" CloudFormation metadata for resources that user assets (enabled by default)', default: true })
Expand All @@ -79,11 +79,12 @@ async function parseCommandLineArguments() {
.option('cloudformation-execution-policies', { type: 'array', desc: 'The Managed Policy ARNs that should be attached to the role performing deployments into this environment (may be repeated, modern bootstrapping only)', default: [], nargs: 1, requiresArg: true })
.option('force', { alias: 'f', type: 'boolean', desc: 'Always bootstrap even if it would downgrade template version', default: false })
.option('termination-protection', { type: 'boolean', default: undefined, desc: 'Toggle CloudFormation termination protection on the bootstrap stacks' })
.option('show-template', { type: 'boolean', desc: 'Instead of actual bootstrapping, print the current CLI\'s bootstrapping template to stdout for customization.', default: false })
.option('template', { type: 'string', requiresArg: true, desc: 'Use the template from the given file instead of the built-in one (use --show-template to obtain an example).' }),
.option('show-template', { type: 'boolean', desc: 'Instead of actual bootstrapping, print the current CLI\'s bootstrapping template to stdout for customization', default: false })
.option('template', { type: 'string', requiresArg: true, desc: 'Use the template from the given file instead of the built-in one (use --show-template to obtain an example)' }),
)
.command('deploy [STACKS..]', 'Deploys the stack(s) named STACKS into your AWS account', yargs => yargs
.option('build-exclude', { type: 'array', alias: 'E', nargs: 1, desc: 'Do not rebuild asset with the given ID. Can be specified multiple times.', default: [] })
.option('all', { type: 'boolean', default: false, desc: 'Deploy all available stacks' })
.option('build-exclude', { type: 'array', alias: 'E', nargs: 1, desc: 'Do not rebuild asset with the given ID. Can be specified multiple times', default: [] })
.option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only deploy requested stacks, don\'t include dependencies' })
.option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'What security-sensitive changes need manual approval' })
.option('ci', { type: 'boolean', desc: 'Force CI detection', default: process.env.CI !== undefined })
Expand All @@ -95,9 +96,10 @@ async function parseCommandLineArguments() {
.option('parameters', { type: 'array', desc: 'Additional parameters passed to CloudFormation at deploy time (STACK:KEY=VALUE)', nargs: 1, requiresArg: true, default: {} })
.option('outputs-file', { type: 'string', alias: 'O', desc: 'Path to file where stack outputs will be written as JSON', requiresArg: true })
.option('previous-parameters', { type: 'boolean', default: true, desc: 'Use previous values for existing parameters (you must specify all parameters on every deployment if this is disabled)' })
.option('progress', { type: 'string', choices: [StackActivityProgress.BAR, StackActivityProgress.EVENTS], desc: 'Display mode for stack activity events.' }),
.option('progress', { type: 'string', choices: [StackActivityProgress.BAR, StackActivityProgress.EVENTS], desc: 'Display mode for stack activity events' }),
)
.command('destroy [STACKS..]', 'Destroy the stack(s) named STACKS', yargs => yargs
.option('all', { type: 'boolean', default: false, desc: 'Destroy all available stacks' })
.option('exclusively', { type: 'boolean', alias: 'e', desc: 'Only destroy requested stacks, don\'t include dependees' })
.option('force', { type: 'boolean', alias: 'f', desc: 'Do not ask for confirmation before destroying the stacks' }))
.command('diff [STACKS..]', 'Compares the specified stack with the deployed stack or a local template file, and returns with status 1 if any difference is found', yargs => yargs
Expand Down Expand Up @@ -210,9 +212,14 @@ async function initCommandLine() {
const toolkitStackName: string = ToolkitInfo.determineName(configuration.settings.get(['toolkitStackName']));
debug(`Toolkit stack: ${colors.bold(toolkitStackName)}`);

if (args.all && args.STACKS) {
throw new Error('You must either specify a list of Stacks or the `--all` argument');
}

args.STACKS = args.STACKS || [];
args.ENVIRONMENTS = args.ENVIRONMENTS || [];

const stacks = (args.all) ? ['*'] : args.STACKS;
const cli = new CdkToolkit({
cloudExecutable,
cloudFormation,
Expand Down Expand Up @@ -292,7 +299,7 @@ async function initCommandLine() {
}
}
return cli.deploy({
stackNames: args.STACKS,
stackNames: stacks,
exclusively: args.exclusively,
toolkitStackName,
roleArn: args.roleArn,
Expand All @@ -311,7 +318,7 @@ async function initCommandLine() {

case 'destroy':
return cli.destroy({
stackNames: args.STACKS,
stackNames: stacks,
exclusively: args.exclusively,
force: args.force,
roleArn: args.roleArn,
Expand Down
2 changes: 1 addition & 1 deletion packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts
Expand Up @@ -86,7 +86,7 @@ export class CloudAssembly {
if (stacks.length === 1) {
return new StackCollection(this, stacks);
} else {
throw new Error('Since this app includes more than a single stack, specify which stacks to use (wildcards are supported)\n' +
throw new Error('Since this app includes more than a single stack, specify which stacks to use (wildcards are supported) or specify `--all`\n' +
`Stacks: ${stacks.map(x => x.id).join(' ')}`);
}
default:
Expand Down
2 changes: 1 addition & 1 deletion packages/aws-cdk/test/api/cloud-assembly.test.ts
Expand Up @@ -57,7 +57,7 @@ test('select behavior: single', async () => {

// WHEN
await expect(cxasm.selectStacks([], { defaultBehavior: DefaultSelection.OnlySingle }))
.rejects.toThrow('Since this app includes more than a single stack, specify which stacks to use (wildcards are supported)');
.rejects.toThrow('Since this app includes more than a single stack, specify which stacks to use (wildcards are supported) or specify `--all`');
});

test('select behavior: repeat', async () => {
Expand Down
16 changes: 16 additions & 0 deletions packages/aws-cdk/test/cdk-toolkit.test.ts
Expand Up @@ -44,6 +44,22 @@ describe('deploy', () => {
await toolkit.deploy({ stackNames: ['Test-Stack-A', 'Test-Stack-B'] });
});

test('with one stack specified', async () => {
// GIVEN
const toolkit = defaultToolkitSetup();

// WHEN
await toolkit.deploy({ stackNames: ['Test-Stack-A'] });
});

test('with stacks all stacks specified as wildcard', async () => {
// GIVEN
const toolkit = defaultToolkitSetup();

// WHEN
await toolkit.deploy({ stackNames: ['*'] });
});

test('with sns notification arns', async () => {
// GIVEN
const notificationArns = ['arn:aws:sns:::cfn-notifications', 'arn:aws:sns:::my-cool-topic'];
Expand Down