Skip to content

Commit bb63b2e

Browse files
committed
fix: handle source conflicts
1 parent 0b94c81 commit bb63b2e

File tree

2 files changed

+49
-28
lines changed

2 files changed

+49
-28
lines changed

src/commands/project/deploy/start.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,14 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
185185

186186
public static errorCodes = toHelpSection('ERROR CODES', DEPLOY_STATUS_CODES_DESCRIPTIONS);
187187

188+
protected ms!: MultiStageOutput<{
189+
mdapiDeploy: MetadataApiDeployStatus;
190+
sourceMemberPolling: SourceMemberPollingEvent;
191+
status: string;
192+
apiData: DeployVersionData;
193+
targetOrg: string;
194+
}>;
195+
188196
public async run(): Promise<DeployResultJson> {
189197
const { flags } = await this.parse(DeployMetadata);
190198
const project = await getOptionalProject();
@@ -208,7 +216,7 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
208216
const username = flags['target-org'].getUsername();
209217
const title = flags['dry-run'] ? 'Deploying Metadata (dry-run)' : 'Deploying Metadata';
210218

211-
const ms = new MultiStageOutput<{
219+
this.ms = new MultiStageOutput<{
212220
mdapiDeploy: MetadataApiDeployStatus;
213221
sourceMemberPolling: SourceMemberPollingEvent;
214222
status: string;
@@ -296,7 +304,9 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
296304
});
297305

298306
const lifecycle = Lifecycle.getInstance();
299-
lifecycle.on('apiVersionDeploy', async (apiData: DeployVersionData) => Promise.resolve(ms.updateData({ apiData })));
307+
lifecycle.on('apiVersionDeploy', async (apiData: DeployVersionData) =>
308+
Promise.resolve(this.ms.updateData({ apiData }))
309+
);
300310

301311
const { deploy } = await executeDeploy(
302312
{
@@ -308,7 +318,7 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
308318
);
309319

310320
if (!deploy) {
311-
ms.stop();
321+
this.ms.stop();
312322
this.log('No changes to deploy');
313323
return { status: 'Nothing to deploy', files: [] };
314324
}
@@ -318,8 +328,8 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
318328
}
319329

320330
if (flags.async) {
321-
ms.goto('Done', { status: 'Queued', targetOrg: username });
322-
ms.stop();
331+
this.ms.goto('Done', { status: 'Queued', targetOrg: username });
332+
this.ms.stop();
323333
if (flags['coverage-formatters']) {
324334
this.warn(messages.getMessage('asyncCoverageJunitWarning'));
325335
}
@@ -328,11 +338,11 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
328338
return asyncFormatter.getJson();
329339
}
330340

331-
ms.goto('Preparing', { targetOrg: username });
341+
this.ms.goto('Preparing', { targetOrg: username });
332342

333343
// for sourceMember polling events
334344
lifecycle.on<SourceMemberPollingEvent>('sourceMemberPollingEvent', (event: SourceMemberPollingEvent) =>
335-
Promise.resolve(ms.goto('Updating Source Tracking', { sourceMemberPolling: event }))
345+
Promise.resolve(this.ms.goto('Updating Source Tracking', { sourceMemberPolling: event }))
336346
);
337347

338348
deploy.onUpdate((data) => {
@@ -341,34 +351,34 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
341351
data.numberTestsTotal > 0 &&
342352
data.numberComponentsDeployed > 0
343353
) {
344-
ms.goto('Running Tests', { mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status) });
354+
this.ms.goto('Running Tests', { mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status) });
345355
} else if (data.status === RequestStatus.Pending) {
346-
ms.goto('Waiting for the org to respond', {
356+
this.ms.goto('Waiting for the org to respond', {
347357
mdapiDeploy: data,
348358
status: mdTransferMessages.getMessage(data?.status),
349359
});
350360
} else {
351-
ms.goto('Deploying Metadata', { mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status) });
361+
this.ms.goto('Deploying Metadata', { mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status) });
352362
}
353363
});
354364

355365
deploy.onFinish((data) => {
356-
ms.goto('Done', { mdapiDeploy: data.response, status: mdTransferMessages.getMessage(data.response.status) });
357-
ms.stop();
366+
this.ms.goto('Done', { mdapiDeploy: data.response, status: mdTransferMessages.getMessage(data.response.status) });
367+
this.ms.stop();
358368
});
359369

360370
deploy.onCancel((data) => {
361-
ms.updateData({ mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status ?? 'Canceled') });
371+
this.ms.updateData({ mdapiDeploy: data, status: mdTransferMessages.getMessage(data?.status ?? 'Canceled') });
362372

363-
ms.stop(new Error('Deploy canceled'));
373+
this.ms.stop(new Error('Deploy canceled'));
364374
});
365375

366376
deploy.onError((error: Error) => {
367377
if (error.message.includes('client has timed out')) {
368-
ms.updateData({ status: 'Client Timeout' });
378+
this.ms.updateData({ status: 'Client Timeout' });
369379
}
370380

371-
ms.stop(error);
381+
this.ms.stop(error);
372382
throw error;
373383
});
374384

