Skip to content

Commit 9dcc3e7

Browse files
feat: add mdapi:deploy:cancel command, refactor base classes to support MDAPI and SOURCE stash keys (#301)
* fix: add mdapi:deploy:cancel command, refactor base classes to support MDAPI and SOURCE stash keys * chore: remove helpers from kit * chore: address QA issues
1 parent 25beb65 commit 9dcc3e7

File tree

15 files changed

+382
-60
lines changed

15 files changed

+382
-60
lines changed

command-snapshot.json

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
11
[
2+
{
3+
"command": "force:mdapi:deploy:cancel",
4+
"plugin": "@salesforce/plugin-source",
5+
"flags": ["apiversion", "jobid", "json", "loglevel", "targetusername", "wait"]
6+
},
7+
{
8+
"command": "force:mdapi:describemetadata",
9+
"plugin": "@salesforce/plugin-source",
10+
"flags": ["apiversion", "filterknown", "json", "loglevel", "resultfile", "targetusername"]
11+
},
12+
{
13+
"command": "force:mdapi:listmetadata",
14+
"plugin": "@salesforce/plugin-source",
15+
"flags": ["apiversion", "folder", "json", "loglevel", "metadatatype", "resultfile", "targetusername"]
16+
},
217
{
318
"command": "force:source:beta:pull",
419
"plugin": "@salesforce/plugin-source",
@@ -105,15 +120,5 @@
105120
"verbose",
106121
"wait"
107122
]
108-
},
109-
{
110-
"command": "force:mdapi:listmetadata",
111-
"plugin": "@salesforce/plugin-source",
112-
"flags": ["apiversion", "json", "loglevel", "resultfile", "targetusername", "metadatatype", "folder"]
113-
},
114-
{
115-
"command": "force:mdapi:describemetadata",
116-
"plugin": "@salesforce/plugin-source",
117-
"flags": ["apiversion", "json", "loglevel", "resultfile", "targetusername", "filterknown"]
118123
}
119124
]

messages/cancel.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
},
1111
"flagsLong": {
1212
"wait": "Number of minutes to wait for the command to complete and display results to the terminal window. If the command continues to run after the wait period, the CLI returns control of the terminal window to you. "
13-
}
13+
},
14+
"CancelFailed": "The cancel command failed due to: %s"
1415
}

messages/deploy.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,6 @@
8181
"deployFailed": "Deploy failed.",
8282
"asyncDeployQueued": "Deploy has been queued.",
8383
"asyncDeployCancel": "Run sfdx force:source:deploy:cancel -i %s to cancel the deploy.",
84-
"asyncDeployReport": "Run sfdx force:source:deploy:report -i %s to get the latest status."
84+
"asyncDeployReport": "Run sfdx force:source:deploy:report -i %s to get the latest status.",
85+
"invalidDeployId": "The provided ID is invalid, deploy IDs must start with '0Af'"
8586
}

