Skip to content

Commit a9bd124

Browse files
committed
feat: add --quiet and --no-progress for token-efficient deploy/retrieve output
1 parent f1389b2 commit a9bd124

21 files changed

Lines changed: 840 additions & 115 deletions

command-snapshot.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@
114114
"flags-dir",
115115
"job-id",
116116
"json",
117+
"no-progress",
118+
"quiet",
117119
"target-org",
118120
"use-most-recent",
119121
"verbose",
@@ -151,6 +153,8 @@
151153
"job-id",
152154
"json",
153155
"junit",
156+
"no-progress",
157+
"quiet",
154158
"results-dir",
155159
"use-most-recent",
156160
"verbose",
@@ -178,9 +182,11 @@
178182
"manifest",
179183
"metadata",
180184
"metadata-dir",
185+
"no-progress",
181186
"post-destructive-changes",
182187
"pre-destructive-changes",
183188
"purge-on-delete",
189+
"quiet",
184190
"results-dir",
185191
"single-package",
186192
"source-dir",
@@ -209,9 +215,11 @@
209215
"manifest",
210216
"metadata",
211217
"metadata-dir",
218+
"no-progress",
212219
"post-destructive-changes",
213220
"pre-destructive-changes",
214221
"purge-on-delete",
222+
"quiet",
215223
"results-dir",
216224
"single-package",
217225
"source-dir",
@@ -289,8 +297,10 @@
289297
"json",
290298
"manifest",
291299
"metadata",
300+
"no-progress",
292301
"output-dir",
293302
"package-name",
303+
"quiet",
294304
"single-package",
295305
"source-dir",
296306
"target-metadata-dir",

messages/deploy.metadata.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ If your org allows source tracking, then this command tracks the changes in your
1212

1313
To deploy multiple metadata components, either set multiple --metadata <name> flags or a single --metadata flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --source-dir.
1414

15+
## Output modes
16+
17+
| Switch | Streaming progress | Final report |
18+
| --------------- | ------------------ | ------------------ |
19+
| default | full | full success table |
20+
| `--concise` | full | failures only |
21+
| `--no-progress` | off | full success table |
22+
| `--quiet` | off | one-line summary |
23+
24+
`--quiet` builds on the same streaming-suppression primitive as `--no-progress`. For token-sensitive workflows, `--json --concise` is already a near-minimal machine-readable payload.
25+
1526
# examples
1627

1728
- Deploy local changes not in the org; uses your default org:
@@ -22,6 +33,14 @@ To deploy multiple metadata components, either set multiple --metadata <name> fl
2233

2334
<%= config.bin %> <%= command.id %> --source-dir force-app --target-org my-scratch --concise
2435

36+
- Deploy all source files in the "force-app" directory to an org with alias "my-scratch"; emit the trimmed JSON payload instead of the full success table:
37+
38+
<%= config.bin %> <%= command.id %> --source-dir force-app --target-org my-scratch --json --concise
39+
40+
- Deploy all source files in the "force-app" directory to an org with alias "my-scratch"; suppress live progress and collapse the final report to one summary line:
41+
42+
<%= config.bin %> <%= command.id %> --source-dir force-app --target-org my-scratch --quiet
43+
2544
- Deploy all the Apex classes and custom objects that are in the "force-app" directory. The list views, layouts, etc, that are associated with the custom objects are also deployed. Both examples are equivalent:
2645

2746
<%= config.bin %> <%= command.id %> --source-dir force-app/main/default/classes force-app/main/default/objects
@@ -170,7 +189,15 @@ Show verbose output of the deploy result.
170189

171190
# flags.concise.summary
172191

173-
Show concise output of the deploy result.
192+
Show concise output of the deploy result by omitting the full success table.
193+
194+
# flags.quiet.summary
195+
196+
Show a one-line deploy summary and suppress live progress to minimize stdout.
197+
198+
# flags.no-progress.summary
199+
200+
Hide the live deploy progress stream while keeping the full final report.
174201

175202
# flags.api-version.summary
176203

messages/deploy.metadata.quick.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,19 @@ If the command continues to run after the wait period, the CLI returns control o
5656

5757
# flags.verbose.summary
5858

59-
Show verbose output of the deploy result.
59+
Show verbose output of the quick deploy result.
6060

