@@ -9,15 +9,19 @@ import * as os from 'os';
9
9
import * as path from 'path' ;
10
10
import { flags , FlagsConfig } from '@salesforce/command' ;
11
11
import { Lifecycle , Messages } from '@salesforce/core' ;
12
- import { DeployResult } from '@salesforce/source-deploy-retrieve' ;
12
+ import { DeployResult , MetadataApiDeploy } from '@salesforce/source-deploy-retrieve' ;
13
13
import { Duration } from '@salesforce/kit' ;
14
14
import { asString , asArray , getBoolean , JsonCollection } from '@salesforce/ts-types' ;
15
15
import * as chalk from 'chalk' ;
16
+ import cli from 'cli-ux' ;
17
+ import { env } from '@salesforce/kit' ;
16
18
import { SourceCommand } from '../../../sourceCommand' ;
17
19
18
20
Messages . importMessagesDirectory ( __dirname ) ;
19
21
const messages = Messages . loadMessages ( '@salesforce/plugin-source' , 'deploy' ) ;
20
22
23
+ type TestLevel = 'NoTestRun' | 'RunSpecifiedTests' | 'RunLocalTests' | 'RunAllTestsInOrg' ;
24
+
21
25
export class Deploy extends SourceCommand {
22
26
public static readonly description = messages . getMessage ( 'description' ) ;
23
27
public static readonly examples = messages . getMessage ( 'examples' ) . split ( os . EOL ) ;
@@ -111,19 +115,24 @@ export class Deploy extends SourceCommand {
111
115
112
116
await hookEmitter . emit ( 'predeploy' , { packageXmlPath : cs . getPackageXml ( ) } ) ;
113
117
114
- const results = await cs
115
- . deploy ( {
116
- usernameOrConnection : this . org . getUsername ( ) ,
117
- apiOptions : {
118
- ignoreWarnings : getBoolean ( this . flags , 'ignorewarnings' , false ) ,
119
- rollbackOnError : ! getBoolean ( this . flags , 'ignoreerrors' , false ) ,
120
- checkOnly : getBoolean ( this . flags , 'checkonly' , false ) ,
121
- runTests : asArray < string > ( this . flags . runtests ) ,
122
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
123
- testLevel : this . flags . testlevel ,
124
- } ,
125
- } )
126
- . start ( ) ;
118
+ const deploy = cs . deploy ( {
119
+ usernameOrConnection : this . org . getUsername ( ) ,
120
+ apiOptions : {
121
+ ignoreWarnings : getBoolean ( this . flags , 'ignorewarnings' , false ) ,
122
+ rollbackOnError : ! getBoolean ( this . flags , 'ignoreerrors' , false ) ,
123
+ checkOnly : getBoolean ( this . flags , 'checkonly' , false ) ,
124
+ runTests : asArray < string > ( this . flags . runtests ) ,
125
+ testLevel : this . flags . testlevel as TestLevel ,
126
+ } ,
127
+ } ) ;
128
+
129
+ // if SFDX_USE_PROGRESS_BAR is true and no --json flag use progress bar, if not, skip
130
+ if ( env . getBoolean ( 'SFDX_USE_PROGRESS_BAR' , true ) && ! this . flags . json ) {
131
+ this . progress ( deploy ) ;
132
+ }
133
+
134
+ const results = await deploy . start ( ) ;
135
+
127
136
await hookEmitter . emit ( 'postdeploy' , results ) ;
128
137
129
138
// skip a lot of steps that would do nothing
@@ -134,6 +143,51 @@ export class Deploy extends SourceCommand {
134
143
return results ;
135
144
}
136
145
146
+ private progress ( deploy : MetadataApiDeploy ) : void {
147
+ // cli.progress doesn't have typings
148
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
149
+ const progressBar = cli . progress ( {
150
+ format : 'SOURCE PROGRESS | {bar} | {value}/{total} Components' ,
151
+ barCompleteChar : '\u2588' ,
152
+ barIncompleteChar : '\u2591' ,
153
+ linewrap : true ,
154
+ } ) ;
155
+ let printOnce = true ;
156
+ deploy . onUpdate ( ( data ) => {
157
+ // the numCompTot. isn't computed right away, wait to start until we know how many we have
158
+ if ( data . numberComponentsTotal && printOnce ) {
159
+ this . ux . log ( `Job ID | ${ data . id } ` ) ;
160
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
161
+ progressBar . start ( data . numberComponentsTotal + data . numberTestsTotal ) ;
162
+ printOnce = false ;
163
+ }
164
+
165
+ // the numTestsTot. isn't computed until validated as tests by the server, update the PB once we know
166
+ if ( data . numberTestsTotal ) {
167
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
168
+ progressBar . setTotal ( data . numberComponentsTotal + data . numberTestsTotal ) ;
169
+ }
170
+
171
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call
172
+ progressBar . update ( data . numberComponentsDeployed + data . numberTestsCompleted ) ;
173
+ } ) ;
174
+
175
+ deploy . onFinish ( ( ) => {
176
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
177
+ progressBar . stop ( ) ;
178
+ } ) ;
179
+
180
+ deploy . onCancel ( ( ) => {
181
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
182
+ progressBar . stop ( ) ;
183
+ } ) ;
184
+
185
+ deploy . onError ( ( ) => {
186
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
187
+ progressBar . stop ( ) ;
188
+ } ) ;
189
+ }
190
+
137
191
private printComponentFailures ( result : DeployResult ) : void {
138
192
if ( result . response . status === 'Failed' && result . components ) {
139
193
// sort by filename then fullname
0 commit comments