From 572221b5ec08d0d24346537952bc42dcfd4ee3ca Mon Sep 17 00:00:00 2001 From: Sai Ray Date: Mon, 22 Jun 2026 18:29:40 -0400 Subject: [PATCH 1/9] chore: midwork --- ...ls-ci-no-synth-time-on-stdout.integtest.ts | 28 ++++++++++--------- packages/aws-cdk/lib/cli/cdk-toolkit.ts | 5 ++-- packages/aws-cdk/test/cli/cdk-toolkit.test.ts | 19 +++++++++++-- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts index c346830e1..ec67b6fd9 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts @@ -1,22 +1,24 @@ import { integTest, withDefaultFixture } from '../../../lib'; integTest( - 'cdk ls --json in CI does not print synthesis time to stdout', + 'cdk ls in CI does not print synthesis time to stdout', withDefaultFixture(async (fixture) => { - // `cdk ls --json` stdout is a machine-readable contract and is often piped (e.g. to `jq`), - // so it must be only the stack listing, not status lines like "✨ Synthesis time: ...". - const listing = await fixture.cdk(['ls', '--json'], { - verbose: false, // fixture defaults verbose on; turn it off so stdout is just the listing - captureStderr: false, // capture stdout only; stderr is folded into the result by default - modEnv: { CI: 'true' }, // CI routes non-error output to stdout (default is stderr) - }); + // In CI, stdout must be only the stack listing, not the "✨ Synthesis time: ..." line. + // Check both plain `cdk ls` (issue #38165) and `cdk ls --json`. + for (const args of [['ls'], ['ls', '--json']]) { + const listing = await fixture.cdk(args, { + verbose: false, // turn off so stdout is just the listing + captureStderr: false, // capture stdout only + modEnv: { CI: 'true' }, // CI routes non-error output to stdout + }); - const lines = listing.trim().split('\n').filter(line => line.length > 0); + const lines = listing.trim().split('\n').filter(line => line.length > 0); - // every line should be a stack; a synth-time line would not carry the prefix - expect(lines.length).toBeGreaterThan(0); - for (const line of lines) { - expect(line).toContain(fixture.stackNamePrefix); + // every line should be a stack; a synth-time line would not carry the prefix + expect(lines.length).toBeGreaterThan(0); + for (const line of lines) { + expect(line).toContain(fixture.stackNamePrefix); + } } }), ); diff --git a/packages/aws-cdk/lib/cli/cdk-toolkit.ts b/packages/aws-cdk/lib/cli/cdk-toolkit.ts index 8f35662f3..934e90058 100644 --- a/packages/aws-cdk/lib/cli/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cli/cdk-toolkit.ts @@ -966,8 +966,9 @@ export class CdkToolkit { ): Promise { this.ioHost.rewriteOnce(IO.CDK_TOOLKIT_I2901, (msg) => formatStackList(msg.data.stacks, options)); - // With `--json`, stdout must stay machine-parsable, so suppress the synth-time line (I1000). - if (options.json) { + // In CI mode (and with --json), the synth-time line (I1000) goes to stdout next to the + // listing and breaks parsers. Suppress it so stdout is only the listing. + if (options.json || this.ioHost.isCI) { this.ioHost.once(IO.CDK_TOOLKIT_I1000, () => ({ preventDefault: true })); } diff --git a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts index 48caf81bd..fdc2938cf 100644 --- a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts @@ -232,8 +232,8 @@ describe('list', () => { expect(listener({ code: 'CDK_TOOLKIT_I1000' })).toEqual({ preventDefault: true }); }); - test('without --json, does not suppress the synthesis-time line', async () => { - // Plain `cdk ls` is not a machine-readable contract, so the line is left alone. + test('without --json and not in CI, does not suppress the synthesis-time line', async () => { + ioHost.isCI = false; const toolkit = defaultToolkitSetup(); const onceSpy = jest.spyOn(ioHost, 'once'); @@ -244,6 +244,21 @@ describe('list', () => { const i1000Call = onceSpy.mock.calls.find(([code]) => (code as any)?.code === 'CDK_TOOLKIT_I1000'); expect(i1000Call).toBeUndefined(); }); + + test('in CI mode without --json, suppresses the synthesis-time line', async () => { + ioHost.isCI = true; + const toolkit = defaultToolkitSetup(); + const onceSpy = jest.spyOn(ioHost, 'once'); + + // WHEN + await toolkit.list([]); + + // THEN + const i1000Call = onceSpy.mock.calls.find(([code]) => (code as any)?.code === 'CDK_TOOLKIT_I1000'); + expect(i1000Call).toBeDefined(); + const listener = i1000Call![1] as (msg: any) => any; + expect(listener({ code: 'CDK_TOOLKIT_I1000' })).toEqual({ preventDefault: true }); + }); }); describe('deploy', () => { From f43451f33718593f14835a171febfe8f708cfe0f Mon Sep 17 00:00:00 2001 From: Sai Ray Date: Mon, 22 Jun 2026 19:42:17 -0400 Subject: [PATCH 2/9] chore: midwork --- packages/aws-cdk/lib/cli/cdk-toolkit.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/lib/cli/cdk-toolkit.ts b/packages/aws-cdk/lib/cli/cdk-toolkit.ts index 934e90058..5ff670ca1 100644 --- a/packages/aws-cdk/lib/cli/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cli/cdk-toolkit.ts @@ -966,8 +966,9 @@ export class CdkToolkit { ): Promise { this.ioHost.rewriteOnce(IO.CDK_TOOLKIT_I2901, (msg) => formatStackList(msg.data.stacks, options)); - // In CI mode (and with --json), the synth-time line (I1000) goes to stdout next to the - // listing and breaks parsers. Suppress it so stdout is only the listing. + // In CI, info-level output (incl. the synth-time line, I1000) routes to stdout next to the + // listing and breaks parsers. With --json, stdout is an explicit machine-readable contract. + // In both cases, suppress I1000 so stdout carries only the listing. if (options.json || this.ioHost.isCI) { this.ioHost.once(IO.CDK_TOOLKIT_I1000, () => ({ preventDefault: true })); } From 404001ac713b813f888ebe8934a04d7076f0f7b0 Mon Sep 17 00:00:00 2001 From: Sai Ray Date: Tue, 23 Jun 2026 20:40:39 -0400 Subject: [PATCH 3/9] chore: midwork --- ...ls-ci-no-synth-time-on-stdout.integtest.ts | 13 ++--- packages/aws-cdk/lib/cli/cdk-toolkit.ts | 22 ++++----- packages/aws-cdk/test/cli/cdk-toolkit.test.ts | 48 ++++++++----------- 3 files changed, 39 insertions(+), 44 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts index ec67b6fd9..d825f64a8 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts @@ -1,20 +1,21 @@ import { integTest, withDefaultFixture } from '../../../lib'; integTest( - 'cdk ls in CI does not print synthesis time to stdout', + 'cdk ls in CI prints only the stack listing to stdout', withDefaultFixture(async (fixture) => { - // In CI, stdout must be only the stack listing, not the "✨ Synthesis time: ..." line. - // Check both plain `cdk ls` (issue #38165) and `cdk ls --json`. - for (const args of [['ls'], ['ls', '--json']]) { + // In CI, stdout must be only the stack listing, not status lines (issue #38165). + // `*list-stacks` is selected because it pulls in a dependency, exercising that path too. + for (const args of [['ls'], ['ls', '--json'], ['ls', `${fixture.stackNamePrefix}-list-stacks`]]) { const listing = await fixture.cdk(args, { verbose: false, // turn off so stdout is just the listing captureStderr: false, // capture stdout only modEnv: { CI: 'true' }, // CI routes non-error output to stdout }); - const lines = listing.trim().split('\n').filter(line => line.length > 0); + expect(listing).not.toContain('Synthesis time'); + expect(listing).not.toContain('Including dependency stacks'); - // every line should be a stack; a synth-time line would not carry the prefix + const lines = listing.trim().split('\n').filter(line => line.length > 0); expect(lines.length).toBeGreaterThan(0); for (const line of lines) { expect(line).toContain(fixture.stackNamePrefix); diff --git a/packages/aws-cdk/lib/cli/cdk-toolkit.ts b/packages/aws-cdk/lib/cli/cdk-toolkit.ts index 5ff670ca1..469c076db 100644 --- a/packages/aws-cdk/lib/cli/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cli/cdk-toolkit.ts @@ -966,19 +966,19 @@ export class CdkToolkit { ): Promise { this.ioHost.rewriteOnce(IO.CDK_TOOLKIT_I2901, (msg) => formatStackList(msg.data.stacks, options)); - // In CI, info-level output (incl. the synth-time line, I1000) routes to stdout next to the - // listing and breaks parsers. With --json, stdout is an explicit machine-readable contract. - // In both cases, suppress I1000 so stdout carries only the listing. - if (options.json || this.ioHost.isCI) { - this.ioHost.once(IO.CDK_TOOLKIT_I1000, () => ({ preventDefault: true })); + // Only the listing should reach stdout; drop info status lines (synth time, dependency notes). + const previousLevel = this.ioHost.logLevel; + this.ioHost.logLevel = 'warn'; + try { + await this.toolkit.list(this.props.cloudExecutable, { + stacks: selectors.length > 0 + ? { patterns: selectors, strategy: StackSelectionStrategy.PATTERN_MATCH, expand: ExpandStackSelection.UPSTREAM } + : undefined, + }); + } finally { + this.ioHost.logLevel = previousLevel; } - await this.toolkit.list(this.props.cloudExecutable, { - stacks: selectors.length > 0 - ? { patterns: selectors, strategy: StackSelectionStrategy.PATTERN_MATCH, expand: ExpandStackSelection.UPSTREAM } - : undefined, - }); - return 0; // exit-code } diff --git a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts index fdc2938cf..3009445f0 100644 --- a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts @@ -216,48 +216,42 @@ describe('list', () => { ]); }); - test('with --json, suppresses the synthesis-time line so stdout stays machine-parsable', async () => { - // `cdk ls --json` stdout is a machine-readable contract; the "Synthesis time" line - // (CDK_TOOLKIT_I1000) must not be written (in CI mode non-error output goes to stdout). + test('raises the log level to warn while listing, so info status lines are dropped', async () => { + // The "Synthesis time" line and "Including dependency stacks" line are info-level; while + // listing, the log level is raised to warn so they never reach stdout next to the listing. const toolkit = defaultToolkitSetup(); - const onceSpy = jest.spyOn(ioHost, 'once'); + let levelDuringList: string | undefined; + jest.spyOn(toolkit.toolkit, 'list').mockImplementation(async () => { + levelDuringList = ioHost.logLevel; + return []; + }); // WHEN - await toolkit.list([], { json: true }); + await toolkit.list([]); - // THEN - a one-shot suppressor for I1000 was registered that prevents default handling. - const i1000Call = onceSpy.mock.calls.find(([code]) => (code as any)?.code === 'CDK_TOOLKIT_I1000'); - expect(i1000Call).toBeDefined(); - const listener = i1000Call![1] as (msg: any) => any; - expect(listener({ code: 'CDK_TOOLKIT_I1000' })).toEqual({ preventDefault: true }); + // THEN - info-level messages are filtered out during the listing + expect(levelDuringList).toEqual('warn'); }); - test('without --json and not in CI, does not suppress the synthesis-time line', async () => { - ioHost.isCI = false; + test('restores the previous log level after listing', async () => { const toolkit = defaultToolkitSetup(); - const onceSpy = jest.spyOn(ioHost, 'once'); + ioHost.logLevel = 'info'; // WHEN await toolkit.list([]); - // THEN - const i1000Call = onceSpy.mock.calls.find(([code]) => (code as any)?.code === 'CDK_TOOLKIT_I1000'); - expect(i1000Call).toBeUndefined(); + // THEN - the temporary raise does not leak into later output (e.g. notices) + expect(ioHost.logLevel).toEqual('info'); }); - test('in CI mode without --json, suppresses the synthesis-time line', async () => { - ioHost.isCI = true; + test('restores the previous log level even if listing throws', async () => { const toolkit = defaultToolkitSetup(); - const onceSpy = jest.spyOn(ioHost, 'once'); + ioHost.logLevel = 'info'; + jest.spyOn(toolkit.toolkit, 'list').mockRejectedValue(new Error('boom')); - // WHEN - await toolkit.list([]); - - // THEN - const i1000Call = onceSpy.mock.calls.find(([code]) => (code as any)?.code === 'CDK_TOOLKIT_I1000'); - expect(i1000Call).toBeDefined(); - const listener = i1000Call![1] as (msg: any) => any; - expect(listener({ code: 'CDK_TOOLKIT_I1000' })).toEqual({ preventDefault: true }); + // WHEN / THEN + await expect(toolkit.list([])).rejects.toThrow('boom'); + expect(ioHost.logLevel).toEqual('info'); }); }); From 492d31fdf6527e070d4e0efe0d20efd62186e8e9 Mon Sep 17 00:00:00 2001 From: Sai Ray Date: Tue, 23 Jun 2026 20:47:40 -0400 Subject: [PATCH 4/9] chore: midwork --- packages/aws-cdk/test/cli/cdk-toolkit.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts index 3009445f0..e223e7d5a 100644 --- a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts @@ -221,7 +221,7 @@ describe('list', () => { // listing, the log level is raised to warn so they never reach stdout next to the listing. const toolkit = defaultToolkitSetup(); let levelDuringList: string | undefined; - jest.spyOn(toolkit.toolkit, 'list').mockImplementation(async () => { + jest.spyOn(toolkit['toolkit'], 'list').mockImplementation(async () => { levelDuringList = ioHost.logLevel; return []; }); @@ -247,7 +247,7 @@ describe('list', () => { test('restores the previous log level even if listing throws', async () => { const toolkit = defaultToolkitSetup(); ioHost.logLevel = 'info'; - jest.spyOn(toolkit.toolkit, 'list').mockRejectedValue(new Error('boom')); + jest.spyOn(toolkit['toolkit'], 'list').mockRejectedValue(new Error('boom')); // WHEN / THEN await expect(toolkit.list([])).rejects.toThrow('boom'); From b0613de9bb5fa38b664ca8c927f8eff3637b2092 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 00:54:58 +0000 Subject: [PATCH 5/9] chore: self mutation Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- packages/aws-cdk/test/cli/cdk-toolkit.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts index e223e7d5a..3009445f0 100644 --- a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts @@ -221,7 +221,7 @@ describe('list', () => { // listing, the log level is raised to warn so they never reach stdout next to the listing. const toolkit = defaultToolkitSetup(); let levelDuringList: string | undefined; - jest.spyOn(toolkit['toolkit'], 'list').mockImplementation(async () => { + jest.spyOn(toolkit.toolkit, 'list').mockImplementation(async () => { levelDuringList = ioHost.logLevel; return []; }); @@ -247,7 +247,7 @@ describe('list', () => { test('restores the previous log level even if listing throws', async () => { const toolkit = defaultToolkitSetup(); ioHost.logLevel = 'info'; - jest.spyOn(toolkit['toolkit'], 'list').mockRejectedValue(new Error('boom')); + jest.spyOn(toolkit.toolkit, 'list').mockRejectedValue(new Error('boom')); // WHEN / THEN await expect(toolkit.list([])).rejects.toThrow('boom'); From 360f40a93bcb588aa8b1a1fd92724abaa9f771cc Mon Sep 17 00:00:00 2001 From: Sai Ray Date: Tue, 23 Jun 2026 21:17:12 -0400 Subject: [PATCH 6/9] chore: midwork --- packages/aws-cdk/test/cli/cdk-toolkit.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts index 3009445f0..1ff1f9437 100644 --- a/packages/aws-cdk/test/cli/cdk-toolkit.test.ts +++ b/packages/aws-cdk/test/cli/cdk-toolkit.test.ts @@ -221,7 +221,7 @@ describe('list', () => { // listing, the log level is raised to warn so they never reach stdout next to the listing. const toolkit = defaultToolkitSetup(); let levelDuringList: string | undefined; - jest.spyOn(toolkit.toolkit, 'list').mockImplementation(async () => { + const listSpy = jest.spyOn(Toolkit.prototype, 'list').mockImplementation(async () => { levelDuringList = ioHost.logLevel; return []; }); @@ -231,6 +231,7 @@ describe('list', () => { // THEN - info-level messages are filtered out during the listing expect(levelDuringList).toEqual('warn'); + listSpy.mockRestore(); }); test('restores the previous log level after listing', async () => { @@ -247,11 +248,12 @@ describe('list', () => { test('restores the previous log level even if listing throws', async () => { const toolkit = defaultToolkitSetup(); ioHost.logLevel = 'info'; - jest.spyOn(toolkit.toolkit, 'list').mockRejectedValue(new Error('boom')); + const listSpy = jest.spyOn(Toolkit.prototype, 'list').mockRejectedValue(new Error('boom')); // WHEN / THEN await expect(toolkit.list([])).rejects.toThrow('boom'); expect(ioHost.logLevel).toEqual('info'); + listSpy.mockRestore(); }); }); From a50be7b8297fb53d043299408bc6b4617c2a1a47 Mon Sep 17 00:00:00 2001 From: Sai Ray Date: Tue, 23 Jun 2026 21:31:44 -0400 Subject: [PATCH 7/9] chore: midwork --- ...ls-ci-no-synth-time-on-stdout.integtest.ts | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts index d825f64a8..2a3a405d5 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts @@ -1,24 +1,18 @@ import { integTest, withDefaultFixture } from '../../../lib'; integTest( - 'cdk ls in CI prints only the stack listing to stdout', + 'cdk ls prints only the stack listing, no status lines', withDefaultFixture(async (fixture) => { - // In CI, stdout must be only the stack listing, not status lines (issue #38165). - // `*list-stacks` is selected because it pulls in a dependency, exercising that path too. - for (const args of [['ls'], ['ls', '--json'], ['ls', `${fixture.stackNamePrefix}-list-stacks`]]) { - const listing = await fixture.cdk(args, { - verbose: false, // turn off so stdout is just the listing - captureStderr: false, // capture stdout only - modEnv: { CI: 'true' }, // CI routes non-error output to stdout - }); + // issue #38165. `*list-stacks` is selected because it pulls in a dependency. + for (const ci of ['true', 'false']) { + for (const args of [['ls'], ['ls', '--json'], ['ls', `${fixture.stackNamePrefix}-list-stacks`]]) { + const output = await fixture.cdk(args, { + verbose: false, + modEnv: { CI: ci }, + }); - expect(listing).not.toContain('Synthesis time'); - expect(listing).not.toContain('Including dependency stacks'); - - const lines = listing.trim().split('\n').filter(line => line.length > 0); - expect(lines.length).toBeGreaterThan(0); - for (const line of lines) { - expect(line).toContain(fixture.stackNamePrefix); + expect(output).not.toContain('Synthesis time'); + expect(output).not.toContain('Including dependency stacks'); } } }), From 101d15873bacc743a2ea25730710cda9054a6bc3 Mon Sep 17 00:00:00 2001 From: Sai Ray Date: Tue, 23 Jun 2026 21:35:53 -0400 Subject: [PATCH 8/9] chore: midwork --- ...tegtest.ts => cdk-cdk-ls-only-stack-listing.integtest.ts} | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/{cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts => cdk-cdk-ls-only-stack-listing.integtest.ts} (62%) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-only-stack-listing.integtest.ts similarity index 62% rename from packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts rename to packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-only-stack-listing.integtest.ts index 2a3a405d5..c1d194691 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-ci-no-synth-time-on-stdout.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-only-stack-listing.integtest.ts @@ -3,9 +3,10 @@ import { integTest, withDefaultFixture } from '../../../lib'; integTest( 'cdk ls prints only the stack listing, no status lines', withDefaultFixture(async (fixture) => { - // issue #38165. `*list-stacks` is selected because it pulls in a dependency. + // `cdk ls` output should be the stack listing only, never status lines like the synth time + // or "Including dependency stacks". `*list-stacks` is selected because it pulls in a dependency. for (const ci of ['true', 'false']) { - for (const args of [['ls'], ['ls', '--json'], ['ls', `${fixture.stackNamePrefix}-list-stacks`]]) { + for (const args of [['ls'], ['ls', `${fixture.stackNamePrefix}-list-stacks`]]) { const output = await fixture.cdk(args, { verbose: false, modEnv: { CI: ci }, From 41a44b63dcb7ea032e4df41e25573be15cfcbf2d Mon Sep 17 00:00:00 2001 From: Sai Ray Date: Tue, 23 Jun 2026 21:50:13 -0400 Subject: [PATCH 9/9] chore: midwork --- ...cdk-cdk-ls-only-stack-listing.integtest.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-only-stack-listing.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-only-stack-listing.integtest.ts index c1d194691..650af13b5 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-only-stack-listing.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/list/cdk-cdk-ls-only-stack-listing.integtest.ts @@ -5,15 +5,21 @@ integTest( withDefaultFixture(async (fixture) => { // `cdk ls` output should be the stack listing only, never status lines like the synth time // or "Including dependency stacks". `*list-stacks` is selected because it pulls in a dependency. - for (const ci of ['true', 'false']) { - for (const args of [['ls'], ['ls', `${fixture.stackNamePrefix}-list-stacks`]]) { - const output = await fixture.cdk(args, { - verbose: false, - modEnv: { CI: ci }, - }); + for (const args of [['ls'], ['ls', `${fixture.stackNamePrefix}-list-stacks`]]) { + const output = await fixture.cdk(args, { + verbose: false, + modEnv: { CI: 'true' }, + }); - expect(output).not.toContain('Synthesis time'); - expect(output).not.toContain('Including dependency stacks'); + // no status lines + expect(output).not.toContain('Synthesis time'); + expect(output).not.toContain('Including dependency stacks'); + + // every line should be a stack + const lines = output.trim().split('\n').filter(line => line.length > 0); + expect(lines.length).toBeGreaterThan(0); + for (const line of lines) { + expect(line).toContain(fixture.stackNamePrefix); } } }),