@@ -389,6 +399,8 @@ export default class DeployMetadata extends SfCommand<DeployResultJson> {
389399
protected catch(error: Error | SfError): Promise<never> {
390400
if (error instanceof SourceConflictError && error.data) {
391401
if (!this.jsonEnabled()) {
402+
this.ms.updateData({ status: 'Failed' });
403+
this.ms.stop(error);
392404
writeConflictTable(error.data);
393405
// set the message and add plugin-specific actions
394406
return super.catch({

src/commands/project/retrieve/start.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ export default class RetrieveMetadata extends SfCommand<RetrieveResultJson> {
147147
);
148148

149149
protected retrieveResult!: RetrieveResult;
150+
protected ms!: MultiStageOutput<{
151+
status: string;
152+
apiData: RetrieveVersionData;
153+
}>;
150154

151155
// eslint-disable-next-line complexity
152156
public async run(): Promise<RetrieveResultJson> {
@@ -162,7 +166,7 @@ export default class RetrieveMetadata extends SfCommand<RetrieveResultJson> {
162166
const zipFileName = flags['zip-file-name'] ?? DEFAULT_ZIP_FILE_NAME;
163167

164168
const stages = ['Preparing retrieve request', 'Sending request to org', 'Waiting for the org to respond', 'Done'];
165-
const ms = new MultiStageOutput<{
169+
this.ms = new MultiStageOutput<{
166170
status: string;
167171
apiData: RetrieveVersionData;
168172
}>({
@@ -192,13 +196,14 @@ export default class RetrieveMetadata extends SfCommand<RetrieveResultJson> {
192196
],
193197
});
194198

195-
ms.goto('Preparing retrieve request');
199+
this.ms.goto('Preparing retrieve request');
196200

197201
const { componentSetFromNonDeletes, fileResponsesFromDelete = [] } = await buildRetrieveAndDeleteTargets(
198202
flags,
199203
format
200204
);
201205
if (format === 'source' && (Boolean(flags.manifest) || Boolean(flags.metadata))) {
206+
// TODO: test this
202207
const access = new RegistryAccess(undefined, SfProject.getInstance()?.getPath());
203208
if (wantsToRetrieveCustomFields(componentSetFromNonDeletes, access)) {
204209
this.warn(messages.getMessage('wantsToRetrieveCustomFields'));
@@ -210,40 +215,40 @@ export default class RetrieveMetadata extends SfCommand<RetrieveResultJson> {
210215
}
211216
const retrieveOpts = await buildRetrieveOptions(flags, format, zipFileName, resolvedTargetDir);
212217

213-
ms.goto('Sending request to org');
218+
this.ms.goto('Sending request to org');
214219

215220
this.retrieveResult = new RetrieveResult({} as MetadataApiRetrieveStatus, componentSetFromNonDeletes);
216221

217222
if (componentSetFromNonDeletes.size !== 0 || retrieveOpts.packageOptions?.length) {
218223
Lifecycle.getInstance().on('apiVersionRetrieve', async (apiData: RetrieveVersionData) =>
219-
Promise.resolve(ms.updateData({ apiData }))
224+
Promise.resolve(this.ms.updateData({ apiData }))
220225
);
221226
const retrieve = await componentSetFromNonDeletes.retrieve(retrieveOpts);
222-
ms.goto('Waiting for the org to respond', { status: 'Pending' });
227+
this.ms.goto('Waiting for the org to respond', { status: 'Pending' });
223228

224229
retrieve.onUpdate((data) => {
225-
ms.goto('Waiting for the org to respond', { status: mdTransferMessages.getMessage(data.status) });
230+
this.ms.goto('Waiting for the org to respond', { status: mdTransferMessages.getMessage(data.status) });
226231
});
227232
retrieve.onFinish((data) => {
228-
ms.goto('Done', { status: mdTransferMessages.getMessage(data.response.status) });
233+
this.ms.goto('Done', { status: mdTransferMessages.getMessage(data.response.status) });
229234
});
230235
retrieve.onCancel((data) => {
231-
ms.updateData({ status: mdTransferMessages.getMessage(data?.status ?? 'Canceled') });
232-
ms.stop(new Error('Retrieve canceled'));
236+
this.ms.updateData({ status: mdTransferMessages.getMessage(data?.status ?? 'Canceled') });
237+
this.ms.stop(new Error('Retrieve canceled'));
233238
});
234239
retrieve.onError((error: Error) => {
235240
if (error.message.includes('client has timed out')) {
236-
ms.updateData({ status: 'Client Timeout' });
241+
this.ms.updateData({ status: 'Client Timeout' });
237242
}
238243

239-
ms.stop(error);
244+
this.ms.stop(error);
240245
throw error;
241246
});
242247

243248
this.retrieveResult = await retrieve.pollStatus(500, flags.wait.seconds);
244249
}
245250

246-
ms.stop();
251+
this.ms.stop();
247252

248253
// flags['output-dir'] will set resolvedTargetDir var, so this check is redundant, but allows for nice typings in the moveResultsForRetrieveTargetDir method
249254
if (flags['output-dir'] && resolvedTargetDir) {
@@ -294,13 +299,17 @@ export default class RetrieveMetadata extends SfCommand<RetrieveResultJson> {
294299

295300
protected catch(error: Error | SfError): Promise<never> {
296301
if (!this.jsonEnabled() && error instanceof SourceConflictError && error.data) {
302+
this.ms.updateData({ status: 'Failed' });
303+
this.ms.stop(error);
297304
writeConflictTable(error.data);
298305
// set the message and add plugin-specific actions
299306
return super.catch({
300307
...error,
301308
message: messages.getMessage('error.Conflicts'),
302309
actions: messages.getMessages('error.Conflicts.Actions'),
303310
});
311+
} else {
312+
this.ms.stop(error);
304313
}
305314

306315
return super.catch(error);

0 commit comments

Comments
 (0)