6161
# flags.concise.summary
6262

63-
Show concise output of the deploy result.
63+
Show concise output of the quick deploy result by omitting the full success table.
64+
65+
# flags.quiet.summary
66+
67+
Show a one-line quick deploy summary. Quick deploy has no live progress stream, so this only trims the final output.
68+
69+
# flags.no-progress.summary
70+
71+
Accepted for parity with other deploy commands; quick deploy has no live progress stream to hide.
6472

6573
# flags.async.summary
6674

messages/deploy.metadata.resume.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,15 @@ Show verbose output of the deploy operation result.
5555

5656
# flags.concise.summary
5757

58-
Show concise output of the deploy operation result.
58+
Show concise output of the deploy operation result by omitting the full success table.
59+
60+
# flags.quiet.summary
61+
62+
Show a one-line deploy resume summary and suppress live progress to minimize stdout.
63+
64+
# flags.no-progress.summary
65+
66+
Hide the live deploy resume progress stream while keeping the full final report.
5967

6068
# warning.DeployNotResumable
6169

messages/deploy.metadata.validate.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,15 @@ Show verbose output of the validation result.
9292

9393
# flags.concise.summary
9494

95-
Show concise output of the validation result.
95+
Show concise output of the validation result by omitting the full success table.
96+
97+
# flags.quiet.summary
98+
99+
Show a one-line validation summary and suppress live progress to minimize stdout.
100+
101+
# flags.no-progress.summary
102+
103+
Hide the live validation progress stream while keeping the full final report.
96104

97105
# flags.api-version.summary
98106

messages/retrieve.start.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,20 @@ If your org allows source tracking, then this command tracks the changes in your
1212

1313
To retrieve multiple metadata components, either use multiple --metadata <name> flags or use a single --metadata flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --source-dir.
1414

15+
## Output modes
16+
17+
`--quiet` suppresses the live retrieve progress stream and collapses the final output to a single summary line. `--no-progress` only hides the streaming block; it keeps the normal final output.
18+
1519
# examples
1620

1721
- Retrieve all remote changes from your default org:
1822

1923
<%= config.bin %> <%= command.id %>
2024

25+
- Retrieve all remote changes from your default org and keep the output to a single summary line:
26+
27+
<%= config.bin %> <%= command.id %> --quiet
28+
2129
- Retrieve the source files in the "force-app" directory from an org with alias "my-scratch":
2230

2331
<%= config.bin %> <%= command.id %> --source-dir force-app --target-org my-scratch
@@ -177,6 +185,14 @@ Running the command multiple times with the same target adds new files and overw
177185

178186
Directory root for the retrieved source files.
179187

188+
# flags.quiet.summary
189+
190+
Show a one-line retrieve summary and suppress live progress to minimize stdout.
191+
192+
# flags.no-progress.summary
193+
194+
Hide the live retrieve progress stream while keeping the final result.
195+
180196
# retrieveTargetDirOverlapsPackage
181197

182198
The retrieve target directory [%s] overlaps one of your package directories. Specify a different retrieve target directory and try again.

