From 36414be368f45312818f9e775218cea1a40caa3c Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Tue, 12 Nov 2024 16:00:31 -0300 Subject: [PATCH 1/8] feat: render test failure counter --- src/utils/deployStages.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utils/deployStages.ts b/src/utils/deployStages.ts index dd2b3da8..09bf4f10 100644 --- a/src/utils/deployStages.ts +++ b/src/utils/deployStages.ts @@ -129,7 +129,7 @@ export class DeployStages { type: 'dynamic-key-value', }, { - label: 'Tests', + label: 'Completed', get: (data): string | undefined => data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestsCompleted ? formatProgress(data?.mdapiDeploy?.numberTestsCompleted, data?.mdapiDeploy?.numberTestsTotal) @@ -137,6 +137,15 @@ export class DeployStages { stage: 'Running Tests', type: 'dynamic-key-value', }, + { + label: 'Failures', + get: (data): string | undefined => + data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors + ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + : undefined, + stage: 'Running Tests', + type: 'dynamic-key-value', + }, { label: 'Members', get: (data): string | undefined => From d95f0a348b1bb789ca81ae0c2b25a3f2360d3b71 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Wed, 27 Nov 2024 13:25:26 -0300 Subject: [PATCH 2/8] feat: show test failures while polling for status --- src/formatters/testResultsFormatter.ts | 6 ++-- src/utils/deployStages.ts | 42 +++++++++++++++++++++++--- src/utils/types.ts | 4 +++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/formatters/testResultsFormatter.ts b/src/formatters/testResultsFormatter.ts index c3ae12fb..c675055d 100644 --- a/src/formatters/testResultsFormatter.ts +++ b/src/formatters/testResultsFormatter.ts @@ -18,7 +18,7 @@ import { Successes, } from '@salesforce/source-deploy-retrieve'; import { ensureArray } from '@salesforce/kit'; -import { TestLevel, Verbosity } from '../utils/types.js'; +import { isTruthy, TestLevel, Verbosity } from '../utils/types.js'; import { tableHeader, error, success, check } from '../utils/output.js'; import { coverageOutput } from '../utils/coverage.js'; @@ -45,7 +45,9 @@ export class TestResultsFormatter { return; } - displayVerboseTestFailures(this.result.response); + if (!isTruthy(process.env.CI)) { + displayVerboseTestFailures(this.result.response); + } if (this.verbosity === 'verbose') { displayVerboseTestSuccesses(this.result.response.details.runTestResult?.successes); diff --git a/src/utils/deployStages.ts b/src/utils/deployStages.ts index 09bf4f10..2d7c605c 100644 --- a/src/utils/deployStages.ts +++ b/src/utils/deployStages.ts @@ -4,12 +4,22 @@ * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ +import os from 'node:os'; import { MultiStageOutput } from '@oclif/multi-stage-output'; import { Lifecycle, Messages } from '@salesforce/core'; -import { MetadataApiDeploy, MetadataApiDeployStatus, RequestStatus } from '@salesforce/source-deploy-retrieve'; +import { + Failures, + MetadataApiDeploy, + MetadataApiDeployStatus, + RequestStatus, + Successes, +} from '@salesforce/source-deploy-retrieve'; import { SourceMemberPollingEvent } from '@salesforce/source-tracking'; import terminalLink from 'terminal-link'; +import { ensureArray } from '@salesforce/kit'; +import ansis from 'ansis'; import { getZipFileSize } from './output.js'; +import { isTruthy } from './types.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const mdTransferMessages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'metadata.transfer'); @@ -129,7 +139,7 @@ export class DeployStages { type: 'dynamic-key-value', }, { - label: 'Completed', + label: 'Successful', get: (data): string | undefined => data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestsCompleted ? formatProgress(data?.mdapiDeploy?.numberTestsCompleted, data?.mdapiDeploy?.numberTestsTotal) @@ -138,10 +148,11 @@ export class DeployStages { type: 'dynamic-key-value', }, { - label: 'Failures', + label: 'Failed', get: (data): string | undefined => data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors - ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + + (isTruthy(process.env.CI) ? os.EOL + formatTestFailures(data) : '') : undefined, stage: 'Running Tests', type: 'dynamic-key-value', @@ -241,3 +252,26 @@ export class DeployStages { this.mso.skipTo('Done', data); } } + +function formatTestFailures(data: Data): string { + if (data.mdapiDeploy.details.runTestResult?.failures === undefined) return ''; + const failures = ensureArray(data.mdapiDeploy.details.runTestResult?.failures).sort(testResultSort); + + let output = ''; + + for (const test of failures) { + const testName = ansis.underline(`${test.name}.${test.methodName}`); + output += ` • ${testName}${os.EOL}`; + output += ` message: ${test.message}${os.EOL}`; + if (test.stackTrace) { + const stackTrace = test.stackTrace.replace(/\n/g, `${os.EOL} `); + output += ` stacktrace:${os.EOL} ${stackTrace}${os.EOL}${os.EOL}`; + } + } + + // remove last EOL char + return output.slice(0, -1); +} + +const testResultSort = (a: T, b: T): number => + a.methodName === b.methodName ? a.name.localeCompare(b.name) : a.methodName.localeCompare(b.methodName); diff --git a/src/utils/types.ts b/src/utils/types.ts index e8a7a8c9..10a4ad62 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -124,3 +124,7 @@ export const isFileResponseDeleted = (fileResponse: FileResponseSuccess): boolea fileResponse.state === ComponentStatus.Deleted; export const isDefined = (value?: T): value is T => value !== undefined; + +export function isTruthy(value: string | undefined): boolean { + return value !== '0' && value !== 'false'; +} From ed04d334bc6e7465943bac633aad444d917c7ef2 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Thu, 28 Nov 2024 18:00:31 -0300 Subject: [PATCH 3/8] fix: improve CI output, handle verbose output --- src/commands/project/delete/source.ts | 1 + src/commands/project/deploy/resume.ts | 1 + src/commands/project/deploy/start.ts | 1 + src/commands/project/deploy/validate.ts | 1 + src/formatters/testResultsFormatter.ts | 11 +++--- src/utils/deployStages.ts | 48 +++++++++++++++++-------- 6 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/commands/project/delete/source.ts b/src/commands/project/delete/source.ts index 103cc03d..d53e5426 100644 --- a/src/commands/project/delete/source.ts +++ b/src/commands/project/delete/source.ts @@ -248,6 +248,7 @@ export class Source extends SfCommand { const stages = new DeployStages({ title: 'Deleting Metadata', jsonEnabled: this.jsonEnabled(), + verbose: this.flags['verbose'], }); const isRest = (await resolveApi()) === API['REST']; diff --git a/src/commands/project/deploy/resume.ts b/src/commands/project/deploy/resume.ts index f24fcd26..143c7cda 100644 --- a/src/commands/project/deploy/resume.ts +++ b/src/commands/project/deploy/resume.ts @@ -134,6 +134,7 @@ export default class DeployMetadataResume extends SfCommand { new DeployStages({ title: 'Resuming Deploy', jsonEnabled: this.jsonEnabled(), + verbose: flags.verbose, }).start( { deploy, diff --git a/src/commands/project/deploy/start.ts b/src/commands/project/deploy/start.ts index e0133378..559bd94e 100644 --- a/src/commands/project/deploy/start.ts +++ b/src/commands/project/deploy/start.ts @@ -250,6 +250,7 @@ export default class DeployMetadata extends SfCommand { this.stages = new DeployStages({ title, jsonEnabled: this.jsonEnabled(), + verbose: flags['verbose'], }); this.deployUrl = buildDeployUrl(flags['target-org'], deploy.id); diff --git a/src/commands/project/deploy/validate.ts b/src/commands/project/deploy/validate.ts index 1f52f422..3bb15b57 100644 --- a/src/commands/project/deploy/validate.ts +++ b/src/commands/project/deploy/validate.ts @@ -211,6 +211,7 @@ export default class DeployMetadataValidate extends SfCommand new DeployStages({ title: 'Validating Deployment', jsonEnabled: this.jsonEnabled(), + verbose: flags.verbose, }).start( { deploy, diff --git a/src/formatters/testResultsFormatter.ts b/src/formatters/testResultsFormatter.ts index c675055d..67513d6f 100644 --- a/src/formatters/testResultsFormatter.ts +++ b/src/formatters/testResultsFormatter.ts @@ -18,9 +18,10 @@ import { Successes, } from '@salesforce/source-deploy-retrieve'; import { ensureArray } from '@salesforce/kit'; -import { isTruthy, TestLevel, Verbosity } from '../utils/types.js'; +import { TestLevel, Verbosity } from '../utils/types.js'; import { tableHeader, error, success, check } from '../utils/output.js'; import { coverageOutput } from '../utils/coverage.js'; +import { isCI } from '../utils/deployStages.js'; const ux = new Ux(); @@ -45,12 +46,14 @@ export class TestResultsFormatter { return; } - if (!isTruthy(process.env.CI)) { + if (!isCI()) { displayVerboseTestFailures(this.result.response); } if (this.verbosity === 'verbose') { - displayVerboseTestSuccesses(this.result.response.details.runTestResult?.successes); + if (!isCI()) { + displayVerboseTestSuccesses(this.result.response.details.runTestResult?.successes); + } displayVerboseTestCoverage(this.result.response.details.runTestResult?.codeCoverage); } @@ -124,7 +127,7 @@ const displayVerboseTestCoverage = (coverage?: CodeCoverage | CodeCoverage[]): v } }; -const testResultSort = (a: T, b: T): number => +export const testResultSort = (a: T, b: T): number => a.methodName === b.methodName ? a.name.localeCompare(b.name) : a.methodName.localeCompare(b.methodName); const coverageSort = (a: CodeCoverage, b: CodeCoverage): number => diff --git a/src/utils/deployStages.ts b/src/utils/deployStages.ts index 2d7c605c..73615e5f 100644 --- a/src/utils/deployStages.ts +++ b/src/utils/deployStages.ts @@ -7,18 +7,13 @@ import os from 'node:os'; import { MultiStageOutput } from '@oclif/multi-stage-output'; import { Lifecycle, Messages } from '@salesforce/core'; -import { - Failures, - MetadataApiDeploy, - MetadataApiDeployStatus, - RequestStatus, - Successes, -} from '@salesforce/source-deploy-retrieve'; +import { MetadataApiDeploy, MetadataApiDeployStatus, RequestStatus } from '@salesforce/source-deploy-retrieve'; import { SourceMemberPollingEvent } from '@salesforce/source-tracking'; import terminalLink from 'terminal-link'; import { ensureArray } from '@salesforce/kit'; import ansis from 'ansis'; -import { getZipFileSize } from './output.js'; +import { testResultSort } from '../formatters/testResultsFormatter.js'; +import { check, getZipFileSize } from './output.js'; import { isTruthy } from './types.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); @@ -27,6 +22,7 @@ const mdTransferMessages = Messages.loadMessages('@salesforce/plugin-deploy-retr type Options = { title: string; jsonEnabled: boolean; + verbose?: boolean; }; type Data = { @@ -58,7 +54,7 @@ function formatProgress(current: number, total: number): string { export class DeployStages { private mso: MultiStageOutput; - public constructor({ title, jsonEnabled }: Options) { + public constructor({ title, jsonEnabled, verbose }: Options) { this.mso = new MultiStageOutput({ title, stages: [ @@ -142,7 +138,8 @@ export class DeployStages { label: 'Successful', get: (data): string | undefined => data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestsCompleted - ? formatProgress(data?.mdapiDeploy?.numberTestsCompleted, data?.mdapiDeploy?.numberTestsTotal) + ? formatProgress(data?.mdapiDeploy?.numberTestsCompleted, data?.mdapiDeploy?.numberTestsTotal) + + (verbose && isCI() ? os.EOL + formatTestSuccesses(data) : '') : undefined, stage: 'Running Tests', type: 'dynamic-key-value', @@ -152,7 +149,7 @@ export class DeployStages { get: (data): string | undefined => data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + - (isTruthy(process.env.CI) ? os.EOL + formatTestFailures(data) : '') + (isCI() ? os.EOL + formatTestFailures(data) : '') : undefined, stage: 'Running Tests', type: 'dynamic-key-value', @@ -253,8 +250,22 @@ export class DeployStages { } } +function formatTestSuccesses(data: Data): string { + const successes = ensureArray(data.mdapiDeploy.details.runTestResult?.successes).sort(testResultSort); + + let output = ''; + + if (successes.length > 0) { + for (const test of successes) { + const testName = ansis.underline(`${test.name}.${test.methodName}`); + output += ` ${check} ${testName}${os.EOL}`; + } + } + + return output; +} + function formatTestFailures(data: Data): string { - if (data.mdapiDeploy.details.runTestResult?.failures === undefined) return ''; const failures = ensureArray(data.mdapiDeploy.details.runTestResult?.failures).sort(testResultSort); let output = ''; @@ -273,5 +284,14 @@ function formatTestFailures(data: Data): string { return output.slice(0, -1); } -const testResultSort = (a: T, b: T): number => - a.methodName === b.methodName ? a.name.localeCompare(b.name) : a.methodName.localeCompare(b.methodName); +export function isCI(): boolean { + if ( + isTruthy(process.env.CI) && + ('CI' in process.env || + 'CONTINUOUS_INTEGRATION' in process.env || + Object.keys(process.env).some((key) => key.startsWith('CI_'))) + ) + return true; + + return false; +} From 7da1bdd4d0f6df227a81272f6c995aea37138f95 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Mon, 9 Dec 2024 15:05:59 -0300 Subject: [PATCH 4/8] chore: dedup failures on mso --- src/utils/deployStages.ts | 59 +++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/utils/deployStages.ts b/src/utils/deployStages.ts index 73615e5f..093c6bff 100644 --- a/src/utils/deployStages.ts +++ b/src/utils/deployStages.ts @@ -7,7 +7,12 @@ import os from 'node:os'; import { MultiStageOutput } from '@oclif/multi-stage-output'; import { Lifecycle, Messages } from '@salesforce/core'; -import { MetadataApiDeploy, MetadataApiDeployStatus, RequestStatus } from '@salesforce/source-deploy-retrieve'; +import { + Failures, + MetadataApiDeploy, + MetadataApiDeployStatus, + RequestStatus, +} from '@salesforce/source-deploy-retrieve'; import { SourceMemberPollingEvent } from '@salesforce/source-tracking'; import terminalLink from 'terminal-link'; import { ensureArray } from '@salesforce/kit'; @@ -53,8 +58,10 @@ function formatProgress(current: number, total: number): string { export class DeployStages { private mso: MultiStageOutput; + private previousFailures: Set; public constructor({ title, jsonEnabled, verbose }: Options) { + this.previousFailures = new Set(); this.mso = new MultiStageOutput({ title, stages: [ @@ -146,11 +153,30 @@ export class DeployStages { }, { label: 'Failed', - get: (data): string | undefined => - data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors - ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + - (isCI() ? os.EOL + formatTestFailures(data) : '') - : undefined, + get: (data): string | undefined => { + let output = + data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors + ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + + (isCI() + ? os.EOL + formatTestFailures(ensureArray(data.mdapiDeploy.details.runTestResult?.failures)) + : '') + : undefined; + + console.log( + // @ts-ignore + `TO RENDER 2: ${data?.mdapiDeploy.details.runTestResult.failures.map((f) => `${f.name}.${f.methodName}`)}` + ); + console.log(data?.mdapiDeploy.numberTestsTotal); + console.log(data?.mdapiDeploy.numberTestErrors); + + if (Array.isArray(data?.mdapiDeploy.details.runTestResult?.failures)) { + data?.mdapiDeploy.details.runTestResult?.failures.forEach((f) => + this.previousFailures.add(`${f.name}.${f.methodName}`) + ); + } + + return output; + }, stage: 'Running Tests', type: 'dynamic-key-value', }, @@ -193,7 +219,22 @@ export class DeployStages { data.numberTestsTotal > 0 && data.numberComponentsDeployed > 0 ) { - this.mso.skipTo('Running Tests', { mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status) }); + const mdapiDeploy: MetadataApiDeployStatus = { + ...data, + }; + if ( + Array.isArray(mdapiDeploy.details.runTestResult?.failures) && + mdapiDeploy.details.runTestResult?.failures.length > 0 + ) { + mdapiDeploy.details.runTestResult.failures = mdapiDeploy.details.runTestResult?.failures.filter( + (f) => !this.previousFailures.has(`${f.name}.${f.methodName}`) + ); + + console.log( + `TO RENDER 1: ${mdapiDeploy.details.runTestResult.failures.map((f) => `${f.name}.${f.methodName}`)}` + ); + } + this.mso.skipTo('Running Tests', { mdapiDeploy, status: mdTransferMessages.getMessage(data?.status) }); } else if (data.status === RequestStatus.Pending) { this.mso.skipTo('Waiting for the org to respond', { mdapiDeploy: data, @@ -265,8 +306,8 @@ function formatTestSuccesses(data: Data): string { return output; } -function formatTestFailures(data: Data): string { - const failures = ensureArray(data.mdapiDeploy.details.runTestResult?.failures).sort(testResultSort); +function formatTestFailures(failuresData: Failures[]): string { + const failures = failuresData.sort(testResultSort); let output = ''; From fe0ec831f9c826cf477f5b5324885a72b9c63c71 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Thu, 12 Dec 2024 18:37:32 -0300 Subject: [PATCH 5/8] chore: refactor + skip dups --- src/utils/deployStages.ts | 66 ++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/utils/deployStages.ts b/src/utils/deployStages.ts index 093c6bff..8a0c899c 100644 --- a/src/utils/deployStages.ts +++ b/src/utils/deployStages.ts @@ -58,10 +58,14 @@ function formatProgress(current: number, total: number): string { export class DeployStages { private mso: MultiStageOutput; - private previousFailures: Set; + /** + * Set of Apex test failures that were already rendered in the `Running Tests` block. + * This is used in the `Failed` stage block for CI output to ensure test failures aren't duplicated when rendering new failures on polling. + */ + private printedApexTestFailures: Set; public constructor({ title, jsonEnabled, verbose }: Options) { - this.previousFailures = new Set(); + this.printedApexTestFailures = new Set(); this.mso = new MultiStageOutput({ title, stages: [ @@ -154,28 +158,35 @@ export class DeployStages { { label: 'Failed', get: (data): string | undefined => { - let output = - data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors - ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + - (isCI() - ? os.EOL + formatTestFailures(ensureArray(data.mdapiDeploy.details.runTestResult?.failures)) - : '') - : undefined; - - console.log( - // @ts-ignore - `TO RENDER 2: ${data?.mdapiDeploy.details.runTestResult.failures.map((f) => `${f.name}.${f.methodName}`)}` - ); - console.log(data?.mdapiDeploy.numberTestsTotal); - console.log(data?.mdapiDeploy.numberTestErrors); + let testFailures: Failures[] = []; + + // only render new test failures + if (isCI() && Array.isArray(data?.mdapiDeploy.details.runTestResult?.failures)) { + // skip failure counter/progress info if there's no new failures to render. + if ( + this.printedApexTestFailures.size > 0 && + data.mdapiDeploy.numberTestErrors === this.printedApexTestFailures.size + ) { + return undefined; + } + + testFailures = data.mdapiDeploy.details.runTestResult?.failures.filter( + (f) => !this.printedApexTestFailures.has(`${f.name}.${f.methodName}`) + ); - if (Array.isArray(data?.mdapiDeploy.details.runTestResult?.failures)) { data?.mdapiDeploy.details.runTestResult?.failures.forEach((f) => - this.previousFailures.add(`${f.name}.${f.methodName}`) + this.printedApexTestFailures.add(`${f.name}.${f.methodName}`) ); + + return data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors + ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + + (isCI() ? os.EOL + formatTestFailures(testFailures) : '') + : undefined; } - return output; + return data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestErrors + ? formatProgress(data?.mdapiDeploy?.numberTestErrors, data?.mdapiDeploy?.numberTestsTotal) + : undefined; }, stage: 'Running Tests', type: 'dynamic-key-value', @@ -219,22 +230,7 @@ export class DeployStages { data.numberTestsTotal > 0 && data.numberComponentsDeployed > 0 ) { - const mdapiDeploy: MetadataApiDeployStatus = { - ...data, - }; - if ( - Array.isArray(mdapiDeploy.details.runTestResult?.failures) && - mdapiDeploy.details.runTestResult?.failures.length > 0 - ) { - mdapiDeploy.details.runTestResult.failures = mdapiDeploy.details.runTestResult?.failures.filter( - (f) => !this.previousFailures.has(`${f.name}.${f.methodName}`) - ); - - console.log( - `TO RENDER 1: ${mdapiDeploy.details.runTestResult.failures.map((f) => `${f.name}.${f.methodName}`)}` - ); - } - this.mso.skipTo('Running Tests', { mdapiDeploy, status: mdTransferMessages.getMessage(data?.status) }); + this.mso.skipTo('Running Tests', { mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status) }); } else if (data.status === RequestStatus.Pending) { this.mso.skipTo('Waiting for the org to respond', { mdapiDeploy: data, From fcc83af585eca9fc8f47db48a827a645e7fed116 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Fri, 13 Dec 2024 15:13:28 -0300 Subject: [PATCH 6/8] chore: remove success on CI output for deploy --- src/commands/project/delete/source.ts | 1 - src/commands/project/deploy/resume.ts | 1 - src/commands/project/deploy/start.ts | 1 - src/commands/project/deploy/validate.ts | 1 - src/utils/deployStages.ts | 24 +++--------------------- 5 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/commands/project/delete/source.ts b/src/commands/project/delete/source.ts index d53e5426..103cc03d 100644 --- a/src/commands/project/delete/source.ts +++ b/src/commands/project/delete/source.ts @@ -248,7 +248,6 @@ export class Source extends SfCommand { const stages = new DeployStages({ title: 'Deleting Metadata', jsonEnabled: this.jsonEnabled(), - verbose: this.flags['verbose'], }); const isRest = (await resolveApi()) === API['REST']; diff --git a/src/commands/project/deploy/resume.ts b/src/commands/project/deploy/resume.ts index 143c7cda..f24fcd26 100644 --- a/src/commands/project/deploy/resume.ts +++ b/src/commands/project/deploy/resume.ts @@ -134,7 +134,6 @@ export default class DeployMetadataResume extends SfCommand { new DeployStages({ title: 'Resuming Deploy', jsonEnabled: this.jsonEnabled(), - verbose: flags.verbose, }).start( { deploy, diff --git a/src/commands/project/deploy/start.ts b/src/commands/project/deploy/start.ts index 559bd94e..e0133378 100644 --- a/src/commands/project/deploy/start.ts +++ b/src/commands/project/deploy/start.ts @@ -250,7 +250,6 @@ export default class DeployMetadata extends SfCommand { this.stages = new DeployStages({ title, jsonEnabled: this.jsonEnabled(), - verbose: flags['verbose'], }); this.deployUrl = buildDeployUrl(flags['target-org'], deploy.id); diff --git a/src/commands/project/deploy/validate.ts b/src/commands/project/deploy/validate.ts index 3bb15b57..1f52f422 100644 --- a/src/commands/project/deploy/validate.ts +++ b/src/commands/project/deploy/validate.ts @@ -211,7 +211,6 @@ export default class DeployMetadataValidate extends SfCommand new DeployStages({ title: 'Validating Deployment', jsonEnabled: this.jsonEnabled(), - verbose: flags.verbose, }).start( { deploy, diff --git a/src/utils/deployStages.ts b/src/utils/deployStages.ts index 8a0c899c..d38acfc3 100644 --- a/src/utils/deployStages.ts +++ b/src/utils/deployStages.ts @@ -15,10 +15,9 @@ import { } from '@salesforce/source-deploy-retrieve'; import { SourceMemberPollingEvent } from '@salesforce/source-tracking'; import terminalLink from 'terminal-link'; -import { ensureArray } from '@salesforce/kit'; import ansis from 'ansis'; import { testResultSort } from '../formatters/testResultsFormatter.js'; -import { check, getZipFileSize } from './output.js'; +import { getZipFileSize } from './output.js'; import { isTruthy } from './types.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); @@ -27,7 +26,6 @@ const mdTransferMessages = Messages.loadMessages('@salesforce/plugin-deploy-retr type Options = { title: string; jsonEnabled: boolean; - verbose?: boolean; }; type Data = { @@ -64,7 +62,7 @@ export class DeployStages { */ private printedApexTestFailures: Set; - public constructor({ title, jsonEnabled, verbose }: Options) { + public constructor({ title, jsonEnabled }: Options) { this.printedApexTestFailures = new Set(); this.mso = new MultiStageOutput({ title, @@ -149,8 +147,7 @@ export class DeployStages { label: 'Successful', get: (data): string | undefined => data?.mdapiDeploy?.numberTestsTotal && data?.mdapiDeploy?.numberTestsCompleted - ? formatProgress(data?.mdapiDeploy?.numberTestsCompleted, data?.mdapiDeploy?.numberTestsTotal) + - (verbose && isCI() ? os.EOL + formatTestSuccesses(data) : '') + ? formatProgress(data?.mdapiDeploy?.numberTestsCompleted, data?.mdapiDeploy?.numberTestsTotal) : undefined, stage: 'Running Tests', type: 'dynamic-key-value', @@ -287,21 +284,6 @@ export class DeployStages { } } -function formatTestSuccesses(data: Data): string { - const successes = ensureArray(data.mdapiDeploy.details.runTestResult?.successes).sort(testResultSort); - - let output = ''; - - if (successes.length > 0) { - for (const test of successes) { - const testName = ansis.underline(`${test.name}.${test.methodName}`); - output += ` ${check} ${testName}${os.EOL}`; - } - } - - return output; -} - function formatTestFailures(failuresData: Failures[]): string { const failures = failuresData.sort(testResultSort); From bf615815bdbfb8762e979eaa77f8965849a89bff Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Fri, 13 Dec 2024 19:09:22 -0300 Subject: [PATCH 7/8] fix: use `alwaysPrintInCI` for test failures block --- src/utils/deployStages.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/deployStages.ts b/src/utils/deployStages.ts index d38acfc3..b63849ed 100644 --- a/src/utils/deployStages.ts +++ b/src/utils/deployStages.ts @@ -154,6 +154,7 @@ export class DeployStages { }, { label: 'Failed', + alwaysPrintInCI: true, get: (data): string | undefined => { let testFailures: Failures[] = []; From d8cb1c466f3c1fd98752d758f4f6187a4778ec1c Mon Sep 17 00:00:00 2001 From: Mike Donnalley Date: Mon, 16 Dec 2024 10:11:39 -0700 Subject: [PATCH 8/8] chore: bump mso --- package.json | 2 +- yarn.lock | 88 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 55 insertions(+), 35 deletions(-) diff --git a/package.json b/package.json index b26914ec..1939288a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "bugs": "https://github.com/forcedotcom/cli/issues", "dependencies": { "@oclif/core": "^4.0.28", - "@oclif/multi-stage-output": "^0.7.12", + "@oclif/multi-stage-output": "^0.8.0", "@salesforce/apex-node": "^8.1.18", "@salesforce/core": "^8.6.4", "@salesforce/kit": "^3.2.3", diff --git a/yarn.lock b/yarn.lock index 0bb57733..dd1b7661 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1396,16 +1396,16 @@ wordwrap "^1.0.0" wrap-ansi "^7.0.0" -"@oclif/multi-stage-output@^0.7.12": - version "0.7.12" - resolved "https://registry.yarnpkg.com/@oclif/multi-stage-output/-/multi-stage-output-0.7.12.tgz#04df5efb6dce527920cf475c9ad9f20236803ccd" - integrity sha512-MmCgqPb7jC7QUOiX9jMik2njplCO+tRybGxiB55OXDmZ7osifM3KuQb/ykgP4XYn559k3DXeNLFS0NpokuH+mw== +"@oclif/multi-stage-output@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@oclif/multi-stage-output/-/multi-stage-output-0.8.0.tgz#868fcce009981afbb614b71246b80cd02c483782" + integrity sha512-B858dgCQPZWHRnzcU42t/cHq3u858UWMQk635qjn/lNlUpFDZKpoVgjVqLlGkQ9iEnqpwTXtyOXSYrLnPjVUeg== dependencies: "@oclif/core" "^4" "@types/react" "^18.3.12" cli-spinners "^2" figures "^6.1.0" - ink "^5.0.1" + ink "^5.1.0" react "^18.3.1" wrap-ansi "^9.0.0" @@ -4072,6 +4072,11 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es-toolkit@^1.22.0: + version "1.30.1" + resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.30.1.tgz#311be8eec88f53b0b1a9d40117f3f3c1e763e274" + integrity sha512-ZXflqanzH8BpHkDhFa10bBf6ONDCe84EPUm7SSICGzuuROSluT2ynTPtwn9PcRelMtorCRozSknI/U0MNYp0Uw== + es6-error@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" @@ -5239,6 +5244,36 @@ ink@^5.0.1: ws "^8.15.0" yoga-wasm-web "~0.3.3" +ink@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ink/-/ink-5.1.0.tgz#8ed050bf7a468489f231c99031f8bb1393c44079" + integrity sha512-3vIO+CU4uSg167/dZrg4wHy75llUINYXxN4OsdaCkE40q4zyOTPwNc2VEpLnnWsIvIQeo6x6lilAhuaSt+rIsA== + dependencies: + "@alcalzone/ansi-tokenize" "^0.1.3" + ansi-escapes "^7.0.0" + ansi-styles "^6.2.1" + auto-bind "^5.0.1" + chalk "^5.3.0" + cli-boxes "^3.0.0" + cli-cursor "^4.0.0" + cli-truncate "^4.0.0" + code-excerpt "^4.0.0" + es-toolkit "^1.22.0" + indent-string "^5.0.0" + is-in-ci "^1.0.0" + patch-console "^2.0.0" + react-reconciler "^0.29.0" + scheduler "^0.23.0" + signal-exit "^3.0.7" + slice-ansi "^7.1.0" + stack-utils "^2.0.6" + string-width "^7.2.0" + type-fest "^4.27.0" + widest-line "^5.0.0" + wrap-ansi "^9.0.0" + ws "^8.18.0" + yoga-wasm-web "~0.3.3" + internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" @@ -5373,6 +5408,11 @@ is-in-ci@^0.1.0: resolved "https://registry.yarnpkg.com/is-in-ci/-/is-in-ci-0.1.0.tgz#5e07d6a02ec3a8292d3f590973357efa3fceb0d3" integrity sha512-d9PXLEY0v1iJ64xLiQMJ51J128EYHAaOR4yZqQi8aHGfw6KgifM3/Viw1oZZ1GCVmb3gBuyhLyHj0HgR2DhSXQ== +is-in-ci@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-in-ci/-/is-in-ci-1.0.0.tgz#9a86bbda7e42c6129902e0574c54b018fbb6ab88" + integrity sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg== + is-inside-container@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" @@ -7786,16 +7826,7 @@ static-eval@2.0.2: dependencies: escodegen "^1.8.1" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7864,14 +7895,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -8164,6 +8188,11 @@ type-fest@^1.0.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== +type-fest@^4.27.0: + version "4.30.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.30.1.tgz#120b9e15177310ec4e9d5d6f187d86c0f4b55e0e" + integrity sha512-ojFL7eDMX2NF0xMbDwPZJ8sb7ckqtlAi1GsmgsFXvErT9kFTk1r0DuQKvrCh73M6D4nngeHJmvogF9OluXs7Hw== + type-fest@^4.8.3: version "4.26.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.26.1.tgz#a4a17fa314f976dd3e6d6675ef6c775c16d7955e" @@ -8472,7 +8501,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -8490,15 +8519,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -8532,7 +8552,7 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@^8.15.0: +ws@^8.15.0, ws@^8.18.0: version "8.18.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==