-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathreport.ts
More file actions
148 lines (136 loc) · 5.86 KB
/
report.ts
File metadata and controls
148 lines (136 loc) · 5.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* Copyright (c) 2022, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import { Messages, Org, SfProject } from '@salesforce/core';
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { ComponentSet, DeployResult, MetadataApiDeploy } from '@salesforce/source-deploy-retrieve';
import { Duration } from '@salesforce/kit';
import { buildComponentSet } from '../../../utils/deploy';
import { DeployProgress } from '../../../utils/progressBar';
import { DeployCache } from '../../../utils/deployCache';
import { DeployReportResultFormatter } from '../../../formatters/deployReportResultFormatter';
import { DeployResultJson } from '../../../utils/types';
import { coverageFormattersFlag } from '../../../utils/flags';
Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'deploy.metadata.report');
const deployMessages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'deploy.metadata');
const testFlags = 'Test';
export default class DeployMetadataReport extends SfCommand<DeployResultJson> {
public static readonly description = messages.getMessage('description');
public static readonly summary = messages.getMessage('summary');
public static readonly examples = messages.getMessages('examples');
public static readonly aliases = ['deploy:metadata:report'];
public static readonly deprecateAliases = true;
public static readonly flags = {
'target-org': Flags.optionalOrg({
char: 'o',
description: deployMessages.getMessage('flags.target-org.description'),
summary: deployMessages.getMessage('flags.target-org.summary'),
}),
'job-id': Flags.salesforceId({
char: 'i',
startsWith: '0Af',
length: 'both',
description: messages.getMessage('flags.job-id.description'),
summary: messages.getMessage('flags.job-id.summary'),
exactlyOne: ['use-most-recent', 'job-id'],
}),
'use-most-recent': Flags.boolean({
char: 'r',
description: messages.getMessage('flags.use-most-recent.description'),
summary: messages.getMessage('flags.use-most-recent.summary'),
exactlyOne: ['use-most-recent', 'job-id'],
}),
'coverage-formatters': { ...coverageFormattersFlag, helpGroup: testFlags },
junit: Flags.boolean({
summary: messages.getMessage('flags.junit.summary'),
helpGroup: testFlags,
}),
'results-dir': Flags.directory({
relationships: [{ type: 'some', flags: ['coverage-formatters', 'junit'] }],
summary: messages.getMessage('flags.results-dir.summary'),
helpGroup: testFlags,
}),
wait: Flags.duration({
char: 'w',
summary: deployMessages.getMessage('flags.wait.summary'),
description: deployMessages.getMessage('flags.wait.description'),
unit: 'minutes',
helpValue: '<minutes>',
min: 0,
default: new Duration(0, Duration.Unit.MINUTES),
}),
};
public async run(): Promise<DeployResultJson> {
const [{ flags }, cache] = await Promise.all([this.parse(DeployMetadataReport), DeployCache.create()]);
const jobId = cache.resolveLatest(flags['use-most-recent'], flags['job-id'], false);
const deployOpts = cache.get(jobId) ?? {};
const org = flags['target-org'] ?? (await Org.create({ aliasOrUsername: deployOpts['target-org'] }));
// if we're using mdapi we won't have a component set
let componentSet = new ComponentSet();
if (!deployOpts.isMdapi) {
if (!cache.get(jobId)) {
// If the cache file isn't there, use the project package directories for the CompSet
try {
this.project = await SfProject.resolve();
const sourcepath = this.project.getUniquePackageDirectories().map((pDir) => pDir.fullPath);
componentSet = await buildComponentSet({ 'source-dir': sourcepath, wait: flags['wait'] });
} catch (err) {
// ignore the error. this was just to get improved command output.
}
} else {
componentSet = await buildComponentSet({ ...deployOpts, wait: flags['wait'] });
}
}
const mdapiDeploy = new MetadataApiDeploy({
// setting an API version here won't matter since we're just checking deploy status
// eslint-disable-next-line sf-plugin/get-connection-with-version
usernameOrConnection: org.getConnection(),
id: jobId,
components: componentSet,
apiOptions: {
rest: deployOpts.api === 'REST',
},
});
const getDeployResult = async (): Promise<DeployResult> => {
try {
const deployStatus = await mdapiDeploy.checkStatus();
return new DeployResult(deployStatus, componentSet);
} catch (error) {
if (error instanceof Error && error.name === 'sf:INVALID_CROSS_REFERENCE_KEY') {
throw deployMessages.createError('error.InvalidDeployId', [jobId, org.getUsername()]);
}
throw error;
}
};
let result: DeployResult;
if (flags.wait.quantity > 0) {
// poll for deploy results
try {
new DeployProgress(mdapiDeploy, this.jsonEnabled()).start();
result = await mdapiDeploy.pollStatus(500, flags.wait.seconds);
} catch (error) {
if (error instanceof Error && error.message.includes('The client has timed out')) {
this.debug('[project deploy report] polling timed out. Requesting status...');
} else {
throw error;
}
} finally {
result = await getDeployResult();
}
} else {
// check the deploy status
result = await getDeployResult();
}
const formatter = new DeployReportResultFormatter(result, {
...deployOpts,
...flags,
...{ 'target-org': org },
});
if (!this.jsonEnabled()) formatter.display();
return formatter.getJson();
}
}