From 16d75dcfdae26d56b792fc0e597f1a360e29716b Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 11 Apr 2022 12:03:49 +0200 Subject: [PATCH 1/2] fix(cli): stack monitor prints over errors In #19742, we limited the amount of text that the status printer would produce, and tried to get rid of the empty lines at the end of the rewritable block as well. Unfortunately, we scrolled up too far, overwriting the error messages that may occur during resource provisioning. Since these were the only place where error messages were displayed, it is now not possible to see why a stack deployment fails. This PR fixes that. --- .../cloudformation/stack-activity-monitor.ts | 8 +++-- packages/aws-cdk/lib/api/util/display.ts | 33 +++++++++---------- .../aws-cdk/test/api/util/display.test.ts | 23 +++++++++++++ 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts index d67105ed46a88..3ac92e15ba706 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts @@ -621,6 +621,10 @@ export class CurrentActivityPrinter extends ActivityPrinterBase { const color = colorFromStatusActivity(res.event.ResourceStatus); const resourceName = res.metadata?.constructPath ?? res.event.LogicalResourceId ?? ''; + if (hasErrorMessage(res.event.ResourceStatus ?? '')) { + debugger; + } + return util.format('%s | %s | %s | %s%s', padLeft(TIMESTAMP_WIDTH, new Date(res.event.Timestamp).toLocaleTimeString()), color(padRight(STATUS_WIDTH, (res.event.ResourceStatus || '').slice(0, STATUS_WIDTH))), @@ -665,7 +669,7 @@ export class CurrentActivityPrinter extends ActivityPrinterBase { // Display in the same block space, otherwise we're going to have silly empty lines. this.block.displayLines(lines); - this.block.removeEmptyLines(lines); + this.block.removeEmptyLines(); } private progressBar(width: number) { @@ -728,7 +732,7 @@ function colorFromStatusActivity(status?: string) { return chalk.red; } - if (status.startsWith('CREATE_') || status.startsWith('UPDATE_')) { + if (status.startsWith('CREATE_') || status.startsWith('UPDATE_') || status.startsWith('IMPORT_')) { return chalk.green; } // For stacks, it may also be 'UPDDATE_ROLLBACK_IN_PROGRESS' diff --git a/packages/aws-cdk/lib/api/util/display.ts b/packages/aws-cdk/lib/api/util/display.ts index a7071ed6a12a4..44e5b6c9fb1c0 100644 --- a/packages/aws-cdk/lib/api/util/display.ts +++ b/packages/aws-cdk/lib/api/util/display.ts @@ -7,6 +7,7 @@ const wrapAnsi = require('wrap-ansi'); */ export class RewritableBlock { private lastHeight = 0; + private trailingEmptyLines = 0; constructor(private readonly stream: NodeJS.WriteStream) { } @@ -22,14 +23,18 @@ export class RewritableBlock { } public displayLines(lines: string[]) { - lines = terminalWrap(this.width, expandNewlines(lines)).slice(0, getMaxBlockHeight(this.height, this.lastHeight, lines)); + lines = terminalWrap(this.width, expandNewlines(lines)); + lines = lines.slice(0, getMaxBlockHeight(this.height, this.lastHeight, lines)); this.stream.write(cursorUp(this.lastHeight)); for (const line of lines) { this.stream.write(cll() + line + '\n'); } + + this.trailingEmptyLines = Math.max(0, this.lastHeight - lines.length); + // Clear remainder of unwritten lines - for (let i = 0; i < this.lastHeight - lines.length; i++) { + for (let i = 0; i < this.trailingEmptyLines; i++) { this.stream.write(cll() + '\n'); } @@ -37,8 +42,8 @@ export class RewritableBlock { this.lastHeight = Math.max(this.lastHeight, lines.length); } - public removeEmptyLines(lines: string[]) { - this.stream.write(cursorUp(this.lastHeight - lines.length)); + public removeEmptyLines() { + this.stream.write(cursorUp(this.trailingEmptyLines)); } } @@ -62,26 +67,18 @@ function cll() { function terminalWrap(width: number | undefined, lines: string[]) { if (width === undefined) { return lines; } - const ret = new Array(); - for (const line of lines) { - ret.push(...wrapAnsi(line, width - 1, { - hard: true, - trim: true, - wordWrap: false, - }).split('\n')); - } - return ret; + return lines.flatMap(line => wrapAnsi(line, width - 1, { + hard: true, + trim: true, + wordWrap: false, + }).split('\n')); } /** * Make sure there are no hidden newlines in the gin strings */ function expandNewlines(lines: string[]): string[] { - const ret = new Array(); - for (const line of lines) { - ret.push(...line.split('\n')); - } - return ret; + return lines.flatMap(line => line.split('\n')); } function getMaxBlockHeight(windowHeight: number | undefined, lastHeight: number, lines: string[]): number { diff --git a/packages/aws-cdk/test/api/util/display.test.ts b/packages/aws-cdk/test/api/util/display.test.ts index 26b54b736b104..4d116078f18df 100644 --- a/packages/aws-cdk/test/api/util/display.test.ts +++ b/packages/aws-cdk/test/api/util/display.test.ts @@ -36,4 +36,27 @@ describe('Rewritable Block Tests', () => { expect(output.length).toEqual(6); }); + + test('display accounts for newlines in output', () => { + const output = stderr.inspectSync(() => { + block.displayLines(['before\nafter']); + }); + expect(output.length).toEqual(3); // cursorup + 2 lines + }); + + test('removeEmptyLines only removes trailing lines', () => { + stderr.inspectSync(() => { + block.displayLines(Array.from(Array(5).keys()).map(x => `${x}`)); + }); + stderr.inspectSync(() => { + // Leaves 3 empty lines + block.displayLines(Array.from(Array(2).keys()).map(x => `${x}`)); + }); + + const output = stderr.inspectSync(() => { + block.removeEmptyLines(); + }); + const expectedEmptyLines = 3; + expect(JSON.stringify(output)).toEqual(JSON.stringify([`\u001b[${expectedEmptyLines}A`])); + }); }); \ No newline at end of file From b3f6006ba2772b1f215192c142152c70c9627a85 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 12 Apr 2022 10:49:02 +0200 Subject: [PATCH 2/2] Update stack-activity-monitor.ts --- .../lib/api/util/cloudformation/stack-activity-monitor.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts index 3ac92e15ba706..d99a299e159fa 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.ts @@ -621,10 +621,6 @@ export class CurrentActivityPrinter extends ActivityPrinterBase { const color = colorFromStatusActivity(res.event.ResourceStatus); const resourceName = res.metadata?.constructPath ?? res.event.LogicalResourceId ?? ''; - if (hasErrorMessage(res.event.ResourceStatus ?? '')) { - debugger; - } - return util.format('%s | %s | %s | %s%s', padLeft(TIMESTAMP_WIDTH, new Date(res.event.Timestamp).toLocaleTimeString()), color(padRight(STATUS_WIDTH, (res.event.ResourceStatus || '').slice(0, STATUS_WIDTH))),