messages/md.cancel.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"description": "cancel a metadata deployment \n Use this command to cancel a specified asynchronous metadata deployment. You can also specify a wait time (in minutes) to check for updates to the canceled deploy status.",
3+
"longDescription": "Cancels an asynchronous metadata deployment.",
4+
"flags": {
5+
"wait": "wait time for command to finish in minutes",
6+
"waitLong": "Number of minutes to wait for the command to complete and display results to the terminal window. If the command continues to run after the wait period, the CLI returns control of the terminal window to you. The default is 33 minutes.",
7+
"jobid": "job ID of the deployment you want to cancel; defaults to your most recent CLI deployment if not specified"
8+
},
9+
10+
"examples": [
11+
"Deploy a directory of files to the org",
12+
" $ sfdx force:mdapi:deploy -d <directory>",
13+
"Now cancel this deployment and wait two minutes",
14+
" $ sfdx force:mdapi:deploy:cancel -w 2",
15+
"If you have multiple deployments in progress and want to cancel a specific one, specify the job ID",
16+
" $ sfdx force:mdapi:deploy:cancel -i <jobid>",
17+
"Check the status of the cancel job",
18+
" $ sfdx force:mdapi:deploy:report"
19+
]
20+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2020, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
8+
import * as os from 'os';
9+
import { flags, FlagsConfig } from '@salesforce/command';
10+
import { Messages, SfdxError } from '@salesforce/core';
11+
import { Duration } from '@salesforce/kit';
12+
import { RequestStatus } from '@salesforce/source-deploy-retrieve';
13+
import { DeployCommand } from '../../../../deployCommand';
14+
import {
15+
DeployCancelCommandResult,
16+
DeployCancelResultFormatter,
17+
} from '../../../../formatters/deployCancelResultFormatter';
18+
19+
Messages.importMessagesDirectory(__dirname);
20+
const messages = Messages.loadMessages('@salesforce/plugin-source', 'md.cancel');
21+
22+
export class Cancel extends DeployCommand {
23+
public static readonly description = messages.getMessage('description');
24+
public static readonly examples = messages.getMessage('examples').split(os.EOL);
25+
public static readonly requiresUsername = true;
26+
public static readonly flagsConfig: FlagsConfig = {
27+
wait: flags.minutes({
28+
char: 'w',
29+
default: Duration.minutes(DeployCommand.DEFAULT_WAIT_MINUTES),
30+
min: Duration.minutes(1),
31+
description: messages.getMessage('flags.wait'),
32+
longDescription: messages.getMessage('flags.waitLong'),
33+
}),
34+
jobid: flags.id({
35+
char: 'i',
36+
description: messages.getMessage('flags.jobid'),
37+
validate: (val) => {
38+
if (val.startsWith('0Af')) {
39+
return true;
40+
} else {
41+
throw SfdxError.create('@salesforce/plugin-source', 'deploy', 'invalidDeployId');
42+
}
43+
},
44+
}),
45+
};
46+
// The most important difference between this and source:deploy:cancel
47+
public isSourceStash = false;
48+
49+
public async run(): Promise<DeployCancelCommandResult> {
50+
await this.cancel();
51+
this.resolveSuccess();
52+
return this.formatResult();
53+
}
54+
55+
protected async cancel(): Promise<void> {
56+
const deployId = this.resolveDeployId(this.getFlag<string>('jobid'));
57+
try {
58+
const deploy = this.createDeploy(deployId);
59+
await deploy.cancel();
60+
61+
this.deployResult = await this.poll(deployId);
62+
} catch (e) {
63+
if (e instanceof Error) {
64+
throw SfdxError.create('@salesforce/plugin-source', 'cancel', 'CancelFailed', [e.message]);
65+
} else {
66+
throw SfdxError.wrap(e);
67+
}
68+
}
69+
}
70+
71+
protected resolveSuccess(): void {
72+
const status = this.deployResult.response.status;
73+
if (status !== RequestStatus.Canceled) {
74+
this.setExitCode(1);
75+
}
76+
}
77+
78+
protected formatResult(): DeployCancelCommandResult {
79+
const formatter = new DeployCancelResultFormatter(this.logger, this.ux, this.deployResult);
80+
if (!this.isJsonOutput()) {
81+
formatter.display();
82+
}
83+
return formatter.getJson();
84+
}
85+
}

