Skip to content

Commit 79d27cf

Browse files
committed
fix: add pvr and pvcr
@W-11444281@ add package:version:report and package:version:create:report
1 parent 8a368fb commit 79d27cf

File tree

5 files changed

+291
-17
lines changed

5 files changed

+291
-17
lines changed

messages/package_version_report.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,15 @@ Dependencies
3737
# codeCoveragePercentages
3838

3939
Code Coverage Details
40+
41+
# ancestorId
42+
43+
Ancestor
44+
45+
# ancestorVersion
46+
47+
Ancestor Version
48+
49+
# isReleased
50+
51+
Released

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,18 @@
1111
"@salesforce/command": "^5.2.4",
1212
"@salesforce/core": "^3.26.1",
1313
"@salesforce/kit": "^1.5.45",
14-
"@salesforce/packaging": "^0.0.17",
14+
"@salesforce/packaging": "0.0.18-t-02",
15+
"chalk": "^4.1.2",
1516
"tslib": "^2"
1617
},
1718
"devDependencies": {
1819
"@oclif/plugin-command-snapshot": "^3.1.3",
1920
"@salesforce/cli-plugins-testkit": "^1.5.35",
2021
"@salesforce/dev-config": "^2.1.3",
2122
"@salesforce/dev-scripts": "^1.0.4",
23+
"@salesforce/plugin-auth": "^2.2.3",
2224
"@salesforce/plugin-command-reference": "^1.3.20",
2325
"@salesforce/plugin-config": "^1.4.12",
24-
"@salesforce/plugin-auth": "^2.2.3",
2526
"@salesforce/prettier-config": "^0.0.2",
2627
"@salesforce/ts-sinon": "1.3.21",
2728
"@salesforce/ts-types": "^1.5.20",

src/commands/force/package/beta/version/create/report.ts

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,22 @@
66
*/
77

88
import { flags, FlagsConfig, SfdxCommand } from '@salesforce/command';
9-
import { Messages, SfdxPropertyKeys } from '@salesforce/core';
9+
import { Messages, OrgConfigProperties } from '@salesforce/core';
10+
import { PackageVersion, PackageVersionCreateRequestResult } from '@salesforce/packaging';
11+
import * as pkgUtils from '@salesforce/packaging';
12+
import * as chalk from 'chalk';
1013

1114
Messages.importMessagesDirectory(__dirname);
1215
const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_version_create_report');
16+
const pvclMessages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_version_create_list');
17+
const plMessages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_list');
1318

1419
export class PackageVersionCreateReportCommand extends SfdxCommand {
1520
public static readonly description = messages.getMessage('cliDescription');
1621
public static readonly longDescription = messages.getMessage('cliLongDescription');
1722
public static readonly help = messages.getMessage('help');
1823
public static readonly;
19-
public static readonly orgType = SfdxPropertyKeys.DEFAULT_DEV_HUB_USERNAME;
24+
public static readonly orgType = OrgConfigProperties.TARGET_DEV_HUB;
2025
public static readonly requiresDevhubUsername = true;
2126
public static readonly flagsConfig: FlagsConfig = {
2227
packagecreaterequestid: flags.id({
@@ -27,8 +32,61 @@ export class PackageVersionCreateReportCommand extends SfdxCommand {
2732
}),
2833
};
2934

30-
public async run(): Promise<unknown> {
31-
process.exitCode = 1;
32-
return Promise.resolve('Not yet implemented');
35+
public async run(): Promise<PackageVersionCreateRequestResult> {
36+
const packageVersion = new PackageVersion({ connection: this.hubOrg.getConnection(), project: undefined });
37+
const result = await packageVersion.getCreateVersionReport(this.flags.packagecreaterequestid);
38+
this.display(result);
39+
return result;
40+
}
41+
42+
private display(record: PackageVersionCreateRequestResult): void {
43+
const installUrlValue =
44+
record.Status === 'Success' ? `${pkgUtils.INSTALL_URL_BASE.toString()}${record.SubscriberPackageVersionId}` : '';
45+
46+
const data = [
47+
{
48+
key: pvclMessages.getMessage('id'),
49+
value: record.Id,
50+
},
51+
{
52+
key: pvclMessages.getMessage('status'),
53+
value: pkgUtils.convertCamelCaseStringToSentence(record.Status),
54+
},
55+
{
56+
key: pvclMessages.getMessage('packageId'),
57+
value: record.Package2Id,
58+
},
59+
{
60+
key: pvclMessages.getMessage('packageVersionId'),
61+
value: record.Package2VersionId,
62+
},
63+
{
64+
key: pvclMessages.getMessage('subscriberPackageVersionId'),
65+
value: record.SubscriberPackageVersionId,
66+
},
67+
{
68+
key: pvclMessages.getMessage('tag'),
69+
value: record.Tag,
70+
},
71+
{
72+
key: pvclMessages.getMessage('branch'),
73+
value: record.Branch,
74+
},
75+
{ key: 'Created Date', value: record.CreatedDate },
76+
{
77+
key: pvclMessages.getMessage('installUrl'),
78+
value: installUrlValue,
79+
},
80+
{
81+
key: plMessages.getMessage('createdBy'),
82+
value: record.CreatedBy,
83+
},
84+
];
85+
86+
this.ux.styledHeader(chalk.blue('Package Version Create Request'));
87+
this.ux.table(data, {
88+
key: { header: 'Name' },
89+
value: { header: 'Value' },
90+
});
3391
}
3492
}

src/commands/force/package/beta/version/report.ts

Lines changed: 209 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,29 @@
66
*/
77

88
import { flags, FlagsConfig, SfdxCommand } from '@salesforce/command';
9-
import { Messages, SfdxPropertyKeys } from '@salesforce/core';
9+
import { Messages, OrgConfigProperties } from '@salesforce/core';
10+
import { CodeCoverage, PackageVersion, PackageVersionReportResult, PackagingSObjects } from '@salesforce/packaging';
11+
import * as pkgUtils from '@salesforce/packaging';
12+
import * as chalk from 'chalk';
1013

1114
Messages.importMessagesDirectory(__dirname);
1215
const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_version_report');
13-
16+
const pvlMessages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_version_list');
17+
const plMessages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_list');
18+
type PackageVersionReportResultModified = Omit<
19+
PackageVersionReportResult,
20+
'CodeCoverage' | 'HasPassedCodeCoverageCheck' | 'Package2' | 'HasMetadataRemoved'
21+
> & {
22+
CodeCoverage: CodeCoverage | string;
23+
HasPassedCodeCoverageCheck: boolean | string;
24+
Package2: Partial<Omit<PackagingSObjects.Package2, 'IsOrgDependent'> & { IsOrgDependent: boolean | string }>;
25+
HasMetadataRemoved: boolean | string;
26+
};
1427
export class PackageVersionReportCommand extends SfdxCommand {
1528
public static readonly description = messages.getMessage('cliDescription');
1629
public static readonly longDescription = messages.getMessage('cliLongDescription');
1730
public static readonly help = messages.getMessage('help');
18-
public static readonly orgType = SfdxPropertyKeys.DEFAULT_DEV_HUB_USERNAME;
31+
public static readonly orgType = OrgConfigProperties.TARGET_DEV_HUB;
1932
public static readonly requiresDevhubUsername = true;
2033
public static readonly requiresProject = true;
2134
public static readonly flagsConfig: FlagsConfig = {
@@ -30,9 +43,199 @@ export class PackageVersionReportCommand extends SfdxCommand {
3043
longDescription: messages.getMessage('verboseLongDescription'),
3144
}),
3245
};
46+
protected haveCodeCoverageData = false;
47+
48+
public async run(): Promise<PackageVersionReportResultModified> {
49+
const packageVersion = new PackageVersion({ connection: this.hubOrg.getConnection(), project: this.project });
50+
const results = await packageVersion.report(this.flags.package, this.flags.verbose);
51+
const massagedResults = await this.massageResultsForDisplay(results);
52+
this.display(massagedResults);
53+
return massagedResults;
54+
}
55+
56+
private display(record: PackageVersionReportResultModified): void {
57+
if (this.flags.json) {
58+
return;
59+
}
60+
61+
let dependencies: string = null;
62+
63+
// collect the Dependency 04ts into a comma-separated list for non-json output
64+
if (this.flags.verbose && record.SubscriberPackageVersion.Dependencies != null) {
65+
dependencies = record.SubscriberPackageVersion.Dependencies.ids
66+
.map((d) => d.subscriberPackageVersionId)
67+
.join(', ');
68+
}
69+
70+
// transform the results into a table
71+
const displayRecords = [
72+
{
73+
key: pvlMessages.getMessage('name'),
74+
value: record.Name,
75+
},
76+
{
77+
key: pvlMessages.getMessage('subscriberPackageVersionId'),
78+
value: record.SubscriberPackageVersionId,
79+
},
80+
{ key: 'Id', value: record.Id },
81+
{
82+
key: pvlMessages.getMessage('packageId'),
83+
value: record.Package2Id,
84+
},
85+
{
86+
key: pvlMessages.getMessage('version'),
87+
value: record.Version,
88+
},
89+
{
90+
key: pvlMessages.getMessage('description'),
91+
value: record.Description === null ? 'null' : record.Description,
92+
},
93+
{
94+
key: pvlMessages.getMessage('packageBranch'),
95+
value: record.Branch === null ? 'null' : record.Branch,
96+
},
97+
{
98+
key: pvlMessages.getMessage('packageTag'),
99+
value: record.Tag === null ? 'null' : record.Tag,
100+
},
101+
{ key: messages.getMessage('isReleased'), value: record.IsReleased.toString() },
102+
{
103+
key: pvlMessages.getMessage('validationSkipped'),
104+
value: record.ValidationSkipped,
105+
},
106+
{ key: messages.getMessage('ancestorId'), value: record.AncestorId },
107+
{ key: messages.getMessage('ancestorVersion'), value: record.AncestorVersion },
108+
{
109+
key: pvlMessages.getMessage('codeCoverage'),
110+
value:
111+
record.CodeCoverage === null
112+
? ' '
113+
: record.CodeCoverage['apexCodeCoveragePercentage'] !== undefined
114+
? `${record.CodeCoverage['apexCodeCoveragePercentage'] as number}%`
115+
: 'N/A', // N/A
116+
},
117+
{
118+
key: pvlMessages.getMessage('hasPassedCodeCoverageCheck'),
119+
value: record.HasPassedCodeCoverageCheck,
120+
},
121+
{
122+
key: pvlMessages.getMessage('convertedFromVersionId'),
123+
value: record.ConvertedFromVersionId === null ? ' ' : record.ConvertedFromVersionId,
124+
},
125+
{
126+
key: plMessages.getMessage('isOrgDependent'),
127+
value: record.Package2.IsOrgDependent,
128+
},
129+
{
130+
key: pvlMessages.getMessage('releaseVersion'),
131+
value: record.ReleaseVersion === null ? '' : record.ReleaseVersion.toFixed(1),
132+
},
133+
{
134+
key: pvlMessages.getMessage('buildDurationInSeconds'),
135+
value: record.BuildDurationInSeconds === null ? '' : record.BuildDurationInSeconds,
136+
},
137+
{
138+
key: pvlMessages.getMessage('hasMetadataRemoved'),
139+
value: record.HasMetadataRemoved,
140+
},
141+
{
142+
key: messages.getMessage('dependencies'),
143+
value: this.flags.verbose && dependencies != null ? dependencies : ' ',
144+
},
145+
{
146+
key: plMessages.getMessage('createdBy'),
147+
value: record.CreatedById,
148+
},
149+
];
150+
const maximumNumClasses = 15; // Number of least code covered classes displayed on the cli output for better UX.
151+
let codeCovStr = ''; // String to display when code coverage data is empty or null
152+
let displayCoverageRecords = [];
153+
// collect the code coverage data into an array of key value records for non-json output
154+
if (this.flags.verbose) {
155+
const coverageData = record.CodeCoveragePercentages?.codeCovPercentages;
156+
if (!coverageData) {
157+
codeCovStr = 'N/A'; // Code coverage isn't calculated as part of version create command
158+
} else if (!coverageData.length) {
159+
// Calculated code coverage data is too big to fit into a DB field. Retrieve it from the packageZip
160+
codeCovStr =
161+
'The code coverage details are too large to display. To request code coverage details for this package version, log a case in the Salesforce Partner Community.';
162+
} else {
163+
displayCoverageRecords = coverageData.slice(0, maximumNumClasses).map((coverageDatum) => {
164+
return {
165+
key: coverageDatum.className,
166+
value: `${coverageDatum.codeCoveragePercentage}%`,
167+
};
168+
});
169+
this.haveCodeCoverageData = displayCoverageRecords.length > 0;
170+
}
171+
}
172+
173+
// Always append code coverage column label ar the end
174+
displayRecords.push({
175+
key: messages.getMessage('codeCoveragePercentages'),
176+
value: this.haveCodeCoverageData === true ? '...' : codeCovStr,
177+
});
178+
if (!this.flags.verbose) {
179+
displayRecords.splice(displayRecords.map((e) => e.key).indexOf('Id'), 1);
180+
displayRecords.splice(
181+
displayRecords.map((e) => e.key).indexOf(pvlMessages.getMessage('convertedFromVersionId')),
182+
1
183+
);
184+
displayRecords.splice(displayRecords.map((e) => e.key).indexOf(messages.getMessage('dependencies')), 1);
185+
displayRecords.splice(
186+
displayRecords.map((e) => e.key).indexOf(messages.getMessage('codeCoveragePercentages')),
187+
1
188+
);
189+
displayCoverageRecords.splice(0, displayCoverageRecords.length);
190+
}
191+
this.ux.styledHeader(chalk.blue('Package Version'));
192+
this.ux.table(displayRecords, { key: { header: 'Name' }, value: { header: 'Value' } });
193+
if (displayCoverageRecords.length > 0) {
194+
this.ux.table(displayCoverageRecords, { key: { header: 'Class Name' }, value: { header: 'Code Coverage' } });
195+
}
196+
}
197+
198+
private async massageResultsForDisplay(
199+
results: PackageVersionReportResult
200+
): Promise<PackageVersionReportResultModified> {
201+
const record = results as PackageVersionReportResultModified;
202+
record.Version = [record.MajorVersion, record.MinorVersion, record.PatchVersion, record.BuildNumber].join('.');
203+
204+
let ancestorVersion: string = null;
205+
const containerOptions = await pkgUtils.getContainerOptions([record.Package2Id], this.hubOrg.getConnection());
206+
const packageType = containerOptions.get(record.Package2Id);
207+
if (record.AncestorId) {
208+
// lookup AncestorVersion value
209+
const ancestorVersionMap = await pkgUtils.getPackageVersionStrings(
210+
[record.AncestorId],
211+
this.hubOrg.getConnection()
212+
);
213+
ancestorVersion = ancestorVersionMap.get(record.AncestorId);
214+
} else {
215+
// otherwise display 'N/A' if package is Unlocked Packages
216+
if (packageType !== 'Managed') {
217+
ancestorVersion = 'N/A';
218+
record.AncestorId = 'N/A';
219+
}
220+
}
221+
222+
record.CodeCoverage =
223+
record.Package2.IsOrgDependent === true || record.ValidationSkipped === true ? 'N/A' : record.CodeCoverage;
224+
225+
record.HasPassedCodeCoverageCheck =
226+
record.Package2.IsOrgDependent === true || record.ValidationSkipped === true
227+
? 'N/A'
228+
: record.HasPassedCodeCoverageCheck;
229+
230+
record.Package2.IsOrgDependent =
231+
packageType === 'Managed' ? 'N/A' : record.Package2.IsOrgDependent === true ? 'Yes' : 'No';
232+
233+
// set HasMetadataRemoved to N/A for Unlocked, and No when value is false or absent (pre-230)
234+
record.HasMetadataRemoved = packageType !== 'Managed' ? 'N/A' : record.HasMetadataRemoved === true ? 'Yes' : 'No';
235+
236+
// add AncestorVersion to the json record
237+
record.AncestorVersion = ancestorVersion;
33238

34-
public async run(): Promise<unknown> {
35-
process.exitCode = 1;
36-
return Promise.resolve('Not yet implemented');
239+
return record;
37240
}
38241
}

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,10 +1150,10 @@
11501150
shx "^0.3.3"
11511151
tslib "^2.2.0"
11521152

1153-
"@salesforce/packaging@^0.0.17":
1154-
version "0.0.17"
1155-
resolved "https://registry.yarnpkg.com/@salesforce/packaging/-/packaging-0.0.17.tgz#cdf26185e2744ec606c4cad1e1978e5e97696e5d"
1156-
integrity sha512-zq0z0tfBZc3sk9rfBLw6ZcLL80KR12V8pEcStUiNF4LuLDD+oUBflyc2gbLcS9Og0oEXafncQxwhws7GWvpDAw==
1153+
"@salesforce/[email protected].18-t-02":
1154+
version "0.0.18-t-02"
1155+
resolved "http://localhost:4873/@salesforce%2fpackaging/-/packaging-0.0.18-t-02.tgz#fcac198ab25db3bfb834fb011b4bf8a7c177ea5c"
1156+
integrity sha512-zVyo/Y141KvLZgnK9bUxttzwY/tiZlAM4DWODXVkrDsH5lHThZklzY5K2zcrAbKImyTOQJB9KKHnjBzWvlvnsQ==
11571157
dependencies:
11581158
"@salesforce/core" "^3.24.0"
11591159
"@salesforce/kit" "^1.5.44"

0 commit comments

Comments
 (0)