src/commands/project/deploy/quick.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import ansis from 'ansis';
18-
import { Messages, Org } from '@salesforce/core';
18+
import { EnvironmentVariable, Messages, Org } from '@salesforce/core';
1919
import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core';
2020
import { MetadataApiDeploy, RequestStatus } from '@salesforce/source-deploy-retrieve';
2121
import { Duration } from '@salesforce/kit';
@@ -44,7 +44,7 @@ export default class DeployMetadataQuick extends SfCommand<DeployResultJson> {
4444
}),
4545
concise: Flags.boolean({
4646
summary: messages.getMessage('flags.concise.summary'),
47-
exclusive: ['verbose'],
47+
exclusive: ['verbose', 'quiet'],
4848
}),
4949
'job-id': Flags.salesforceId({
5050
char: 'i',
@@ -63,7 +63,14 @@ export default class DeployMetadataQuick extends SfCommand<DeployResultJson> {
6363
}),
6464
verbose: Flags.boolean({
6565
summary: messages.getMessage('flags.verbose.summary'),
66-
exclusive: ['concise'],
66+
exclusive: ['concise', 'quiet'],
67+
}),
68+
quiet: Flags.boolean({
69+
summary: messages.getMessage('flags.quiet.summary'),
70+
exclusive: ['verbose', 'concise'],
71+
}),
72+
'no-progress': Flags.boolean({
73+
summary: messages.getMessage('flags.no-progress.summary'),
6774
}),
6875
wait: Flags.duration({
6976
char: 'w',
@@ -85,6 +92,13 @@ export default class DeployMetadataQuick extends SfCommand<DeployResultJson> {
8592

8693
public static errorCodes = toHelpSection('ERROR CODES', DEPLOY_STATUS_CODES_DESCRIPTIONS);
8794

95+
public static envVariablesSection = toHelpSection(
96+
'ENVIRONMENT VARIABLES',
97+
EnvironmentVariable.SF_TARGET_ORG,
98+
EnvironmentVariable.SF_USE_PROGRESS_BAR,
99+
'SF_DEPLOY_PROGRESS'
100+
);
101+
88102
private deployUrl?: string;
89103

90104
public async run(): Promise<DeployResultJson> {
@@ -101,13 +115,21 @@ export default class DeployMetadataQuick extends SfCommand<DeployResultJson> {
101115
id: jobId,
102116
rest: api === API['REST'],
103117
});
104-
this.log(`Deploy ID: ${ansis.bold(deployId)}`);
105118
this.deployUrl = buildDeployUrl(flags['target-org'], deployId);
106-
this.log(`Deploy URL: ${ansis.bold(this.deployUrl)}`);
119+
if (!flags.quiet) {
120+
this.log(`Deploy ID: ${ansis.bold(deployId)}`);
121+
this.log(`Deploy URL: ${ansis.bold(this.deployUrl)}`);
122+
}
107123

108124
if (flags.async) {
109125
const asyncFormatter = new AsyncDeployResultFormatter(deployId);
110-
if (!this.jsonEnabled()) asyncFormatter.display();
126+
if (!this.jsonEnabled()) {
127+
if (flags.quiet) {
128+
this.log(`Deploy ID: ${ansis.bold(deployId)}`);
129+
} else {
130+
asyncFormatter.display();
131+
}
132+
}
111133
return this.mixinUrlMeta(await asyncFormatter.getJson());
112134
}
113135

@@ -122,17 +144,20 @@ export default class DeployMetadataQuick extends SfCommand<DeployResultJson> {
122144
frequency: Duration.seconds(1),
123145
timeout: flags.wait,
124146
});
125-
const formatter = new DeployResultFormatter(result, flags);
147+
const formatter = new DeployResultFormatter(result, { ...flags, 'target-org': targetOrg });
126148

127149
if (!this.jsonEnabled()) formatter.display();
128150

129151
await DeployCache.update(deployId, { status: result.response.status });
130152

131153
process.exitCode = determineExitCode(result);
132154
if (result.response.status === RequestStatus.Succeeded) {
133-
this.log();
134-
this.logSuccess(messages.getMessage('info.QuickDeploySuccess', [deployId]));
155+
if (!flags.quiet) {
156+
this.log();
157+
this.logSuccess(messages.getMessage('info.QuickDeploySuccess', [deployId]));
158+
}
135159
} else {
160+
// failure detail must survive --quiet; quiet collapses successful output only
136161
this.log(messages.getMessage('error.QuickDeployFailure', [deployId, result.response.status]));
137162
}
138163

src/commands/project/deploy/resume.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { EnvironmentVariable, Messages, Org, SfError } from '@salesforce/core';
1818
import { SfCommand, toHelpSection, Flags } from '@salesforce/sf-plugins-core';
1919
import { DeployResult, MetadataApiDeploy } from '@salesforce/source-deploy-retrieve';
2020
import { Duration } from '@salesforce/kit';
21-
import { DeployStages } from '../../../utils/deployStages.js';
21+
import { DeployStages, shouldShowDeployProgress } from '../../../utils/deployStages.js';
2222
import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js';
2323
import { API, DeployResultJson } from '../../../utils/types.js';
2424
import {
@@ -37,6 +37,13 @@ const messages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'de
3737

3838
const testFlags = 'Test';
3939

40+
export const resolveResumeVerbose = (
41+
flags: { quiet?: boolean; verbose?: boolean; concise?: boolean },
42+
deployOpts: { verbose?: boolean }
43+
// a current --quiet/--concise request must override cached verbose; only fall back to the
44+
// cache when no explicit verbosity flag is set on this invocation.
45+
): boolean => (flags.quiet ?? flags.concise ? false : flags.verbose ?? deployOpts.verbose ?? false);
46+
4047
export default class DeployMetadataResume extends SfCommand<DeployResultJson> {
4148
public static readonly description = messages.getMessage('description');
4249
public static readonly summary = messages.getMessage('summary');
@@ -47,7 +54,7 @@ export default class DeployMetadataResume extends SfCommand<DeployResultJson> {
4754
public static readonly flags = {
4855
concise: Flags.boolean({
4956
summary: messages.getMessage('flags.concise.summary'),
50-
exclusive: ['verbose'],
57+
exclusive: ['verbose', 'quiet'],
5158
}),
5259
'job-id': Flags.salesforceId({
5360
char: 'i',
@@ -65,7 +72,14 @@ export default class DeployMetadataResume extends SfCommand<DeployResultJson> {
6572
}),
6673
verbose: Flags.boolean({
6774
summary: messages.getMessage('flags.verbose.summary'),
68-
exclusive: ['concise'],
75+
exclusive: ['concise', 'quiet'],
76+
}),
77+
quiet: Flags.boolean({
78+
summary: messages.getMessage('flags.quiet.summary'),
79+
exclusive: ['verbose', 'concise'],
80+
}),
81+
'no-progress': Flags.boolean({
82+
summary: messages.getMessage('flags.no-progress.summary'),
6983
}),
7084
// we want this to allow undefined so that we can use the default value from the cache
7185
// eslint-disable-next-line sf-plugin/flag-min-max-default
@@ -89,7 +103,11 @@ export default class DeployMetadataResume extends SfCommand<DeployResultJson> {
89103
}),
90104
};
91105

92-
public static envVariablesSection = toHelpSection('ENVIRONMENT VARIABLES', EnvironmentVariable.SF_USE_PROGRESS_BAR);
106+
public static envVariablesSection = toHelpSection(
107+
'ENVIRONMENT VARIABLES',
108+
EnvironmentVariable.SF_USE_PROGRESS_BAR,
109+
'SF_DEPLOY_PROGRESS'
110+
);
93111

94112
public static errorCodes = toHelpSection('ERROR CODES', DEPLOY_STATUS_CODES_DESCRIPTIONS);
95113

@@ -123,6 +141,12 @@ export default class DeployMetadataResume extends SfCommand<DeployResultJson> {
123141
result = new DeployResult(deployStatus, componentSet);
124142
} else {
125143
const wait = flags.wait ?? Duration.minutes(deployOpts.wait ?? 33);
144+
const verbose = resolveResumeVerbose(flags, deployOpts);
145+
const showProgress = shouldShowDeployProgress({
146+
jsonEnabled: this.jsonEnabled(),
147+
quiet: flags.quiet,
148+
noProgress: flags['no-progress'],
149+
});
126150
const { deploy } = await executeDeploy(
127151
// there will always be conflicts on a resume if anything deployed--the changes on the server are not synced to local
128152
{
@@ -143,14 +167,15 @@ export default class DeployMetadataResume extends SfCommand<DeployResultJson> {
143167
new DeployStages({
144168
title: 'Resuming Deploy',
145169
jsonEnabled: this.jsonEnabled(),
170+
showProgress,
146171
}).start(
147172
{
148173
deploy,
149174
username: deployOpts['target-org'],
150175
},
151176
{
152177
deployUrl: this.deployUrl,
153-
verbose: flags.verbose ?? deployOpts.verbose,
178+
verbose,
154179
}
155180
);
156181

@@ -168,8 +193,9 @@ export default class DeployMetadataResume extends SfCommand<DeployResultJson> {
168193

169194
const formatter = new DeployResultFormatter(result, {
170195
...flags,
171-
verbose: deployOpts.verbose,
172-
concise: deployOpts.concise,
196+
verbose: resolveResumeVerbose(flags, deployOpts),
197+
concise: flags.concise ?? deployOpts.concise,
198+
'target-org': org,
173199
});
174200

175201
if (!this.jsonEnabled()) formatter.display();

0 commit comments

Comments
 (0)