Skip to content

Commit 8ed9430

Browse files
WillieRuemmelemdonnalley
authored andcommitted
Merge pull request #1123 from salesforcecli/mdonnalley/ink
feat: use @oclif/multi-stage-output
1 parent a8db701 commit 8ed9430

File tree

11 files changed

+580
-201
lines changed

11 files changed

+580
-201
lines changed

messages/retrieve.start.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,6 @@ Extract all files from the retrieved zip file.
145145

146146
File name to use for the retrieved zip file.
147147

148-
# spinner.start
149-
150-
Preparing retrieve request
151-
152-
# spinner.sending
153-
154-
Sending request to org
155-
156-
# spinner.polling
157-
158-
Waiting for the org to respond
159-
160148
# error.Conflicts
161149

162150
There are changes in your local files that conflict with the org changes you're trying to retrieve.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"bugs": "https://github.com/forcedotcom/cli/issues",
77
"dependencies": {
88
"@oclif/core": "^4.0.18",
9+
"@oclif/multi-stage-output": "^0.4.3-dev.0",
910
"@salesforce/apex-node": "^8.1.3",
1011
"@salesforce/core": "^8.4.0",
1112
"@salesforce/kit": "^3.2.1",

src/commands/project/delete/source.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
requiredOrgFlagWithDeprecations,
3434
SfCommand,
3535
} from '@salesforce/sf-plugins-core';
36+
import { DeployStages } from '../../../utils/deployStages.js';
3637
import { writeConflictTable } from '../../../utils/conflicts.js';
3738
import { isNonDecomposedCustomLabel, isNonDecomposedCustomLabelsOrCustomLabel } from '../../../utils/metadataTypes.js';
3839
import { getFileResponseSuccessProps, tableHeader } from '../../../utils/output.js';
@@ -41,7 +42,6 @@ import { getPackageDirs, getSourceApiVersion } from '../../../utils/project.js';
4142
import { resolveApi, validateTests } from '../../../utils/deploy.js';
4243
import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js';
4344
import { DeleteResultFormatter } from '../../../formatters/deleteResultFormatter.js';
44-
import { DeployProgress } from '../../../utils/progressBar.js';
4545
import { DeployCache } from '../../../utils/deployCache.js';
4646
import { testLevelFlag, testsFlag } from '../../../utils/flags.js';
4747
const testFlags = 'Test';
@@ -244,8 +244,14 @@ export class Source extends SfCommand<DeleteSourceJson> {
244244

245245
// fire predeploy event for the delete
246246
await Lifecycle.getInstance().emit('predeploy', this.components);
247+
248+
const stages = new DeployStages({
249+
title: 'Deleting Metadata',
250+
jsonEnabled: this.jsonEnabled(),
251+
});
252+
247253
const isRest = (await resolveApi()) === API['REST'];
248-
this.log(`*** Deleting with ${isRest ? 'REST' : 'SOAP'} API ***`);
254+
stages.update({ message: `Deleting with ${isRest ? 'REST' : 'SOAP'} API` });
249255

250256
const deploy = await this.componentSet.deploy({
251257
usernameOrConnection: this.org.getUsername() as string,
@@ -257,7 +263,7 @@ export class Source extends SfCommand<DeleteSourceJson> {
257263
},
258264
});
259265

260-
new DeployProgress(deploy, this.jsonEnabled()).start();
266+
stages.start({ deploy, username: this.org.getUsername() });
261267
this.deployResult = await deploy.pollStatus({ timeout: this.flags.wait });
262268
if (!deploy.id) {
263269
throw new SfError('The deploy id is not available.');

src/commands/project/deploy/report.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import { Messages, Org, SfProject } from '@salesforce/core';
99
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
1010
import { ComponentSet, DeployResult, MetadataApiDeploy, RequestStatus } from '@salesforce/source-deploy-retrieve';
11+
import { DeployStages } from '../../../utils/deployStages.js';
1112
import { buildComponentSet } from '../../../utils/deploy.js';
12-
import { DeployProgress } from '../../../utils/progressBar.js';
1313
import { DeployCache } from '../../../utils/deployCache.js';
1414
import { DeployReportResultFormatter } from '../../../formatters/deployReportResultFormatter.js';
1515
import { API, DeployResultJson } from '../../../utils/types.js';
@@ -70,7 +70,7 @@ export default class DeployMetadataReport extends SfCommand<DeployResultJson> {
7070
const jobId = cache.resolveLatest(flags['use-most-recent'], flags['job-id'], false);
7171

7272
const deployOpts = cache.maybeGet(jobId);
73-
const wait = flags['wait'];
73+
const { wait } = flags;
7474
const org = deployOpts?.['target-org']
7575
? await Org.create({ aliasOrUsername: deployOpts['target-org'] })
7676
: flags['target-org'];
@@ -124,7 +124,10 @@ export default class DeployMetadataReport extends SfCommand<DeployResultJson> {
124124
if (wait) {
125125
// poll for deploy results
126126
try {
127-
new DeployProgress(mdapiDeploy, this.jsonEnabled()).start();
127+
new DeployStages({
128+
title: 'Deploying Metadata',
129+
jsonEnabled: this.jsonEnabled(),
130+
}).start({ deploy: mdapiDeploy, username: org.getUsername() });
128131
result = await mdapiDeploy.pollStatus(500, wait.seconds);
129132
} catch (error) {
130133
if (error instanceof Error && error.message.includes('The client has timed out')) {

src/commands/project/deploy/resume.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77

8-
import ansis from 'ansis';
98
import { EnvironmentVariable, Messages, Org, SfError } from '@salesforce/core';
109
import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core';
1110
import { DeployResult, MetadataApiDeploy } from '@salesforce/source-deploy-retrieve';
1211
import { Duration } from '@salesforce/kit';
12+
import { DeployStages } from '../../../utils/deployStages.js';
1313
import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js';
14-
import { DeployProgress } from '../../../utils/progressBar.js';
1514
import { API, DeployResultJson } from '../../../utils/types.js';
1615
import { buildComponentSet, determineExitCode, executeDeploy, isNotResumable } from '../../../utils/deploy.js';
1716
import { DeployCache } from '../../../utils/deployCache.js';
@@ -124,8 +123,11 @@ export default class DeployMetadataResume extends SfCommand<DeployResultJson> {
124123
jobId
125124
);
126125

127-
this.log(`Deploy ID: ${ansis.bold(jobId)}`);
128-
new DeployProgress(deploy, this.jsonEnabled()).start();
126+
new DeployStages({
127+
title: 'Resuming Deploy',
128+
jsonEnabled: this.jsonEnabled(),
129+
}).start({ deploy, username: deployOpts['target-org'] });
130+
129131
result = await deploy.pollStatus(500, wait.seconds);
130132

131133
if (!deploy.id) {

src/commands/project/deploy/start.ts

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@
44
* Licensed under the BSD 3-Clause license.
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
7-
8-
import ansis from 'ansis';
97
import { EnvironmentVariable, Lifecycle, Messages, OrgConfigProperties, SfError } from '@salesforce/core';
108
import { type DeployVersionData, DeployZipData } from '@salesforce/source-deploy-retrieve';
119
import { Duration } from '@salesforce/kit';
1210
import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core';
1311
import { SourceConflictError } from '@salesforce/source-tracking';
12+
import { DeployStages } from '../../../utils/deployStages.js';
1413
import { AsyncDeployResultFormatter } from '../../../formatters/asyncDeployResultFormatter.js';
1514
import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js';
1615
import { AsyncDeployResultJson, DeployResultJson, TestLevel } from '../../../utils/types.js';
17-
import { DeployProgress } from '../../../utils/progressBar.js';
1816
import { executeDeploy, resolveApi, validateTests, determineExitCode } from '../../../utils/deploy.js';
1917
import { DeployCache } from '../../../utils/deployCache.js';
2018
import { DEPLOY_STATUS_CODES_DESCRIPTIONS } from '../../../utils/errorCodes.js';
@@ -177,6 +175,8 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
177175

178176
public static errorCodes = toHelpSection('ERROR CODES', DEPLOY_STATUS_CODES_DESCRIPTIONS);
179177

178+
protected stages!: DeployStages;
179+
180180
private zipSize?: number;
181181
private zipFileCount?: number;
182182

@@ -201,33 +201,47 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
201201

202202
const api = await resolveApi(this.configAggregator);
203203
const username = flags['target-org'].getUsername();
204-
const action = flags['dry-run'] ? 'Deploying (dry-run)' : 'Deploying';
204+
const title = flags['dry-run'] ? 'Deploying Metadata (dry-run)' : 'Deploying Metadata';
205205

206-
// eslint-disable-next-line @typescript-eslint/require-await
207-
Lifecycle.getInstance().on('apiVersionDeploy', async (apiData: DeployVersionData) => {
208-
this.log(
209-
messages.getMessage('apiVersionMsgDetailed', [
210-
action,
211-
// technically manifestVersion can be undefined, but only on raw mdapi deployments.
212-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
213-
flags['metadata-dir'] ? '<version specified in manifest>' : `v${apiData.manifestVersion}`,
214-
username,
215-
apiData.apiVersion,
216-
apiData.webService,
217-
])
218-
);
206+
this.stages = new DeployStages({
207+
title,
208+
jsonEnabled: this.jsonEnabled(),
219209
});
220-
210+
const lifecycle = Lifecycle.getInstance();
221211
// eslint-disable-next-line @typescript-eslint/require-await
222-
Lifecycle.getInstance().on('deployZipData', async (zipData: DeployZipData) => {
212+
lifecycle.on('deployZipData', async (zipData: DeployZipData) => {
223213
this.zipSize = zipData.zipSize;
224-
if (flags.verbose && this.zipSize) this.log(`Deploy size: ${getZipFileSize(this.zipSize)} of ~39 MB limit`);
214+
if (flags.verbose && this.zipSize) {
215+
this.stages.update({
216+
deploySize: `${getZipFileSize(this.zipSize)} of ~39 MB limit`,
217+
});
218+
}
225219
if (zipData.zipFileCount) {
226220
this.zipFileCount = zipData.zipFileCount;
227-
if (flags.verbose && this.zipSize) this.log(`Deployed files count: ${this.zipFileCount} of 10,000 limit`);
221+
if (flags.verbose && this.zipSize) {
222+
this.stages.update({
223+
deployFileCount: `${this.zipFileCount} of 10,000 limit`,
224+
});
225+
}
228226
}
229227
});
230228

229+
lifecycle.on('apiVersionDeploy', async (apiData: DeployVersionData) =>
230+
Promise.resolve(
231+
this.stages.update({
232+
message: messages.getMessage('apiVersionMsgDetailed', [
233+
flags['dry-run'] ? 'Deploying (dry-run)' : 'Deploying',
234+
// technically manifestVersion can be undefined, but only on raw mdapi deployments.
235+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
236+
flags['metadata-dir'] ? '<version specified in manifest>' : `v${apiData.manifestVersion}`,
237+
username,
238+
apiData.apiVersion,
239+
apiData.webService,
240+
]),
241+
})
242+
)
243+
);
244+
231245
const { deploy } = await executeDeploy(
232246
{
233247
...flags,
@@ -238,16 +252,20 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
238252
);
239253

240254
if (!deploy) {
255+
this.stages.stop();
241256
this.log('No changes to deploy');
242257
return { status: 'Nothing to deploy', files: [] };
243258
}
244259

245260
if (!deploy.id) {
246261
throw new SfError('The deploy id is not available.');
247262
}
248-
this.log(`Deploy ID: ${ansis.bold(deploy.id)}`);
263+
264+
this.stages.start({ username, deploy });
249265

250266
if (flags.async) {
267+
this.stages.done({ status: 'Queued', username });
268+
this.stages.stop();
251269
if (flags['coverage-formatters']) {
252270
this.warn(messages.getMessage('asyncCoverageJunitWarning'));
253271
}
@@ -257,8 +275,6 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
257275
return this.mixinZipMeta(await asyncFormatter.getJson());
258276
}
259277

260-
new DeployProgress(deploy, this.jsonEnabled()).start();
261-
262278
const result = await deploy.pollStatus({ timeout: flags.wait });
263279
process.exitCode = determineExitCode(result);
264280
const formatter = new DeployResultFormatter(result, flags);
@@ -276,6 +292,8 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
276292
protected catch(error: Error | SfError): Promise<never> {
277293
if (error instanceof SourceConflictError && error.data) {
278294
if (!this.jsonEnabled()) {
295+
this.stages.update({ status: 'Failed' });
296+
this.stages.stop(error);
279297
writeConflictTable(error.data);
280298
// set the message and add plugin-specific actions
281299
return super.catch({

src/commands/project/deploy/validate.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { EnvironmentVariable, Lifecycle, Messages, OrgConfigProperties, SfError
1111
import { CodeCoverageWarnings, DeployVersionData, RequestStatus } from '@salesforce/source-deploy-retrieve';
1212
import { Duration, ensureArray } from '@salesforce/kit';
1313
import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core';
14+
import { DeployStages } from '../../../utils/deployStages.js';
1415
import { AsyncDeployResultFormatter } from '../../../formatters/asyncDeployResultFormatter.js';
1516
import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js';
16-
import { DeployProgress } from '../../../utils/progressBar.js';
1717
import { DeployResultJson, TestLevel } from '../../../utils/types.js';
1818
import { executeDeploy, resolveApi, determineExitCode, validateTests } from '../../../utils/deploy.js';
1919
import { DEPLOY_STATUS_CODES_DESCRIPTIONS } from '../../../utils/errorCodes.js';
@@ -195,15 +195,18 @@ export default class DeployMetadataValidate extends SfCommand<DeployResultJson>
195195
if (!deploy.id) {
196196
throw new SfError('The deploy id is not available.');
197197
}
198-
this.log(`Deploy ID: ${ansis.bold(deploy.id)}`);
199198

200199
if (flags.async) {
200+
this.log(`Deploy ID: ${ansis.bold(deploy.id)}`);
201201
const asyncFormatter = new AsyncDeployResultFormatter(deploy.id);
202202
if (!this.jsonEnabled()) asyncFormatter.display();
203203
return asyncFormatter.getJson();
204204
}
205205

206-
new DeployProgress(deploy, this.jsonEnabled()).start();
206+
new DeployStages({
207+
title: 'Validating Deployment',
208+
jsonEnabled: this.jsonEnabled(),
209+
}).start({ deploy, username });
207210

208211
const result = await deploy.pollStatus(500, flags.wait?.seconds);
209212
process.exitCode = determineExitCode(result);

0 commit comments

Comments
 (0)