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 ' ;
8+ import { MultiStageOutput } from '@oclif/multi-stage-output ' ;
99import { EnvironmentVariable , Lifecycle , Messages , OrgConfigProperties , SfError } from '@salesforce/core' ;
10- import { DeployVersionData } from '@salesforce/source-deploy-retrieve' ;
10+ import { DeployVersionData , MetadataApiDeployStatus } from '@salesforce/source-deploy-retrieve' ;
1111import { Duration } from '@salesforce/kit' ;
1212import { SfCommand , toHelpSection , Flags } from '@salesforce/sf-plugins-core' ;
13- import { SourceConflictError } from '@salesforce/source-tracking' ;
13+ import { SourceConflictError , SourceMemberPollingEvent } from '@salesforce/source-tracking' ;
14+ import { DeployStages } from '../../../utils/deployStages.js' ;
1415import { AsyncDeployResultFormatter } from '../../../formatters/asyncDeployResultFormatter.js' ;
1516import { DeployResultFormatter } from '../../../formatters/deployResultFormatter.js' ;
16- import { DeployProgress } from '../../../utils/progressBar.js' ;
1717import { DeployResultJson , TestLevel } from '../../../utils/types.js' ;
1818import { executeDeploy , resolveApi , validateTests , determineExitCode } from '../../../utils/deploy.js' ;
1919import { DeployCache } from '../../../utils/deployCache.js' ;
@@ -176,6 +176,16 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
176176
177177 public static errorCodes = toHelpSection ( 'ERROR CODES' , DEPLOY_STATUS_CODES_DESCRIPTIONS ) ;
178178
179+ protected ms ! : MultiStageOutput < {
180+ mdapiDeploy : MetadataApiDeployStatus ;
181+ sourceMemberPolling : SourceMemberPollingEvent ;
182+ status : string ;
183+ apiData : DeployVersionData ;
184+ targetOrg : string ;
185+ } > ;
186+
187+ protected stages ! : DeployStages ;
188+
179189 public async run ( ) : Promise < DeployResultJson > {
180190 const { flags } = await this . parse ( DeployMetadata ) ;
181191 const project = await getOptionalProject ( ) ;
@@ -197,23 +207,30 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
197207
198208 const api = await resolveApi ( this . configAggregator ) ;
199209 const username = flags [ 'target-org' ] . getUsername ( ) ;
200- const action = flags [ 'dry-run' ] ? 'Deploying (dry-run)' : 'Deploying' ;
210+ const title = flags [ 'dry-run' ] ? 'Deploying Metadata (dry-run)' : 'Deploying Metadata ' ;
201211
202- // eslint-disable-next-line @typescript-eslint/require-await
203- Lifecycle . getInstance ( ) . on ( 'apiVersionDeploy' , async ( apiData : DeployVersionData ) => {
204- this . log (
205- messages . getMessage ( 'apiVersionMsgDetailed' , [
206- action ,
207- // technically manifestVersion can be undefined, but only on raw mdapi deployments.
208- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
209- flags [ 'metadata-dir' ] ? '<version specified in manifest>' : `v${ apiData . manifestVersion } ` ,
210- username ,
211- apiData . apiVersion ,
212- apiData . webService ,
213- ] )
214- ) ;
212+ this . stages = new DeployStages ( {
213+ title,
214+ jsonEnabled : this . jsonEnabled ( ) ,
215215 } ) ;
216216
217+ const lifecycle = Lifecycle . getInstance ( ) ;
218+ lifecycle . on ( 'apiVersionDeploy' , async ( apiData : DeployVersionData ) =>
219+ Promise . resolve (
220+ this . stages . update ( {
221+ message : messages . getMessage ( 'apiVersionMsgDetailed' , [
222+ flags [ 'dry-run' ] ? 'Deploying (dry-run)' : 'Deploying' ,
223+ // technically manifestVersion can be undefined, but only on raw mdapi deployments.
224+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
225+ flags [ 'metadata-dir' ] ? '<version specified in manifest>' : `v${ apiData . manifestVersion } ` ,
226+ username ,
227+ apiData . apiVersion ,
228+ apiData . webService ,
229+ ] ) ,
230+ } )
231+ )
232+ ) ;
233+
217234 const { deploy } = await executeDeploy (
218235 {
219236 ...flags ,
@@ -224,16 +241,20 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
224241 ) ;
225242
226243 if ( ! deploy ) {
244+ this . stages . stop ( ) ;
227245 this . log ( 'No changes to deploy' ) ;
228246 return { status : 'Nothing to deploy' , files : [ ] } ;
229247 }
230248
231249 if ( ! deploy . id ) {
232250 throw new SfError ( 'The deploy id is not available.' ) ;
233251 }
234- this . log ( `Deploy ID: ${ ansis . bold ( deploy . id ) } ` ) ;
252+
253+ this . stages . start ( { username, deploy } ) ;
235254
236255 if ( flags . async ) {
256+ this . stages . done ( { status : 'Queued' , username } ) ;
257+ this . stages . stop ( ) ;
237258 if ( flags [ 'coverage-formatters' ] ) {
238259 this . warn ( messages . getMessage ( 'asyncCoverageJunitWarning' ) ) ;
239260 }
@@ -242,8 +263,6 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
242263 return asyncFormatter . getJson ( ) ;
243264 }
244265
245- new DeployProgress ( deploy , this . jsonEnabled ( ) ) . start ( ) ;
246-
247266 const result = await deploy . pollStatus ( { timeout : flags . wait } ) ;
248267 process . exitCode = determineExitCode ( result ) ;
249268 const formatter = new DeployResultFormatter ( result , flags ) ;
@@ -261,6 +280,8 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
261280 protected catch ( error : Error | SfError ) : Promise < never > {
262281 if ( error instanceof SourceConflictError && error . data ) {
263282 if ( ! this . jsonEnabled ( ) ) {
283+ this . stages . update ( { status : 'Failed' } ) ;
284+ this . stages . stop ( error ) ;
264285 writeConflictTable ( error . data ) ;
265286 // set the message and add plugin-specific actions
266287 return super . catch ( {
0 commit comments