src/commands/force/source/delete.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export class Delete extends DeployCommand {
4444
}),
4545
wait: flags.minutes({
4646
char: 'w',
47-
default: Duration.minutes(Delete.DEFAULT_SRC_WAIT_MINUTES),
47+
default: Duration.minutes(Delete.DEFAULT_WAIT_MINUTES),
4848
min: Duration.minutes(1),
4949
description: messages.getMessage('flags.wait'),
5050
longDescription: messages.getMessage('flagsLong.wait'),

src/commands/force/source/deploy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export class Deploy extends DeployCommand {
4242
}),
4343
wait: flags.minutes({
4444
char: 'w',
45-
default: Duration.minutes(Deploy.DEFAULT_SRC_WAIT_MINUTES),
45+
default: Duration.minutes(Deploy.DEFAULT_WAIT_MINUTES),
4646
min: Duration.minutes(0), // wait=0 means deploy is asynchronous
4747
description: messages.getMessage('flags.wait'),
4848
longDescription: messages.getMessage('flagsLong.wait'),

src/commands/force/source/deploy/cancel.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77

88
import * as os from 'os';
99
import { flags, FlagsConfig } from '@salesforce/command';
10-
import { Messages } from '@salesforce/core';
10+
import { Messages, SfdxError } from '@salesforce/core';
1111
import { Duration } from '@salesforce/kit';
12-
import { getString } from '@salesforce/ts-types';
1312
import { RequestStatus } from '@salesforce/source-deploy-retrieve';
1413
import { DeployCommand } from '../../../../deployCommand';
1514
import {
@@ -27,14 +26,21 @@ export class Cancel extends DeployCommand {
2726
public static readonly flagsConfig: FlagsConfig = {
2827
wait: flags.minutes({
2928
char: 'w',
30-
default: Duration.minutes(DeployCommand.DEFAULT_SRC_WAIT_MINUTES),
29+
default: Duration.minutes(DeployCommand.DEFAULT_WAIT_MINUTES),
3130
min: Duration.minutes(1),
3231
description: messages.getMessage('flags.wait'),
3332
longDescription: messages.getMessage('flagsLong.wait'),
3433
}),
3534
jobid: flags.id({
3635
char: 'i',
3736
description: messages.getMessage('flags.jobid'),
37+
validate: (val) => {
38+
if (val.startsWith('0Af')) {
39+
return true;
40+
} else {
41+
throw SfdxError.create('@salesforce/plugin-source', 'deploy', 'invalidDeployId');
42+
}
43+
},
3844
}),
3945
};
4046

@@ -46,18 +52,22 @@ export class Cancel extends DeployCommand {
4652

4753
protected async cancel(): Promise<void> {
4854
const deployId = this.resolveDeployId(this.getFlag<string>('jobid'));
55+
try {
56+
const deploy = this.createDeploy(deployId);
57+
await deploy.cancel();
4958

50-
// TODO: update to use SDRL. This matches the toolbelt implementation.
51-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-assignment
52-
await this.org.getConnection().metadata['_invoke']('cancelDeploy', {
53-
deployId,
54-
});
55-
56-
this.deployResult = await this.poll(deployId);
59+
this.deployResult = await this.poll(deployId);
60+
} catch (e) {
61+
if (e instanceof Error) {
62+
throw SfdxError.create('@salesforce/plugin-source', 'cancel', 'CancelFailed', [e.message]);
63+
} else {
64+
throw SfdxError.wrap(e);
65+
}
66+
}
5767
}
5868

5969
protected resolveSuccess(): void {
60-
const status = getString(this.deployResult, 'response.status');
70+
const status = this.deployResult.response.status;
6171
if (status !== RequestStatus.Canceled) {
6272
this.setExitCode(1);
6373
}

src/commands/force/source/deploy/report.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
*/
77

88
import * as os from 'os';
9-
import { Messages, SfdxProject } from '@salesforce/core';
9+
import { Messages, SfdxError, SfdxProject } from '@salesforce/core';
1010
import { flags, FlagsConfig } from '@salesforce/command';
1111
import { Duration, env } from '@salesforce/kit';
12-
import { MetadataApiDeploy } from '@salesforce/source-deploy-retrieve';
1312
import { DeployCommand } from '../../../../deployCommand';
1413
import {
1514
DeployReportCommandResult,
@@ -30,7 +29,7 @@ export class Report extends DeployCommand {
3029
public static readonly flagsConfig: FlagsConfig = {
3130
wait: flags.minutes({
3231
char: 'w',
33-
default: Duration.minutes(DeployCommand.DEFAULT_SRC_WAIT_MINUTES),
32+
default: Duration.minutes(DeployCommand.DEFAULT_WAIT_MINUTES),
3433
min: Duration.minutes(1),
3534
description: messages.getMessage('flags.wait'),
3635
longDescription: messages.getMessage('flagsLong.wait'),
@@ -39,6 +38,13 @@ export class Report extends DeployCommand {
3938
char: 'i',
4039
description: messages.getMessage('flags.jobid'),
4140
longDescription: messages.getMessage('flagsLong.jobid'),
41+
validate: (val) => {
42+
if (val.startsWith('0Af')) {
43+
return true;
44+
} else {
45+
throw SfdxError.create('@salesforce/plugin-source', 'deploy', 'invalidDeployId');
46+
}
47+
},
4248
}),
4349
verbose: flags.builtin({
4450
description: messages.getMessage('flags.verbose'),
@@ -50,15 +56,6 @@ export class Report extends DeployCommand {
5056
return this.formatResult();
5157
}
5258

53-
/**
54-
* This method is here to provide a workaround to stubbing a constructor in the tests.
55-
*
56-
* @param id
57-
*/
58-
public createDeploy(id?: string): MetadataApiDeploy {
59-
return new MetadataApiDeploy({ usernameOrConnection: this.org.getUsername(), id });
60-
}
61-
6259
protected async doReport(): Promise<void> {
6360
const deployId = this.resolveDeployId(this.getFlag<string>('jobid'));
6461

src/commands/force/source/retrieve.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import { join } from 'path';
1010
import { flags, FlagsConfig } from '@salesforce/command';
1111
import { Messages, SfdxProject } from '@salesforce/core';
1212
import { Duration } from '@salesforce/kit';
13-
import { RetrieveResult, ComponentSet, RequestStatus } from '@salesforce/source-deploy-retrieve';
13+
import { ComponentSet, RequestStatus, RetrieveResult } from '@salesforce/source-deploy-retrieve';
1414
import { SourceCommand } from '../../../sourceCommand';
1515
import {
16-
RetrieveResultFormatter,
17-
RetrieveCommandResult,
1816
PackageRetrieval,
17+
RetrieveCommandResult,
18+
RetrieveResultFormatter,
1919
} from '../../../formatters/retrieveResultFormatter';
2020
import { ComponentSetBuilder } from '../../../componentSetBuilder';
2121

@@ -41,7 +41,7 @@ export class Retrieve extends SourceCommand {
4141
}),
4242
wait: flags.minutes({
4343
char: 'w',
44-
default: Duration.minutes(SourceCommand.DEFAULT_SRC_WAIT_MINUTES),
44+
default: Duration.minutes(SourceCommand.DEFAULT_WAIT_MINUTES),
4545
min: Duration.minutes(1),
4646
description: messages.getMessage('flags.wait'),
4747
longDescription: messages.getMessage('flagsLong.wait'),

0 commit comments

Comments
 (0)