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 { Messages , Org } from '@salesforce/core' ;
9- import { Duration } from '@salesforce/kit' ;
8+ import { Messages , Org , SfProject } from '@salesforce/core' ;
109import { SfCommand , Flags } from '@salesforce/sf-plugins-core' ;
11- import { DeployResult , MetadataApiDeployStatus } from '@salesforce/source-deploy-retrieve' ;
10+ import { ComponentSet , DeployResult , MetadataApiDeploy } from '@salesforce/source-deploy-retrieve' ;
1211import { buildComponentSet } from '../../../utils/deploy' ;
12+ import { DeployProgress } from '../../../utils/progressBar' ;
1313import { DeployCache } from '../../../utils/deployCache' ;
1414import { DeployReportResultFormatter } from '../../../formatters/deployReportResultFormatter' ;
1515import { DeployResultJson } from '../../../utils/types' ;
1616import { coverageFormattersFlag } from '../../../utils/flags' ;
1717
1818Messages . importMessagesDirectory ( __dirname ) ;
1919const messages = Messages . loadMessages ( '@salesforce/plugin-deploy-retrieve' , 'deploy.metadata.report' ) ;
20+ const deployMessages = Messages . loadMessages ( '@salesforce/plugin-deploy-retrieve' , 'deploy.metadata' ) ;
2021const testFlags = 'Test' ;
2122
2223export default class DeployMetadataReport extends SfCommand < DeployResultJson > {
@@ -27,6 +28,11 @@ export default class DeployMetadataReport extends SfCommand<DeployResultJson> {
2728 public static readonly deprecateAliases = true ;
2829
2930 public static readonly flags = {
31+ 'target-org' : Flags . optionalOrg ( {
32+ char : 'o' ,
33+ description : deployMessages . getMessage ( 'flags.target-org.description' ) ,
34+ summary : deployMessages . getMessage ( 'flags.target-org.summary' ) ,
35+ } ) ,
3036 'job-id' : Flags . salesforceId ( {
3137 char : 'i' ,
3238 startsWith : '0Af' ,
@@ -51,23 +57,84 @@ export default class DeployMetadataReport extends SfCommand<DeployResultJson> {
5157 summary : messages . getMessage ( 'flags.results-dir.summary' ) ,
5258 helpGroup : testFlags ,
5359 } ) ,
60+ // we want to allow undefined for a simple check deploy status
61+ // eslint-disable-next-line sf-plugin/flag-min-max-default
62+ wait : Flags . duration ( {
63+ char : 'w' ,
64+ summary : deployMessages . getMessage ( 'flags.wait.summary' ) ,
65+ description : deployMessages . getMessage ( 'flags.wait.description' ) ,
66+ unit : 'minutes' ,
67+ helpValue : '<minutes>' ,
68+ min : 1 ,
69+ } ) ,
5470 } ;
5571
5672 public async run ( ) : Promise < DeployResultJson > {
5773 const [ { flags } , cache ] = await Promise . all ( [ this . parse ( DeployMetadataReport ) , DeployCache . create ( ) ] ) ;
58- const jobId = cache . resolveLatest ( flags [ 'use-most-recent' ] , flags [ 'job-id' ] ) ;
74+ const jobId = cache . resolveLatest ( flags [ 'use-most-recent' ] , flags [ 'job-id' ] , false ) ;
75+
76+ const deployOpts = cache . get ( jobId ) ?? { } ;
77+ const wait = flags [ 'wait' ] ;
78+ const org = flags [ 'target-org' ] ?? ( await Org . create ( { aliasOrUsername : deployOpts [ 'target-org' ] } ) ) ;
5979
60- const deployOpts = cache . get ( jobId ) ;
61- const org = await Org . create ( { aliasOrUsername : deployOpts [ 'target-org' ] } ) ;
62- const [ deployStatus , componentSet ] = await Promise . all ( [
63- // we'll use whatever the org supports since we can't specify the org
80+ // if we're using mdapi we won't have a component set
81+ let componentSet = new ComponentSet ( ) ;
82+ if ( ! deployOpts . isMdapi ) {
83+ if ( ! cache . get ( jobId ) ) {
84+ // If the cache file isn't there, use the project package directories for the CompSet
85+ try {
86+ this . project = await SfProject . resolve ( ) ;
87+ const sourcepath = this . project . getUniquePackageDirectories ( ) . map ( ( pDir ) => pDir . fullPath ) ;
88+ componentSet = await buildComponentSet ( { 'source-dir' : sourcepath , wait } ) ;
89+ } catch ( err ) {
90+ // ignore the error. this was just to get improved command output.
91+ }
92+ } else {
93+ componentSet = await buildComponentSet ( { ...deployOpts , wait } ) ;
94+ }
95+ }
96+ const mdapiDeploy = new MetadataApiDeploy ( {
97+ // setting an API version here won't matter since we're just checking deploy status
6498 // eslint-disable-next-line sf-plugin/get-connection-with-version
65- org . getConnection ( ) . metadata . checkDeployStatus ( jobId , true ) ,
66- // if we're using mdapi, we won't have a component set
67- deployOpts . isMdapi ? undefined : buildComponentSet ( { ...deployOpts , wait : Duration . minutes ( deployOpts . wait ) } ) ,
68- ] ) ;
99+ usernameOrConnection : org . getConnection ( ) ,
100+ id : jobId ,
101+ components : componentSet ,
102+ apiOptions : {
103+ rest : deployOpts . api === 'REST' ,
104+ } ,
105+ } ) ;
106+
107+ const getDeployResult = async ( ) : Promise < DeployResult > => {
108+ try {
109+ const deployStatus = await mdapiDeploy . checkStatus ( ) ;
110+ return new DeployResult ( deployStatus , componentSet ) ;
111+ } catch ( error ) {
112+ if ( error instanceof Error && error . name === 'sf:INVALID_CROSS_REFERENCE_KEY' ) {
113+ throw deployMessages . createError ( 'error.InvalidDeployId' , [ jobId , org . getUsername ( ) ] ) ;
114+ }
115+ throw error ;
116+ }
117+ } ;
69118
70- const result = new DeployResult ( deployStatus as MetadataApiDeployStatus , componentSet ) ;
119+ let result : DeployResult ;
120+ if ( wait ) {
121+ // poll for deploy results
122+ try {
123+ new DeployProgress ( mdapiDeploy , this . jsonEnabled ( ) ) . start ( ) ;
124+ result = await mdapiDeploy . pollStatus ( 500 , wait . seconds ) ;
125+ } catch ( error ) {
126+ if ( error instanceof Error && error . message . includes ( 'The client has timed out' ) ) {
127+ this . debug ( '[project deploy report] polling timed out. Requesting status...' ) ;
128+ } else {
129+ throw error ;
130+ }
131+ } finally {
132+ result = await getDeployResult ( ) ;
133+ }
134+ } else {
135+ // check the deploy status
136+ result = await getDeployResult ( ) ;
137+ }
71138
72139 const formatter = new DeployReportResultFormatter ( result , {
73140 ...deployOpts ,
0 commit comments