salesforce-alm
Version:
This package contains tools, and APIs, for an improved salesforce.com developer experience.
329 lines (327 loc) • 15.9 kB
JavaScript
"use strict";
/*
* Copyright (c) 2020, 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
*/
// Node
const util = require("util");
const moment = require("moment");
const _ = require("lodash");
// Local
const Messages = require("../messages");
const messages = Messages();
const logger = require("../core/logApi");
const pkgUtils = require("./packageUtils");
// Stripping CodeCoverage, HasPassedCodeCoverageCheck as they are causing a perf issue in 47.0+ W-6997762
const DEFAULT_SELECT = 'SELECT Id, Package2Id, SubscriberPackageVersionId, Name, Package2.Name, Package2.NamespacePrefix, ' +
'Description, Tag, Branch, MajorVersion, MinorVersion, PatchVersion, BuildNumber, IsReleased, ' +
'CreatedDate, LastModifiedDate, IsPasswordProtected, AncestorId, ValidationSkipped, CreatedById ' +
'FROM Package2Version';
const VERBOSE_SELECT = 'SELECT Id, Package2Id, SubscriberPackageVersionId, Name, Package2.Name, Package2.NamespacePrefix, ' +
'Description, Tag, Branch, MajorVersion, MinorVersion, PatchVersion, BuildNumber, IsReleased, ' +
'CreatedDate, LastModifiedDate, IsPasswordProtected, CodeCoverage, HasPassedCodeCoverageCheck, AncestorId, ValidationSkipped, ' +
'ConvertedFromVersionId, Package2.IsOrgDependent, ReleaseVersion, BuildDurationInSeconds, HasMetadataRemoved, CreatedById ' +
'FROM Package2Version';
const DEFAULT_ORDER_BY_FIELDS = 'Package2Id, Branch, MajorVersion, MinorVersion, PatchVersion, BuildNumber';
class PackageVersionListCommand {
constructor() {
this.logger = logger.child('package:version:list');
this.results = [];
this.verbose = false;
this.concise = false;
}
execute(context) {
return this._execute(context).catch((err) => {
// TODO
// until package2 is GA, wrap perm-based errors w/ 'contact sfdc' action (REMOVE once package2 is GA'd)
throw pkgUtils.applyErrorAction(err);
});
}
_execute(context) {
this.org = context.org;
this.force = context.org.force;
this.verbose = context.flags.verbose;
this.concise = context.flags.concise;
return this.force.toolingQuery(this.org, this._constructQuery(context.flags)).then(async (queryResult) => {
const records = queryResult.records;
if (records && records.length > 0) {
let ancestorVersionsMap;
let containerOptionsMap;
// lookup ancestorVersions if ancestorIds are present
const ancestorIds = records.filter((record) => record.AncestorId).map((record) => record.AncestorId);
if (ancestorIds && ancestorIds.length > 0) {
ancestorVersionsMap = await pkgUtils.getPackageVersionStrings(ancestorIds, this.force, this.org);
}
// Get the container options for each package version. We need this for determining if the version is OrgDependent
const recordIds = [...new Set(records.map((record) => record.Package2Id))];
containerOptionsMap = await pkgUtils.getContainerOptions(recordIds, this.force, this.org);
records.forEach((record) => {
const ids = [record.Id, record.SubscriberPackageVersionId];
const aliases = [];
ids.forEach((id) => {
const matches = pkgUtils.getPackageAliasesFromId(id, this.force);
if (matches.length > 0) {
aliases.push(matches);
}
});
const AliasStr = aliases.length > 0 ? aliases.join() : '';
// set Ancestor display values
let ancestorVersion = null;
if (record.AncestorId) {
ancestorVersion = ancestorVersionsMap.get(record.AncestorId);
}
else if (containerOptionsMap.get(record.Package2Id) !== 'Managed') {
// display N/A if package is unlocked
ancestorVersion = 'N/A';
record.AncestorId = 'N/A';
}
const codeCoverage = record.CodeCoverage != null
? `${record.CodeCoverage['apexCodeCoveragePercentage']}%`
: record.Package2.IsOrgDependent === true || record.ValidationSkipped === true
? 'N/A'
: '';
const hasPassedCodeCoverageCheck = record.Package2.IsOrgDependent === true || record.ValidationSkipped === true
? 'N/A'
: record.HasPassedCodeCoverageCheck;
const isOrgDependent = containerOptionsMap.get(record.Package2Id) === 'Managed'
? 'N/A'
: record.Package2.IsOrgDependent === true
? 'Yes'
: 'No';
const hasMetadataRemoved = containerOptionsMap.get(record.Package2Id) !== 'Managed'
? 'N/A'
: record.HasMetadataRemoved === true
? 'Yes'
: 'No';
this.results.push({
Package2Id: record.Package2Id,
Branch: record.Branch,
Tag: record.Tag,
MajorVersion: record.MajorVersion,
MinorVersion: record.MinorVersion,
PatchVersion: record.PatchVersion,
BuildNumber: record.BuildNumber,
Id: record.Id,
SubscriberPackageVersionId: record.SubscriberPackageVersionId,
ConvertedFromVersionId: record.ConvertedFromVersionId,
Name: record.Name,
NamespacePrefix: record.Package2.NamespacePrefix,
Package2Name: record.Package2.Name,
Description: record.Description,
Version: [record.MajorVersion, record.MinorVersion, record.PatchVersion, record.BuildNumber].join('.'),
// Table output needs string false to display 'false'
IsPasswordProtected: context.flags.json
? record.IsPasswordProtected
: record.IsPasswordProtected.toString(),
IsReleased: context.flags.json ? record.IsReleased : record.IsReleased.toString(),
CreatedDate: moment(record.CreatedDate).format('YYYY-MM-DD HH:mm'),
LastModifiedDate: moment(record.LastModifiedDate).format('YYYY-MM-DD HH:mm'),
InstallUrl: pkgUtils.INSTALL_URL_BASE + record.SubscriberPackageVersionId,
CodeCoverage: codeCoverage,
HasPassedCodeCoverageCheck: hasPassedCodeCoverageCheck,
ValidationSkipped: record.ValidationSkipped,
AncestorId: record.AncestorId,
AncestorVersion: ancestorVersion,
Alias: AliasStr,
IsOrgDependent: isOrgDependent,
ReleaseVersion: record.ReleaseVersion == null ? '' : Number.parseFloat(record.ReleaseVersion).toFixed(1),
BuildDurationInSeconds: record.BuildDurationInSeconds == null ? '' : record.BuildDurationInSeconds,
HasMetadataRemoved: hasMetadataRemoved,
CreatedBy: record.CreatedById,
});
});
}
return this.results;
});
}
_getLastDays(paramName, lastDays) {
if (isNaN(lastDays)) {
throw new Error(messages.getMessage('invalidDaysNumber', paramName, 'packaging'));
}
if (parseInt(lastDays, 10) < 0) {
throw new Error(messages.getMessage('invalidDaysNumber', paramName, 'packaging'));
}
return lastDays;
}
// construct custom WHERE clause parts
_constructWhere(idsOrAliases, createdLastDays, lastModLastDays) {
const where = [];
// filter on given package ids
if (idsOrAliases) {
// split and remove dups
if (util.isString(idsOrAliases)) {
idsOrAliases = idsOrAliases.split(',');
}
idsOrAliases = _.uniq(idsOrAliases);
// resolve any aliases
const packageIds = idsOrAliases.map((idOrAlias) => pkgUtils.getPackageIdFromAlias(idOrAlias, this.force));
// validate ids
packageIds.forEach((packageid) => {
pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, packageid);
});
// stash where part
if (packageIds.length > 1) {
where.push(`Package2Id IN ('${packageIds.join("','")}')`);
}
else {
where.push(`Package2Id = '${packageIds[0]}'`);
}
}
// filter on created date, days ago: 0 for today, etc
if (!util.isNullOrUndefined(createdLastDays)) {
createdLastDays = this._getLastDays('createdlastdays', createdLastDays);
where.push(`CreatedDate = LAST_N_DAYS:${createdLastDays}`);
}
// filter on last mod date, days ago: 0 for today, etc
if (!util.isNullOrUndefined(lastModLastDays)) {
lastModLastDays = this._getLastDays('modifiedlastdays', lastModLastDays);
where.push(`LastModifiedDate = LAST_N_DAYS:${lastModLastDays}`);
}
// exclude deleted
where.push('IsDeprecated = false');
return where;
}
// assemble query
_assembleQueryParts(select, where = [], orderBy = '') {
let wherePart = '';
if (where.length > 0) {
wherePart = ` WHERE ${where.join(' AND ')}`;
}
const query = `${select}${wherePart}${orderBy}`;
logger.debug(query);
return query;
}
// construct query based on given params
_constructQuery(flags = {}) {
// construct custom WHERE clause, if applicable
const where = this._constructWhere(flags.packages, flags.createdlastdays, flags.modifiedlastdays);
if (flags.released) {
where.push('IsReleased = true');
}
// construct ORDER BY clause
// TODO: validate given fields
const orderBy = ` ORDER BY ${flags.orderby ? flags.orderby : DEFAULT_ORDER_BY_FIELDS}`;
return this._assembleQueryParts(flags.verbose === true ? VERBOSE_SELECT : DEFAULT_SELECT, where, orderBy);
}
/**
* indicates that the human readable message should be tabular
*
* @returns {[{}...]}
*/
getColumnData() {
this.logger.styledHeader(this.logger.color.blue(`Package Versions [${this.results.length}]`));
if (this.concise) {
return [
{
key: 'Package2Id',
label: messages.getMessage('packageId', [], 'package_version_list'),
},
{
key: 'Version',
label: messages.getMessage('version', [], 'package_version_list'),
},
{
key: 'SubscriberPackageVersionId',
label: messages.getMessage('subscriberPackageVersionId', [], 'package_version_list'),
},
{ key: 'IsReleased', label: 'Released' },
];
}
const columns = [
{ key: 'Package2Name', label: 'Package Name' },
{ key: 'NamespacePrefix', label: 'Namespace' },
{ key: 'Name', label: 'Version Name' },
{
key: 'Version',
label: messages.getMessage('version', [], 'package_version_list'),
},
{
key: 'SubscriberPackageVersionId',
label: messages.getMessage('subscriberPackageVersionId', [], 'package_version_list'),
},
{
key: 'Alias',
label: messages.getMessage('alias', [], 'package_version_list'),
},
{
key: 'IsPasswordProtected',
label: messages.getMessage('installKey', [], 'package_version_list'),
},
{ key: 'IsReleased', label: 'Released' },
{
key: 'ValidationSkipped',
label: messages.getMessage('validationSkipped', [], 'package_version_list'),
},
{ key: 'AncestorId', label: 'Ancestor' },
{ key: 'AncestorVersion', label: 'Ancestor Version' },
{
key: 'Branch',
label: messages.getMessage('packageBranch', [], 'package_version_list'),
},
];
if (this.verbose) {
columns.push({
key: 'Package2Id',
label: messages.getMessage('packageId', [], 'package_version_list'),
});
columns.push({
key: 'InstallUrl',
label: messages.getMessage('installUrl', [], 'package_version_list'),
});
columns.push({
key: 'Id',
label: messages.getMessage('id', [], 'package_version_list'),
});
columns.push({ key: 'CreatedDate', label: 'Created Date' });
columns.push({ key: 'LastModifiedDate', label: 'Last Modified Date' });
columns.push({
key: 'Tag',
label: messages.getMessage('packageTag', [], 'package_version_list'),
});
columns.push({
key: 'Description',
label: messages.getMessage('description', [], 'package_version_list'),
});
columns.push({
key: 'CodeCoverage',
label: messages.getMessage('codeCoverage', [], 'package_version_list'),
});
columns.push({
key: 'HasPassedCodeCoverageCheck',
label: messages.getMessage('hasPassedCodeCoverageCheck', [], 'package_version_list'),
});
columns.push({
key: 'ConvertedFromVersionId',
label: messages.getMessage('convertedFromVersionId', [], 'package_version_list'),
});
columns.push({
key: 'IsOrgDependent',
label: messages.getMessage('isOrgDependent', [], 'package_list'),
});
columns.push({
key: 'ReleaseVersion',
label: messages.getMessage('releaseVersion', [], 'package_version_list'),
});
columns.push({
key: 'BuildDurationInSeconds',
label: messages.getMessage('buildDurationInSeconds', [], 'package_version_list'),
});
columns.push({
key: 'HasMetadataRemoved',
label: messages.getMessage('hasMetadataRemoved', [], 'package_version_list'),
});
columns.push({
key: 'CreatedBy',
label: messages.getMessage('createdBy', [], 'package_list'),
});
}
return columns;
}
}
PackageVersionListCommand.DEFAULT_SELECT = DEFAULT_SELECT;
PackageVersionListCommand.VERBOSE_SELECT = VERBOSE_SELECT;
PackageVersionListCommand.DEFAULT_ORDER_BY_FIELDS = DEFAULT_ORDER_BY_FIELDS;
module.exports = PackageVersionListCommand;
//# sourceMappingURL=packageVersionListCommand.js.map