From e017f825e48c52b5c625559ed7ec6dc6a23a29cb Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Fri, 15 Dec 2023 11:02:14 -0600 Subject: [PATCH 1/8] feat(cli): add option to ignore no stacks --- .../aws-cdk/lib/api/cxapp/cloud-assembly.ts | 11 +++++++++-- packages/aws-cdk/lib/api/deploy-stack.ts | 7 +++++++ packages/aws-cdk/lib/api/deployments.ts | 7 +++++++ packages/aws-cdk/lib/cdk-toolkit.ts | 17 ++++++++++++++--- packages/aws-cdk/lib/cli.ts | 4 +++- packages/aws-cdk/lib/settings.ts | 1 + .../aws-cdk/test/api/cloud-assembly.test.ts | 8 ++++++++ 7 files changed, 49 insertions(+), 6 deletions(-) diff --git a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts index 84cfa775e0cf7..c2efeda10dce4 100644 --- a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts +++ b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts @@ -38,9 +38,16 @@ export interface SelectStacksOptions { extend?: ExtendedStackSelection; /** - * The behavior if if no selectors are privided. + * The behavior if if no selectors are provided. */ defaultBehavior: DefaultSelection; + + /** + * Ignore the error message if the app contains no stacks. + * + * @default false + */ + ignoreNoStacks?: boolean; } /** @@ -99,7 +106,7 @@ export class CloudAssembly { const allTopLevel = selector.allTopLevel ?? false; const patterns = sanitizePatterns(selector.patterns); - if (stacks.length === 0) { + if (stacks.length === 0 && !options.ignoreNoStacks) { throw new Error('This app contains no stacks'); } diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 02d1d7b0f0324..2db9ffda5d51f 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -205,6 +205,13 @@ export interface DeployStackOptions { * @default true To remain backward compatible. */ readonly assetParallelism?: boolean; + + /** + * Ignore the error message if the app contains no stacks. + * + * @default false + */ + ignoreNoStacks?: boolean; } export type DeploymentMethod = diff --git a/packages/aws-cdk/lib/api/deployments.ts b/packages/aws-cdk/lib/api/deployments.ts index e6c2254c70ebb..ffbd72b8af244 100644 --- a/packages/aws-cdk/lib/api/deployments.ts +++ b/packages/aws-cdk/lib/api/deployments.ts @@ -198,6 +198,13 @@ export interface DeployStackOptions { * @default true To remain backward compatible. */ readonly assetParallelism?: boolean; + + /** + * Ignore the error message if the app contains no stacks. + * + * @default false + */ + ignoreNoStacks?: boolean; } interface AssetOptions { diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index d2faab3a274c9..7f5b001a8d87e 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -175,7 +175,8 @@ export class CdkToolkit { } const startSynthTime = new Date().getTime(); - const stackCollection = await this.selectStacksForDeploy(options.selector, options.exclusively, options.cacheCloudAssembly); + // eslint-disable-next-line max-len + const stackCollection = await this.selectStacksForDeploy(options.selector, options.exclusively, options.cacheCloudAssembly, options.ignoreNoStacks); const elapsedSynthTime = new Date().getTime() - startSynthTime; print('\n✨ Synthesis time: %ss\n', formatTime(elapsedSynthTime)); @@ -305,6 +306,7 @@ export class CdkToolkit { hotswap: options.hotswap, extraUserAgent: options.extraUserAgent, assetParallelism: options.assetParallelism, + ignoreNoStacks: options.ignoreNoStacks, }); const message = result.noOp @@ -479,7 +481,7 @@ export class CdkToolkit { } public async import(options: ImportOptions) { - const stacks = await this.selectStacksForDeploy(options.selector, true, true); + const stacks = await this.selectStacksForDeploy(options.selector, true, true, false); if (stacks.stackCount > 1) { throw new Error(`Stack selection is ambiguous, please choose a specific stack for import [${stacks.stackArtifacts.map(x => x.id).join(', ')}]`); @@ -729,11 +731,13 @@ export class CdkToolkit { return stacks; } - private async selectStacksForDeploy(selector: StackSelector, exclusively?: boolean, cacheCloudAssembly?: boolean): Promise { + // eslint-disable-next-line max-len + private async selectStacksForDeploy(selector: StackSelector, exclusively?: boolean, cacheCloudAssembly?: boolean, ignoreNoStacks?: boolean): Promise { const assembly = await this.assembly(cacheCloudAssembly); const stacks = await assembly.selectStacks(selector, { extend: exclusively ? ExtendedStackSelection.None : ExtendedStackSelection.Upstream, defaultBehavior: DefaultSelection.OnlySingle, + ignoreNoStacks, }); this.validateStacksSelected(stacks, selector.patterns); @@ -1134,6 +1138,13 @@ export interface DeployOptions extends CfnDeployOptions, WatchOptions { * @default AssetBuildTime.ALL_BEFORE_DEPLOY */ readonly assetBuildTime?: AssetBuildTime; + + /** + * Ignore the error message if the app contains no stacks. + * + * @default false + */ + readonly ignoreNoStacks?: boolean; } export interface ImportOptions extends CfnDeployOptions { diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index 85e3bdaaf4996..03ecc4480b826 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -172,7 +172,8 @@ async function parseCommandLineArguments(args: string[]) { }) .option('concurrency', { type: 'number', desc: 'Maximum number of simultaneous deployments (dependency permitting) to execute.', default: 1, requiresArg: true }) .option('asset-parallelism', { type: 'boolean', desc: 'Whether to build/publish assets in parallel' }) - .option('asset-prebuild', { type: 'boolean', desc: 'Whether to build all assets before deploying the first stack (useful for failing Docker builds)', default: true }), + .option('asset-prebuild', { type: 'boolean', desc: 'Whether to build all assets before deploying the first stack (useful for failing Docker builds)', default: true }) + .option('ignore-no-stacks', { type: 'boolean', desc: 'Ignore the error message if the app contains no stacks', default: false }), ) .command('import [STACK]', 'Import existing resource(s) into the given STACK', (yargs: Argv) => yargs .option('execute', { type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true }) @@ -583,6 +584,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise Date: Sat, 16 Dec 2023 14:41:20 -0600 Subject: [PATCH 2/8] add tests --- .../cli-integ/lib/with-cli-no-stacks.ts | 134 ++++++++++++++++++ .../cli-integ/resources/cdk-apps/app/app.js | 6 + .../resources/cdk-apps/no-stack-app/app.js | 11 ++ .../resources/cdk-apps/no-stack-app/cdk.json | 7 + .../cli-integ-tests/cli-lib.integtest.ts | 22 +++ .../tests/cli-integ-tests/cli.integtest.ts | 25 ++++ packages/aws-cdk/README.md | 14 ++ .../aws-cdk/lib/api/cxapp/cloud-assembly.ts | 8 +- .../aws-cdk/test/api/cloud-assembly.test.ts | 32 +++++ 9 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts create mode 100755 packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js create mode 100644 packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/cdk.json diff --git a/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts b/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts new file mode 100644 index 0000000000000..625af386db31a --- /dev/null +++ b/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts @@ -0,0 +1,134 @@ +import * as os from 'os'; +import * as path from 'path'; +import { TestContext } from './integ-test'; +import { RESOURCES_DIR } from './resources'; +import { AwsContext, withAws } from './with-aws'; +import { cloneDirectory, installNpmPackages, TestFixture, DEFAULT_TEST_TIMEOUT_S, CdkCliOptions } from './with-cdk-app'; +import { withTimeout } from './with-timeout'; + +/** + * Higher order function to execute a block with a CliLib Integration CDK app fixture + */ +export function withCliLibIntegrationCdkApp(block: (context: CliLibIntegrationTestFixture) => Promise) { + return async (context: A) => { + const randy = context.randomString; + const stackNamePrefix = `cdktest-${randy}`; + const integTestDir = path.join(os.tmpdir(), `cdk-integ-${randy}`); + + context.log(` Stack prefix: ${stackNamePrefix}\n`); + context.log(` Test directory: ${integTestDir}\n`); + context.log(` Region: ${context.aws.region}\n`); + + await cloneDirectory(path.join(RESOURCES_DIR, 'cdk-apps', 'no-stack-app'), integTestDir, context.output); + const fixture = new CliLibIntegrationTestFixture( + integTestDir, + stackNamePrefix, + context.output, + context.aws, + context.randomString); + + let success = true; + try { + const installationVersion = fixture.packages.requestedFrameworkVersion(); + + if (fixture.packages.majorVersion() === '1') { + throw new Error('This test suite is only compatible with AWS CDK v2'); + } + + const alphaInstallationVersion = fixture.packages.requestedAlphaVersion(); + await installNpmPackages(fixture, { + 'aws-cdk-lib': installationVersion, + '@aws-cdk/cli-lib-alpha': alphaInstallationVersion, + '@aws-cdk/aws-lambda-go-alpha': alphaInstallationVersion, + '@aws-cdk/aws-lambda-python-alpha': alphaInstallationVersion, + 'constructs': '^10', + }); + + await block(fixture); + } catch (e: any) { + // We survive certain cases involving gopkg.in + if (errorCausedByGoPkg(e.message)) { + return; + } + success = false; + throw e; + } finally { + if (process.env.INTEG_NO_CLEAN) { + context.log(`Left test directory in '${integTestDir}' ($INTEG_NO_CLEAN)\n`); + } else { + await fixture.dispose(success); + } + } + }; +} + +/** + * Return whether or not the error is being caused by gopkg.in being down + * + * Our Go build depends on https://gopkg.in/, which has errors pretty often + * (every couple of days). It is run by a single volunteer. + */ +function errorCausedByGoPkg(error: string) { + // The error is different depending on what request fails. Messages recognized: + //////////////////////////////////////////////////////////////////// + // go: github.com/aws/aws-lambda-go@v1.28.0 requires + // gopkg.in/yaml.v3@v3.0.0-20200615113413-eeeca48fe776: invalid version: git ls-remote -q origin in /go/pkg/mod/cache/vcs/0901dc1ef67fcce1c9b3ae51078740de4a0e2dc673e720584ac302973af82f36: exit status 128: + // remote: Cannot obtain refs from GitHub: cannot talk to GitHub: Get https://github.com/go-yaml/yaml.git/info/refs?service=git-upload-pack: net/http: request canceled (Client.Timeout exceeded while awaiting headers) + // fatal: unable to access 'https://gopkg.in/yaml.v3/': The requested URL returned error: 502 + //////////////////////////////////////////////////////////////////// + // go: downloading github.com/aws/aws-lambda-go v1.28.0 + // go: github.com/aws/aws-lambda-go@v1.28.0 requires + // gopkg.in/yaml.v3@v3.0.0-20200615113413-eeeca48fe776: unrecognized import path "gopkg.in/yaml.v3": reading https://gopkg.in/yaml.v3?go-get=1: 502 Bad Gateway + // server response: Cannot obtain refs from GitHub: cannot talk to GitHub: Get https://github.com/go-yaml/yaml.git/info/refs?service=git-upload-pack: net/http: request canceled (Client.Timeout exceeded while awaiting headers) + //////////////////////////////////////////////////////////////////// + // go: github.com/aws/aws-lambda-go@v1.28.0 requires + // gopkg.in/yaml.v3@v3.0.0-20200615113413-eeeca48fe776: invalid version: git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /go/pkg/mod/cache/vcs/0901dc1ef67fcce1c9b3ae51078740de4a0e2dc673e720584ac302973af82f36: exit status 128: + // error: RPC failed; HTTP 502 curl 22 The requested URL returned error: 502 + // fatal: the remote end hung up unexpectedly + //////////////////////////////////////////////////////////////////// + + return (error.includes('gopkg\.in.*invalid version.*exit status 128') + || error.match(/unrecognized import path[^\n]gopkg\.in/)); +} + +/** + * SAM Integration test fixture for CDK - SAM integration test cases + */ +export function withCliLibFixture(block: (context: CliLibIntegrationTestFixture) => Promise) { + return withAws(withTimeout(DEFAULT_TEST_TIMEOUT_S, withCliLibIntegrationCdkApp(block))); +} + +export class CliLibIntegrationTestFixture extends TestFixture { + /** + * + */ + public async cdk(args: string[], options: CdkCliOptions = {}) { + const action = args[0]; + const stackName = args[1]; + + const cliOpts: Record = { + stacks: stackName ? [stackName] : undefined, + }; + + if (action === 'deploy') { + cliOpts.requireApproval = options.neverRequireApproval ? 'never' : 'broadening'; + } + + return this.shell(['node', '--input-type=module', `<<__EOS__ + import { AwsCdkCli } from '@aws-cdk/cli-lib-alpha'; + const cli = AwsCdkCli.fromCdkAppDirectory(); + + await cli.${action}(${JSON.stringify(cliOpts)}); +__EOS__`], { + ...options, + modEnv: { + AWS_REGION: this.aws.region, + AWS_DEFAULT_REGION: this.aws.region, + STACK_NAME_PREFIX: this.stackNamePrefix, + PACKAGE_LAYOUT_VERSION: this.packages.majorVersion(), + ...options.modEnv, + }, + }); + } + +} diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js index 048e6fabd5165..322b828baf3f1 100755 --- a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js +++ b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js @@ -403,6 +403,8 @@ class BuiltinLambdaStack extends cdk.Stack { } } +class StackWithNoResources extends cdk.Stack {} + const app = new cdk.App({ context: { '@aws-cdk/core:assetHashSalt': process.env.CODEBUILD_BUILD_ID, // Force all assets to be unique, but consistent in one build @@ -492,6 +494,10 @@ switch (stackSet) { stage.synth({ validateOnSynthesis: true }); break; + case 'stage-with-no-resources': + new StackWithNoResources(app, `${stackPrefix}-stage-with-no-resources`); + break; + default: throw new Error(`Unrecognized INTEG_STACK_SET: '${stackSet}'`); } diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js new file mode 100755 index 0000000000000..ff84c957c7397 --- /dev/null +++ b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js @@ -0,0 +1,11 @@ +const cdk = require('aws-cdk-lib/core'); + +const stackPrefix = process.env.STACK_NAME_PREFIX; +if (!stackPrefix) { + throw new Error(`the STACK_NAME_PREFIX environment variable is required`); +} + +const app = new cdk.App(); +new NoStackApp(app, `${stackPrefix}-no-stack-1`); + +app.synth(); diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/cdk.json b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/cdk.json new file mode 100644 index 0000000000000..44809158dbdac --- /dev/null +++ b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/cdk.json @@ -0,0 +1,7 @@ +{ + "app": "node app.js", + "versionReporting": false, + "context": { + "aws-cdk:enableDiffNoFail": "true" + } +} diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts index 2d0da77b48f63..6a72987783691 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts @@ -47,6 +47,28 @@ integTest('cli-lib deploy', withCliLibFixture(async (fixture) => { } })); +integTest('cli-lib deploy no stack', withCliLibFixture(async (fixture) => { + const stackName = fixture.fullStackName('no-stack-1'); + + try { + // deploy the stack + await fixture.cdk(['deploy', stackName], { + options: ['--ignore-no-stacks'], + }); + + // verify the number of resources in the stack + const expectedStack = await fixture.aws.cloudFormation('describeStackResources', { + StackName: stackName, + }); + expect(expectedStack.StackResources?.length).toEqual(0); + } finally { + // delete the stack + await fixture.cdk(['destroy', stackName], { + captureStderr: false, + }); + } +})); + integTest('security related changes without a CLI are expected to fail when approval is required', withCliLibFixture(async (fixture) => { const stdErr = await fixture.cdk(['deploy', fixture.fullStackName('simple-1')], { onlyStderr: true, diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index ccdf07b166f33..76caa2dc70a48 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -780,6 +780,31 @@ integTest('deploy stack without resource', withDefaultFixture(async (fixture) => .rejects.toThrow('conditional-resource does not exist'); })); +integTest('deploy --ignore-no-stacks', withDefaultFixture(async (fixture) => { + const stackArn = await fixture.cdkDeploy('stage-with-no-resources', { + options: ['--ignore-no-stacks'], + modEnv: { + INTEG_STACK_SET: 'stage-with-no-resources', + }, + }); + + // verify that we only deployed both stacks (there are 2 ARNs in the output) + /* eslint-disable no-console */ + console.log(stackArn); +})); + +integTest('deploy stack with no resources and no --ignore-no-stacks', withDefaultFixture(async (fixture) => { + const stackArn = await fixture.cdkDeploy('stage-with-no-resources', { + modEnv: { + INTEG_STACK_SET: 'stage-with-no-resources', + }, + }); + + // verify that we only deployed both stacks (there are 2 ARNs in the output) + /* eslint-disable no-console */ + console.log(stackArn); +})); + integTest('IAM diff', withDefaultFixture(async (fixture) => { const output = await fixture.cdk(['diff', fixture.fullStackName('iam-test')]); diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 864c7de02c968..cb19137245fe2 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -382,6 +382,20 @@ $ cdk deploy --method=prepare-change-set --change-set-name MyChangeSetName For more control over when stack changes are deployed, the CDK can generate a CloudFormation change set but not execute it. +#### Ignore No Stacks + +You may have an app with multiple environments, e.g., dev and prod. When starting +development, your prod app may not have any resources or the resources are commented +out. In this scenario, you will receive an error message stating that the app has no +stacks. + +To bypass this error messages, you can pass the `--ignore-no-stacks` flag to the +`deploy` command: + +```console +$ cdk deploy --ignore-no-stacks +``` + #### Hotswap deployments for faster development You can pass the `--hotswap` flag to the `deploy` command: diff --git a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts index c2efeda10dce4..3637c61879d7e 100644 --- a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts +++ b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts @@ -106,8 +106,12 @@ export class CloudAssembly { const allTopLevel = selector.allTopLevel ?? false; const patterns = sanitizePatterns(selector.patterns); - if (stacks.length === 0 && !options.ignoreNoStacks) { - throw new Error('This app contains no stacks'); + if (stacks.length === 0) { + if (options.ignoreNoStacks) { + return new StackCollection(this, []); + } else { + throw new Error('This app contains no stacks'); + } } if (allTopLevel) { diff --git a/packages/aws-cdk/test/api/cloud-assembly.test.ts b/packages/aws-cdk/test/api/cloud-assembly.test.ts index 52c9ba4949d18..97c71c5df2b36 100644 --- a/packages/aws-cdk/test/api/cloud-assembly.test.ts +++ b/packages/aws-cdk/test/api/cloud-assembly.test.ts @@ -156,6 +156,38 @@ test('select behavior with nested assemblies: repeat', async() => { expect(x.stackCount).toBe(2); }); +test('select behavior with no stacks and ignore stacks option', async() => { + // GIVEN + const cxasm = await testCloudAssemblyNoStacks(); + + // WHEN + const x = await cxasm.selectStacks({ patterns: [] }, { + defaultBehavior: DefaultSelection.AllStacks, + ignoreNoStacks: true, + }); + + // THEN + expect(x.stackCount).toBe(0); +}); + +test('select behavior with no stacks and no ignore stacks option', async() => { + // GIVEN + const cxasm = await testCloudAssemblyNoStacks(); + + // WHEN & THEN + await expect(cxasm.selectStacks({ patterns: [] }, { defaultBehavior: DefaultSelection.AllStacks, ignoreNoStacks: false })) + .rejects.toThrow('This app contains no stacks'); +}); + +test('select behavior with no stacks and default ignore stacks options (false)', async() => { + // GIVEN + const cxasm = await testCloudAssemblyNoStacks(); + + // WHEN & THEN + await expect(cxasm.selectStacks({ patterns: [] }, { defaultBehavior: DefaultSelection.AllStacks })) + .rejects.toThrow('This app contains no stacks'); +}); + async function testCloudAssembly({ env }: { env?: string, versionReporting?: boolean } = {}) { const cloudExec = new MockCloudExecutable({ stacks: [{ From 03c14473e5bd0f06130347cb8c8b7352e68b1a32 Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Wed, 20 Dec 2023 16:29:48 -0600 Subject: [PATCH 3/8] remove unneeded test --- .../cli-integ/tests/cli-integ-tests/cli.integtest.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index 76caa2dc70a48..1c00d9c9a7d19 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -793,18 +793,6 @@ integTest('deploy --ignore-no-stacks', withDefaultFixture(async (fixture) => { console.log(stackArn); })); -integTest('deploy stack with no resources and no --ignore-no-stacks', withDefaultFixture(async (fixture) => { - const stackArn = await fixture.cdkDeploy('stage-with-no-resources', { - modEnv: { - INTEG_STACK_SET: 'stage-with-no-resources', - }, - }); - - // verify that we only deployed both stacks (there are 2 ARNs in the output) - /* eslint-disable no-console */ - console.log(stackArn); -})); - integTest('IAM diff', withDefaultFixture(async (fixture) => { const output = await fixture.cdk(['diff', fixture.fullStackName('iam-test')]); From b42cb06fd764ace2b82ade970139c48cea9df18a Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Fri, 22 Dec 2023 16:14:50 -0600 Subject: [PATCH 4/8] add feedback from luca --- .../cli-integ/lib/with-cli-no-stacks.ts | 11 ++++++----- .../tests/cli-integ-tests/cli-lib.integtest.ts | 4 ++-- packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts | 5 ++--- packages/aws-cdk/lib/api/deploy-stack.ts | 2 +- packages/aws-cdk/lib/api/deployments.ts | 2 +- packages/aws-cdk/lib/cdk-toolkit.ts | 10 +++++----- packages/aws-cdk/lib/cli.ts | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts b/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts index 625af386db31a..7d95eb9f1d41d 100644 --- a/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts +++ b/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts @@ -9,7 +9,8 @@ import { withTimeout } from './with-timeout'; /** * Higher order function to execute a block with a CliLib Integration CDK app fixture */ -export function withCliLibIntegrationCdkApp(block: (context: CliLibIntegrationTestFixture) => Promise) { +export function withCliLibNoStacksIntegrationCdkApp +(block: (context:CliLibNoStacksIntegrationTestFixture) => Promise) { return async (context: A) => { const randy = context.randomString; const stackNamePrefix = `cdktest-${randy}`; @@ -20,7 +21,7 @@ export function withCliLibIntegrationCdkApp( context.log(` Region: ${context.aws.region}\n`); await cloneDirectory(path.join(RESOURCES_DIR, 'cdk-apps', 'no-stack-app'), integTestDir, context.output); - const fixture = new CliLibIntegrationTestFixture( + const fixture = new CliLibNoStacksIntegrationTestFixture( integTestDir, stackNamePrefix, context.output, @@ -94,11 +95,11 @@ function errorCausedByGoPkg(error: string) { /** * SAM Integration test fixture for CDK - SAM integration test cases */ -export function withCliLibFixture(block: (context: CliLibIntegrationTestFixture) => Promise) { - return withAws(withTimeout(DEFAULT_TEST_TIMEOUT_S, withCliLibIntegrationCdkApp(block))); +export function withCliLibNoStacksFixture(block: (context: CliLibNoStacksIntegrationTestFixture) => Promise) { + return withAws(withTimeout(DEFAULT_TEST_TIMEOUT_S, withCliLibNoStacksIntegrationCdkApp(block))); } -export class CliLibIntegrationTestFixture extends TestFixture { +export class CliLibNoStacksIntegrationTestFixture extends TestFixture { /** * */ diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts index 6a72987783691..c6d93177415db 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts @@ -1,4 +1,4 @@ -import { integTest, withCliLibFixture } from '../../lib'; +import { integTest, withCliLibFixture, withCliLibNoStacksFixture } from '../../lib'; jest.setTimeout(2 * 60 * 60_000); // Includes the time to acquire locks, worst-case single-threaded runtime @@ -47,7 +47,7 @@ integTest('cli-lib deploy', withCliLibFixture(async (fixture) => { } })); -integTest('cli-lib deploy no stack', withCliLibFixture(async (fixture) => { +integTest('cli-lib deploy no stack', withCliLibNoStacksFixture(async (fixture) => { const stackName = fixture.fullStackName('no-stack-1'); try { diff --git a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts index 3637c61879d7e..c797e3a3492c4 100644 --- a/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts +++ b/packages/aws-cdk/lib/api/cxapp/cloud-assembly.ts @@ -43,7 +43,7 @@ export interface SelectStacksOptions { defaultBehavior: DefaultSelection; /** - * Ignore the error message if the app contains no stacks. + * Whether to deploy if the app contains no stacks. * * @default false */ @@ -109,9 +109,8 @@ export class CloudAssembly { if (stacks.length === 0) { if (options.ignoreNoStacks) { return new StackCollection(this, []); - } else { - throw new Error('This app contains no stacks'); } + throw new Error('This app contains no stacks'); } if (allTopLevel) { diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 2db9ffda5d51f..c4dcf03c5b1ef 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -207,7 +207,7 @@ export interface DeployStackOptions { readonly assetParallelism?: boolean; /** - * Ignore the error message if the app contains no stacks. + * Whether to deploy if the app contains no stacks. * * @default false */ diff --git a/packages/aws-cdk/lib/api/deployments.ts b/packages/aws-cdk/lib/api/deployments.ts index ffbd72b8af244..196c3fae3a999 100644 --- a/packages/aws-cdk/lib/api/deployments.ts +++ b/packages/aws-cdk/lib/api/deployments.ts @@ -200,7 +200,7 @@ export interface DeployStackOptions { readonly assetParallelism?: boolean; /** - * Ignore the error message if the app contains no stacks. + * Whether to deploy if the app contains no stacks. * * @default false */ diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index 7f5b001a8d87e..9ef39c8a0e423 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -175,8 +175,8 @@ export class CdkToolkit { } const startSynthTime = new Date().getTime(); - // eslint-disable-next-line max-len - const stackCollection = await this.selectStacksForDeploy(options.selector, options.exclusively, options.cacheCloudAssembly, options.ignoreNoStacks); + const stackCollection = await this.selectStacksForDeploy(options.selector, options.exclusively, + options.cacheCloudAssembly, options.ignoreNoStacks); const elapsedSynthTime = new Date().getTime() - startSynthTime; print('\n✨ Synthesis time: %ss\n', formatTime(elapsedSynthTime)); @@ -731,8 +731,8 @@ export class CdkToolkit { return stacks; } - // eslint-disable-next-line max-len - private async selectStacksForDeploy(selector: StackSelector, exclusively?: boolean, cacheCloudAssembly?: boolean, ignoreNoStacks?: boolean): Promise { + private async selectStacksForDeploy(selector: StackSelector, exclusively?: boolean, + cacheCloudAssembly?: boolean, ignoreNoStacks?: boolean): Promise { const assembly = await this.assembly(cacheCloudAssembly); const stacks = await assembly.selectStacks(selector, { extend: exclusively ? ExtendedStackSelection.None : ExtendedStackSelection.Upstream, @@ -1140,7 +1140,7 @@ export interface DeployOptions extends CfnDeployOptions, WatchOptions { readonly assetBuildTime?: AssetBuildTime; /** - * Ignore the error message if the app contains no stacks. + * Whether to deploy if the app contains no stacks. * * @default false */ diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index 03ecc4480b826..c872109a423c5 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -173,7 +173,7 @@ async function parseCommandLineArguments(args: string[]) { .option('concurrency', { type: 'number', desc: 'Maximum number of simultaneous deployments (dependency permitting) to execute.', default: 1, requiresArg: true }) .option('asset-parallelism', { type: 'boolean', desc: 'Whether to build/publish assets in parallel' }) .option('asset-prebuild', { type: 'boolean', desc: 'Whether to build all assets before deploying the first stack (useful for failing Docker builds)', default: true }) - .option('ignore-no-stacks', { type: 'boolean', desc: 'Ignore the error message if the app contains no stacks', default: false }), + .option('ignore-no-stacks', { type: 'boolean', desc: 'Whether to deploy if the app contains no stacks', default: false }), ) .command('import [STACK]', 'Import existing resource(s) into the given STACK', (yargs: Argv) => yargs .option('execute', { type: 'boolean', desc: 'Whether to execute ChangeSet (--no-execute will NOT execute the ChangeSet)', default: true }) From c583e43649540234a33f3da715ea2cd2c54b4d0b Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Sat, 23 Dec 2023 14:49:43 -0600 Subject: [PATCH 5/8] temp staging --- .../@aws-cdk-testing/cli-integ/lib/index.ts | 1 + ...no-stacks.ts => with-cli-lib-no-stacks.ts} | 11 +++++---- .../cli-integ/resources/cdk-apps/app/app.js | 5 +--- .../resources/cdk-apps/no-stack-app/app.js | 6 ----- .../cli-integ-tests/cli-lib.integtest.ts | 24 +------------------ .../tests/cli-integ-tests/cli.integtest.ts | 19 +++++++++------ .../cdk-cli-wrapper/lib/cdk-wrapper.ts | 1 + .../cdk-cli-wrapper/lib/commands/deploy.ts | 7 ++++++ .../cdk-cli-wrapper/test/cdk-wrapper.test.ts | 2 ++ .../cli-lib-alpha/THIRD_PARTY_LICENSES | 6 ++--- packages/aws-cdk/lib/api/deploy-stack.ts | 9 +------ 11 files changed, 35 insertions(+), 56 deletions(-) rename packages/@aws-cdk-testing/cli-integ/lib/{with-cli-no-stacks.ts => with-cli-lib-no-stacks.ts} (96%) diff --git a/packages/@aws-cdk-testing/cli-integ/lib/index.ts b/packages/@aws-cdk-testing/cli-integ/lib/index.ts index cabb094e65c00..b5f7cd4548893 100644 --- a/packages/@aws-cdk-testing/cli-integ/lib/index.ts +++ b/packages/@aws-cdk-testing/cli-integ/lib/index.ts @@ -4,6 +4,7 @@ export * from './integ-test'; export * from './memoize'; export * from './resource-pool'; export * from './with-cli-lib'; +export * from './with-cli-lib-no-stacks'; export * from './with-sam'; export * from './shell'; export * from './with-aws'; diff --git a/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts b/packages/@aws-cdk-testing/cli-integ/lib/with-cli-lib-no-stacks.ts similarity index 96% rename from packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts rename to packages/@aws-cdk-testing/cli-integ/lib/with-cli-lib-no-stacks.ts index 7d95eb9f1d41d..abf0096cad60d 100644 --- a/packages/@aws-cdk-testing/cli-integ/lib/with-cli-no-stacks.ts +++ b/packages/@aws-cdk-testing/cli-integ/lib/with-cli-lib-no-stacks.ts @@ -105,16 +105,18 @@ export class CliLibNoStacksIntegrationTestFixture extends TestFixture { */ public async cdk(args: string[], options: CdkCliOptions = {}) { const action = args[0]; - const stackName = args[1]; + const ignoreNoStacks = args[1]; - const cliOpts: Record = { - stacks: stackName ? [stackName] : undefined, - }; + const cliOpts: Record = {}; if (action === 'deploy') { cliOpts.requireApproval = options.neverRequireApproval ? 'never' : 'broadening'; } + if (ignoreNoStacks == '--ignore-no-stacks') { + cliOpts.ignoreNoStacks = true; + } + return this.shell(['node', '--input-type=module', `<<__EOS__ import { AwsCdkCli } from '@aws-cdk/cli-lib-alpha'; const cli = AwsCdkCli.fromCdkAppDirectory(); @@ -125,7 +127,6 @@ __EOS__`], { modEnv: { AWS_REGION: this.aws.region, AWS_DEFAULT_REGION: this.aws.region, - STACK_NAME_PREFIX: this.stackNamePrefix, PACKAGE_LAYOUT_VERSION: this.packages.majorVersion(), ...options.modEnv, }, diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js index 322b828baf3f1..eeb1ad83673e2 100755 --- a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js +++ b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js @@ -403,8 +403,6 @@ class BuiltinLambdaStack extends cdk.Stack { } } -class StackWithNoResources extends cdk.Stack {} - const app = new cdk.App({ context: { '@aws-cdk/core:assetHashSalt': process.env.CODEBUILD_BUILD_ID, // Force all assets to be unique, but consistent in one build @@ -494,8 +492,7 @@ switch (stackSet) { stage.synth({ validateOnSynthesis: true }); break; - case 'stage-with-no-resources': - new StackWithNoResources(app, `${stackPrefix}-stage-with-no-resources`); + case 'stage-with-no-stacks': break; default: diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js index ff84c957c7397..0ab5ae37bbf1a 100755 --- a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js +++ b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js @@ -1,11 +1,5 @@ const cdk = require('aws-cdk-lib/core'); -const stackPrefix = process.env.STACK_NAME_PREFIX; -if (!stackPrefix) { - throw new Error(`the STACK_NAME_PREFIX environment variable is required`); -} - const app = new cdk.App(); -new NoStackApp(app, `${stackPrefix}-no-stack-1`); app.synth(); diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts index c6d93177415db..2d0da77b48f63 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli-lib.integtest.ts @@ -1,4 +1,4 @@ -import { integTest, withCliLibFixture, withCliLibNoStacksFixture } from '../../lib'; +import { integTest, withCliLibFixture } from '../../lib'; jest.setTimeout(2 * 60 * 60_000); // Includes the time to acquire locks, worst-case single-threaded runtime @@ -47,28 +47,6 @@ integTest('cli-lib deploy', withCliLibFixture(async (fixture) => { } })); -integTest('cli-lib deploy no stack', withCliLibNoStacksFixture(async (fixture) => { - const stackName = fixture.fullStackName('no-stack-1'); - - try { - // deploy the stack - await fixture.cdk(['deploy', stackName], { - options: ['--ignore-no-stacks'], - }); - - // verify the number of resources in the stack - const expectedStack = await fixture.aws.cloudFormation('describeStackResources', { - StackName: stackName, - }); - expect(expectedStack.StackResources?.length).toEqual(0); - } finally { - // delete the stack - await fixture.cdk(['destroy', stackName], { - captureStderr: false, - }); - } -})); - integTest('security related changes without a CLI are expected to fail when approval is required', withCliLibFixture(async (fixture) => { const stdErr = await fixture.cdk(['deploy', fixture.fullStackName('simple-1')], { onlyStderr: true, diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index 1c00d9c9a7d19..ad6a5f6ed9ad2 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -1,7 +1,7 @@ import { promises as fs, existsSync } from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { integTest, cloneDirectory, shell, withDefaultFixture, retry, sleep, randomInteger, withSamIntegrationFixture, RESOURCES_DIR, withCDKMigrateFixture } from '../../lib'; +import { integTest, cloneDirectory, shell, withDefaultFixture, retry, sleep, randomInteger, withSamIntegrationFixture, RESOURCES_DIR, withCDKMigrateFixture, withCliLibNoStacksFixture } from '../../lib'; jest.setTimeout(2 * 60 * 60_000); // Includes the time to acquire locks, worst-case single-threaded runtime @@ -780,17 +780,22 @@ integTest('deploy stack without resource', withDefaultFixture(async (fixture) => .rejects.toThrow('conditional-resource does not exist'); })); -integTest('deploy --ignore-no-stacks', withDefaultFixture(async (fixture) => { - const stackArn = await fixture.cdkDeploy('stage-with-no-resources', { +integTest('deploy no stacks with --ignore-no-stacks', withDefaultFixture(async (fixture) => { + // empty array for stack names + await fixture.cdkDeploy([], { options: ['--ignore-no-stacks'], modEnv: { - INTEG_STACK_SET: 'stage-with-no-resources', + INTEG_STACK_SET: 'stage-with-no-stacks', }, }); +})); - // verify that we only deployed both stacks (there are 2 ARNs in the output) - /* eslint-disable no-console */ - console.log(stackArn); +integTest('deploy no stacks error', withDefaultFixture(async (fixture) => { + await expect(fixture.cdkDeploy([], { + modEnv: { + INTEG_STACK_SET: 'stage-with-no-stacks', + }, + })).rejects.toThrow('exited with error'); })); integTest('IAM diff', withDefaultFixture(async (fixture) => { diff --git a/packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts b/packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts index 9fe40b0b1314f..f8364c4a3f419 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts +++ b/packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts @@ -174,6 +174,7 @@ export class CdkCliWrapper implements ICdk { ...renderBooleanArg('previous-parameters', options.usePreviousParameters), ...renderBooleanArg('rollback', options.rollback), ...renderBooleanArg('staging', options.staging), + ...renderBooleanArg('ignore-no-stacks', options.ignoreNoStacks), ...options.reuseAssets ? renderArrayArg('--reuse-assets', options.reuseAssets) : [], ...options.notificationArns ? renderArrayArg('--notification-arns', options.notificationArns) : [], ...options.parameters ? renderMapArrayArg('--parameters', options.parameters) : [], diff --git a/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts b/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts index 59ffedefe9945..eb92f5ca0e37e 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts +++ b/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts @@ -141,6 +141,13 @@ export interface DeployOptions extends DefaultCdkOptions { * @default 1 */ readonly concurrency?: number; + + /** + * Whether to deploy if the app contains no stacks. + * + * @default false + */ + readonly ignoreNoStacks?: boolean; } export type DeploymentMethod = 'direct' | 'change-set'; diff --git a/packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts b/packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts index 266a7b9c81190..d370d5fd295ce 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts +++ b/packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts @@ -89,6 +89,7 @@ test('deploy with all arguments', () => { versionReporting: true, usePreviousParameters: true, progress: StackActivityProgress.BAR, + ignoreNoStacks: true, }); // THEN @@ -129,6 +130,7 @@ test('deploy with all arguments', () => { '--previous-parameters', '--progress', 'bar', '--app', + '--ignore-no-stacks', 'node bin/my-app.js', 'test-stack1', ]), diff --git a/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES b/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES index 9927af86bd644..c430595bb0514 100644 --- a/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES +++ b/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES @@ -207,7 +207,7 @@ The @aws-cdk/cli-lib-alpha package includes the following third-party software/l ---------------- -** @jsii/check-node@1.92.0 - https://www.npmjs.com/package/@jsii/check-node/v/1.92.0 | Apache-2.0 +** @jsii/check-node@1.93.0 - https://www.npmjs.com/package/@jsii/check-node/v/1.93.0 | Apache-2.0 jsii Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -471,7 +471,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE ---------------- -** aws-sdk@2.1498.0 - https://www.npmjs.com/package/aws-sdk/v/2.1498.0 | Apache-2.0 +** aws-sdk@2.1517.0 - https://www.npmjs.com/package/aws-sdk/v/2.1517.0 | Apache-2.0 AWS SDK for JavaScript Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -668,7 +668,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ---------------- -** cdk-from-cfn@0.84.0 - https://www.npmjs.com/package/cdk-from-cfn/v/0.84.0 | MIT OR Apache-2.0 +** cdk-from-cfn@0.91.0 - https://www.npmjs.com/package/cdk-from-cfn/v/0.91.0 | MIT OR Apache-2.0 ---------------- diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index c4dcf03c5b1ef..122e51c7853c0 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -126,7 +126,7 @@ export interface DeployStackOptions { * The collection of extra parameters * (in addition to those used for assets) * to pass to the deployed template. - * Note that parameters with `undefined` or empty values will be ignored, + * Note that parameters with `undefined` or empty values will be d, * and not passed to the template. * * @default - no additional parameters will be passed to the template @@ -205,13 +205,6 @@ export interface DeployStackOptions { * @default true To remain backward compatible. */ readonly assetParallelism?: boolean; - - /** - * Whether to deploy if the app contains no stacks. - * - * @default false - */ - ignoreNoStacks?: boolean; } export type DeploymentMethod = From 044dd766ada349cb4d835fa6334e65d48ee938ae Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Sat, 23 Dec 2023 14:50:37 -0600 Subject: [PATCH 6/8] lets try this --- .../@aws-cdk-testing/cli-integ/lib/index.ts | 1 - .../cli-integ/lib/with-cli-lib-no-stacks.ts | 136 ------------------ .../tests/cli-integ-tests/cli.integtest.ts | 2 +- 3 files changed, 1 insertion(+), 138 deletions(-) delete mode 100644 packages/@aws-cdk-testing/cli-integ/lib/with-cli-lib-no-stacks.ts diff --git a/packages/@aws-cdk-testing/cli-integ/lib/index.ts b/packages/@aws-cdk-testing/cli-integ/lib/index.ts index b5f7cd4548893..cabb094e65c00 100644 --- a/packages/@aws-cdk-testing/cli-integ/lib/index.ts +++ b/packages/@aws-cdk-testing/cli-integ/lib/index.ts @@ -4,7 +4,6 @@ export * from './integ-test'; export * from './memoize'; export * from './resource-pool'; export * from './with-cli-lib'; -export * from './with-cli-lib-no-stacks'; export * from './with-sam'; export * from './shell'; export * from './with-aws'; diff --git a/packages/@aws-cdk-testing/cli-integ/lib/with-cli-lib-no-stacks.ts b/packages/@aws-cdk-testing/cli-integ/lib/with-cli-lib-no-stacks.ts deleted file mode 100644 index abf0096cad60d..0000000000000 --- a/packages/@aws-cdk-testing/cli-integ/lib/with-cli-lib-no-stacks.ts +++ /dev/null @@ -1,136 +0,0 @@ -import * as os from 'os'; -import * as path from 'path'; -import { TestContext } from './integ-test'; -import { RESOURCES_DIR } from './resources'; -import { AwsContext, withAws } from './with-aws'; -import { cloneDirectory, installNpmPackages, TestFixture, DEFAULT_TEST_TIMEOUT_S, CdkCliOptions } from './with-cdk-app'; -import { withTimeout } from './with-timeout'; - -/** - * Higher order function to execute a block with a CliLib Integration CDK app fixture - */ -export function withCliLibNoStacksIntegrationCdkApp -(block: (context:CliLibNoStacksIntegrationTestFixture) => Promise) { - return async (context: A) => { - const randy = context.randomString; - const stackNamePrefix = `cdktest-${randy}`; - const integTestDir = path.join(os.tmpdir(), `cdk-integ-${randy}`); - - context.log(` Stack prefix: ${stackNamePrefix}\n`); - context.log(` Test directory: ${integTestDir}\n`); - context.log(` Region: ${context.aws.region}\n`); - - await cloneDirectory(path.join(RESOURCES_DIR, 'cdk-apps', 'no-stack-app'), integTestDir, context.output); - const fixture = new CliLibNoStacksIntegrationTestFixture( - integTestDir, - stackNamePrefix, - context.output, - context.aws, - context.randomString); - - let success = true; - try { - const installationVersion = fixture.packages.requestedFrameworkVersion(); - - if (fixture.packages.majorVersion() === '1') { - throw new Error('This test suite is only compatible with AWS CDK v2'); - } - - const alphaInstallationVersion = fixture.packages.requestedAlphaVersion(); - await installNpmPackages(fixture, { - 'aws-cdk-lib': installationVersion, - '@aws-cdk/cli-lib-alpha': alphaInstallationVersion, - '@aws-cdk/aws-lambda-go-alpha': alphaInstallationVersion, - '@aws-cdk/aws-lambda-python-alpha': alphaInstallationVersion, - 'constructs': '^10', - }); - - await block(fixture); - } catch (e: any) { - // We survive certain cases involving gopkg.in - if (errorCausedByGoPkg(e.message)) { - return; - } - success = false; - throw e; - } finally { - if (process.env.INTEG_NO_CLEAN) { - context.log(`Left test directory in '${integTestDir}' ($INTEG_NO_CLEAN)\n`); - } else { - await fixture.dispose(success); - } - } - }; -} - -/** - * Return whether or not the error is being caused by gopkg.in being down - * - * Our Go build depends on https://gopkg.in/, which has errors pretty often - * (every couple of days). It is run by a single volunteer. - */ -function errorCausedByGoPkg(error: string) { - // The error is different depending on what request fails. Messages recognized: - //////////////////////////////////////////////////////////////////// - // go: github.com/aws/aws-lambda-go@v1.28.0 requires - // gopkg.in/yaml.v3@v3.0.0-20200615113413-eeeca48fe776: invalid version: git ls-remote -q origin in /go/pkg/mod/cache/vcs/0901dc1ef67fcce1c9b3ae51078740de4a0e2dc673e720584ac302973af82f36: exit status 128: - // remote: Cannot obtain refs from GitHub: cannot talk to GitHub: Get https://github.com/go-yaml/yaml.git/info/refs?service=git-upload-pack: net/http: request canceled (Client.Timeout exceeded while awaiting headers) - // fatal: unable to access 'https://gopkg.in/yaml.v3/': The requested URL returned error: 502 - //////////////////////////////////////////////////////////////////// - // go: downloading github.com/aws/aws-lambda-go v1.28.0 - // go: github.com/aws/aws-lambda-go@v1.28.0 requires - // gopkg.in/yaml.v3@v3.0.0-20200615113413-eeeca48fe776: unrecognized import path "gopkg.in/yaml.v3": reading https://gopkg.in/yaml.v3?go-get=1: 502 Bad Gateway - // server response: Cannot obtain refs from GitHub: cannot talk to GitHub: Get https://github.com/go-yaml/yaml.git/info/refs?service=git-upload-pack: net/http: request canceled (Client.Timeout exceeded while awaiting headers) - //////////////////////////////////////////////////////////////////// - // go: github.com/aws/aws-lambda-go@v1.28.0 requires - // gopkg.in/yaml.v3@v3.0.0-20200615113413-eeeca48fe776: invalid version: git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /go/pkg/mod/cache/vcs/0901dc1ef67fcce1c9b3ae51078740de4a0e2dc673e720584ac302973af82f36: exit status 128: - // error: RPC failed; HTTP 502 curl 22 The requested URL returned error: 502 - // fatal: the remote end hung up unexpectedly - //////////////////////////////////////////////////////////////////// - - return (error.includes('gopkg\.in.*invalid version.*exit status 128') - || error.match(/unrecognized import path[^\n]gopkg\.in/)); -} - -/** - * SAM Integration test fixture for CDK - SAM integration test cases - */ -export function withCliLibNoStacksFixture(block: (context: CliLibNoStacksIntegrationTestFixture) => Promise) { - return withAws(withTimeout(DEFAULT_TEST_TIMEOUT_S, withCliLibNoStacksIntegrationCdkApp(block))); -} - -export class CliLibNoStacksIntegrationTestFixture extends TestFixture { - /** - * - */ - public async cdk(args: string[], options: CdkCliOptions = {}) { - const action = args[0]; - const ignoreNoStacks = args[1]; - - const cliOpts: Record = {}; - - if (action === 'deploy') { - cliOpts.requireApproval = options.neverRequireApproval ? 'never' : 'broadening'; - } - - if (ignoreNoStacks == '--ignore-no-stacks') { - cliOpts.ignoreNoStacks = true; - } - - return this.shell(['node', '--input-type=module', `<<__EOS__ - import { AwsCdkCli } from '@aws-cdk/cli-lib-alpha'; - const cli = AwsCdkCli.fromCdkAppDirectory(); - - await cli.${action}(${JSON.stringify(cliOpts)}); -__EOS__`], { - ...options, - modEnv: { - AWS_REGION: this.aws.region, - AWS_DEFAULT_REGION: this.aws.region, - PACKAGE_LAYOUT_VERSION: this.packages.majorVersion(), - ...options.modEnv, - }, - }); - } - -} diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index ad6a5f6ed9ad2..f8d0b0f0809de 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -1,7 +1,7 @@ import { promises as fs, existsSync } from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { integTest, cloneDirectory, shell, withDefaultFixture, retry, sleep, randomInteger, withSamIntegrationFixture, RESOURCES_DIR, withCDKMigrateFixture, withCliLibNoStacksFixture } from '../../lib'; +import { integTest, cloneDirectory, shell, withDefaultFixture, retry, sleep, randomInteger, withSamIntegrationFixture, RESOURCES_DIR, withCDKMigrateFixture } from '../../lib'; jest.setTimeout(2 * 60 * 60_000); // Includes the time to acquire locks, worst-case single-threaded runtime From cb550c10f0067c3c4b4916809303c54a0f1cded8 Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Sat, 23 Dec 2023 14:53:16 -0600 Subject: [PATCH 7/8] fix --- .../cli-integ/resources/cdk-apps/no-stack-app/app.js | 5 ----- .../cli-integ/resources/cdk-apps/no-stack-app/cdk.json | 7 ------- packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts | 1 - packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts | 7 ------- packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts | 2 -- packages/aws-cdk/lib/api/deploy-stack.ts | 2 +- 6 files changed, 1 insertion(+), 23 deletions(-) delete mode 100755 packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js delete mode 100644 packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/cdk.json diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js deleted file mode 100755 index 0ab5ae37bbf1a..0000000000000 --- a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/app.js +++ /dev/null @@ -1,5 +0,0 @@ -const cdk = require('aws-cdk-lib/core'); - -const app = new cdk.App(); - -app.synth(); diff --git a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/cdk.json b/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/cdk.json deleted file mode 100644 index 44809158dbdac..0000000000000 --- a/packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/no-stack-app/cdk.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "app": "node app.js", - "versionReporting": false, - "context": { - "aws-cdk:enableDiffNoFail": "true" - } -} diff --git a/packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts b/packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts index f8364c4a3f419..9fe40b0b1314f 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts +++ b/packages/@aws-cdk/cdk-cli-wrapper/lib/cdk-wrapper.ts @@ -174,7 +174,6 @@ export class CdkCliWrapper implements ICdk { ...renderBooleanArg('previous-parameters', options.usePreviousParameters), ...renderBooleanArg('rollback', options.rollback), ...renderBooleanArg('staging', options.staging), - ...renderBooleanArg('ignore-no-stacks', options.ignoreNoStacks), ...options.reuseAssets ? renderArrayArg('--reuse-assets', options.reuseAssets) : [], ...options.notificationArns ? renderArrayArg('--notification-arns', options.notificationArns) : [], ...options.parameters ? renderMapArrayArg('--parameters', options.parameters) : [], diff --git a/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts b/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts index eb92f5ca0e37e..59ffedefe9945 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts +++ b/packages/@aws-cdk/cdk-cli-wrapper/lib/commands/deploy.ts @@ -141,13 +141,6 @@ export interface DeployOptions extends DefaultCdkOptions { * @default 1 */ readonly concurrency?: number; - - /** - * Whether to deploy if the app contains no stacks. - * - * @default false - */ - readonly ignoreNoStacks?: boolean; } export type DeploymentMethod = 'direct' | 'change-set'; diff --git a/packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts b/packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts index d370d5fd295ce..266a7b9c81190 100644 --- a/packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts +++ b/packages/@aws-cdk/cdk-cli-wrapper/test/cdk-wrapper.test.ts @@ -89,7 +89,6 @@ test('deploy with all arguments', () => { versionReporting: true, usePreviousParameters: true, progress: StackActivityProgress.BAR, - ignoreNoStacks: true, }); // THEN @@ -130,7 +129,6 @@ test('deploy with all arguments', () => { '--previous-parameters', '--progress', 'bar', '--app', - '--ignore-no-stacks', 'node bin/my-app.js', 'test-stack1', ]), diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 122e51c7853c0..02d1d7b0f0324 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -126,7 +126,7 @@ export interface DeployStackOptions { * The collection of extra parameters * (in addition to those used for assets) * to pass to the deployed template. - * Note that parameters with `undefined` or empty values will be d, + * Note that parameters with `undefined` or empty values will be ignored, * and not passed to the template. * * @default - no additional parameters will be passed to the template From 0090999421c04d1856f06963b563c5c130f09e72 Mon Sep 17 00:00:00 2001 From: Michael Sambol Date: Sat, 23 Dec 2023 14:54:28 -0600 Subject: [PATCH 8/8] fix2 --- .../cli-integ/tests/cli-integ-tests/cli.integtest.ts | 1 + packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index f8d0b0f0809de..b64a3c085bd34 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -791,6 +791,7 @@ integTest('deploy no stacks with --ignore-no-stacks', withDefaultFixture(async ( })); integTest('deploy no stacks error', withDefaultFixture(async (fixture) => { + // empty array for stack names await expect(fixture.cdkDeploy([], { modEnv: { INTEG_STACK_SET: 'stage-with-no-stacks', diff --git a/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES b/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES index c430595bb0514..9927af86bd644 100644 --- a/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES +++ b/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES @@ -207,7 +207,7 @@ The @aws-cdk/cli-lib-alpha package includes the following third-party software/l ---------------- -** @jsii/check-node@1.93.0 - https://www.npmjs.com/package/@jsii/check-node/v/1.93.0 | Apache-2.0 +** @jsii/check-node@1.92.0 - https://www.npmjs.com/package/@jsii/check-node/v/1.92.0 | Apache-2.0 jsii Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -471,7 +471,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE ---------------- -** aws-sdk@2.1517.0 - https://www.npmjs.com/package/aws-sdk/v/2.1517.0 | Apache-2.0 +** aws-sdk@2.1498.0 - https://www.npmjs.com/package/aws-sdk/v/2.1498.0 | Apache-2.0 AWS SDK for JavaScript Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -668,7 +668,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ---------------- -** cdk-from-cfn@0.91.0 - https://www.npmjs.com/package/cdk-from-cfn/v/0.91.0 | MIT OR Apache-2.0 +** cdk-from-cfn@0.84.0 - https://www.npmjs.com/package/cdk-from-cfn/v/0.84.0 | MIT OR Apache-2.0 ----------------