@salesforce/acu-pack
Version:
SFDX CLI Extensions
418 lines • 18.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SfdxTasks = exports.SfdxOrgInfo = exports.SfdxJobInfo = void 0;
const path = require("path");
const fs_1 = require("fs");
const ts_types_1 = require("@salesforce/ts-types");
const utils_1 = require("../lib/utils");
const utils_2 = require("../lib/utils");
const constants_1 = require("../lib/constants");
const sfdx_core_1 = require("./sfdx-core");
const sfdx_query_1 = require("./sfdx-query");
class SfdxJobInfo {
constructor() {
this.statusCount = 0;
this.maxStatusCount = 0;
}
isDone() {
// Holding1, Queued, Preparing, Processing, Aborted, Completed,Failed
return this.state === 'Aborted' || this.state === 'Completed' || this.state === 'Failed' || this.state === 'Closed';
}
}
exports.SfdxJobInfo = SfdxJobInfo;
class SfdxOrgInfo {
constructor(result = null) {
if (!result) {
return;
}
this.username = result.username;
this.id = result.id;
this.connectedStatus = result.connectedStatus;
this.accessToken = result.accessToken;
this.instanceUrl = result.instanceUrl;
this.clientId = result.clientId;
this.alias = result.alias;
}
}
exports.SfdxOrgInfo = SfdxOrgInfo;
class SfdxTasks {
static async describeMetadata(usernameOrAlias) {
const response = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_DESCRIBE_METADATA} --json -u ${usernameOrAlias}`);
/* eslint-disable-next-line @typescript-eslint/no-unsafe-return */
return !response || !response.metadataObjects
? []
: (0, ts_types_1.ensureArray)(response.metadataObjects);
}
static async executeAnonymousBlock(usernameOrAlias, apexFilePath, logLevel = 'debug') {
const response = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_APEX_EXECUTE} --json --loglevel ${logLevel} -u ${usernameOrAlias} --apexcodefile ${apexFilePath}`);
/* eslint-disable-next-line @typescript-eslint/no-unsafe-return */
return response.result;
}
static async retrievePackage(usernameOrAlias, packageFilePath = constants_1.default.DEFAULT_PACKAGE_PATH) {
// get custom objects
/* eslint-disable-next-line @typescript-eslint/no-unsafe-return */
return await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_SOURCE_RETRIEVE} --json -x ${packageFilePath} -u ${usernameOrAlias}`);
}
static async initializeProject(projectName) {
return await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_PROJECT_CREATE} --projectname ${projectName}`);
}
static async *getTypesForPackage(usernameOrAlias, describeMetadatas, namespaces = null) {
let folderPathMap;
for (const describeMetadata of describeMetadatas) {
const members = [];
if (!describeMetadata.inFolder) {
for await (const result of this.listMetadata(usernameOrAlias, describeMetadata.xmlName, namespaces)) {
members.push(result.fullName);
}
}
else {
const folderMetaName = describeMetadata.xmlName === sfdx_core_1.SfdxCore.EMAIL_TEMPLATE_XML_NAME
? sfdx_core_1.SfdxCore.EMAIL_TEMPLATE_XML_NAME
: `${describeMetadata.xmlName}Folder`;
// Get SOQL folder data (ONCE!)
if (!folderPathMap) {
folderPathMap = await this.getFolderSOQLData(usernameOrAlias);
}
// Iterate all the folder metas
for await (const folderMeta of this.listMetadata(usernameOrAlias, folderMetaName, namespaces)) {
// Set the parent Id (used for nested folders)
// Salesforce does not return the full path in the metadada
//
const folderPath = folderPathMap.has(folderMeta.id)
? folderPathMap.get(folderMeta.id)
: folderMeta.fullName;
// Add the meta for just the folder
members.push(folderPath);
for await (const inFolderMetadata of this.listMetadataInFolder(usernameOrAlias, describeMetadata.xmlName, folderMeta.fullName)) {
// Add the meta for the item in the folder
members.push([folderPath, path.basename(inFolderMetadata.fullName)].join('/'));
}
}
}
yield { name: describeMetadata.xmlName, members };
}
}
static async listMetadatas(usernameOrAlias, metadataTypes, namespaces = null) {
const response = new Map();
for (const metadataType of metadataTypes) {
const results = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_MDAPI_LISTMETADATA} --json -m ${metadataType} -u ${usernameOrAlias}`);
// If there are no instances of the metadatatype SFDX just returns {status:0}
const members = [];
if (results) {
for (const result of results) {
// If we have a metadata namespace AND
// We are excluding namespaces OR
// The list of allowed namespaces does not include the metdata namespace
// Continue.
if (result.namespacePrefix && namespaces && !namespaces.has(result.namespacePrefix)) {
continue;
}
members.push(result.fullName);
}
}
response.set(metadataType, members);
}
return response;
}
static async *listMetadata(usernameOrAlias, metadataType, namespaces = null) {
const results = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_MDAPI_LISTMETADATA} --json -m ${metadataType} -u ${usernameOrAlias}`);
// If there are no instances of the metadatatype SFDX just returns {status:0}
if (results) {
let resultsArray;
try {
resultsArray = (0, ts_types_1.ensureArray)(results);
}
catch {
resultsArray = [results];
}
for (const result of resultsArray) {
// If we have a metadata namespace AND
// We are excluding namespaces OR
// The list of allowed namespaces does not include the metdata namespace
// Continue.
if (result.namespacePrefix && (!namespaces || !namespaces.has(result.namespacePrefix))) {
continue;
}
yield result;
}
}
}
static async *listMetadataInFolder(usernameOrAlias, metadataType, folderName, namespaces = null) {
const results = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_MDAPI_LISTMETADATA} --json -m ${metadataType} --folder ${folderName} -u ${usernameOrAlias}`);
// If there are no instances of the metadatatype SFDX just returns {status:0}
if (results) {
let resultsArray;
try {
resultsArray = (0, ts_types_1.ensureArray)(results);
}
catch {
resultsArray = [results];
}
for (const result of resultsArray) {
// If we have a metadata namespace AND
// We are excluding namespaces OR
// The list of allowed namespaces does not include the metdata namespace
// Continue.
if (result.namespacePrefix && (!namespaces || !namespaces.has(result.namespacePrefix))) {
continue;
}
yield result;
}
}
}
static async describeObject(usernameOrAlias, objectName) {
/* eslint-disable-next-line @typescript-eslint/no-unsafe-return */
return await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_SCHEMA_DESCRIBE} --json -s ${objectName} -u ${usernameOrAlias}`);
}
static async enqueueApexTests(usernameOrAlias, sfdxEntities, shouldSkipCodeCoverage = false) {
if (!usernameOrAlias || !sfdxEntities) {
return null;
}
const tempFileName = 'apexTestQueueItems.csv';
// Create the file for the bulk upsert
// Create for writing - truncates if exists
const stream = (0, fs_1.openSync)(tempFileName, 'w');
// NOTE: Do NOT include spaces between fields...results in an error
(0, fs_1.writeSync)(stream, `ApexClassId,ShouldSkipCodeCoverage${constants_1.default.EOL}`);
for (const sfdxEntity of sfdxEntities) {
(0, fs_1.writeSync)(stream, `${sfdxEntity.id},${shouldSkipCodeCoverage}${constants_1.default.EOL}`);
}
const command = `${constants_1.default.SFDX_DATA_UPSERT} --json -s ApexTestQueueItem -i Id -f "${tempFileName}" -u ${usernameOrAlias}`;
const results = await sfdx_core_1.SfdxCore.command(command);
return SfdxTasks.getJobInfo(results);
}
static async getBulkJobStatus(usernameOrAlias, jobInfo) {
if (!usernameOrAlias || !jobInfo || !jobInfo.id) {
return null;
}
let command = `${constants_1.default.SFDX_DATA_STATUS} --json -i ${jobInfo.id} -u ${usernameOrAlias}`;
if (jobInfo.batchId) {
command += ` -b ${jobInfo.batchId}`;
}
const results = await sfdx_core_1.SfdxCore.command(command);
const newJobInfo = SfdxTasks.getJobInfo(results);
newJobInfo.statusCount++;
return newJobInfo;
}
static async *waitForJob(usernameOrAlias, jobInfo, maxWaitSeconds = -1, sleepMiliseconds = 5000) {
const maxCounter = (maxWaitSeconds * 1000) / sleepMiliseconds;
jobInfo.statusCount = 0;
while ((maxCounter <= 0 || jobInfo.statusCount <= maxCounter) && !jobInfo.isDone()) {
await utils_1.default.sleep(sleepMiliseconds);
jobInfo = await SfdxTasks.getBulkJobStatus(usernameOrAlias, jobInfo);
jobInfo.maxStatusCount = maxCounter;
jobInfo.statusCount++;
yield jobInfo;
}
return jobInfo;
}
static async getOrgInfo(orgAliasOrUsername) {
if (!orgAliasOrUsername) {
return null;
}
const result = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_ORG_DISPLAY} --json -u ${orgAliasOrUsername}`);
return new SfdxOrgInfo(result);
}
static getMapFromSourceTrackingStatus(sourceTrackingStatues) {
if (!sourceTrackingStatues) {
return null;
}
const metadataMap = new Map();
const conflictTypes = new Map();
const deleteTypes = new Map();
for (const status of sourceTrackingStatues) {
/*
Actions: Add, Changed, Deleted
{
"state": "Local Add",
"fullName": "SF86_Template",
"type": "StaticResource",
"filePath": "force-app\\main\\default\\staticresources\\SF86_Template.xml"
},
{
"state": "Remote Add",
"fullName": "Admin",
"type": "Profile",
"filePath": null
},
{
"state": "Remote Changed (Conflict)",
"fullName": "Custom%3A Support Profile",
"type": "Profile",
"filePath": "force-app\\main\\default\\profiles\\Custom%3A Support Profile.profile-meta.xml"
},
*/
const actionParts = status.state.split(' ');
const typeName = status.type.trim().endsWith('Folder')
? status.type.replace(/Folder/, '').trim()
: status.type.trim();
const fullName = status.fullName.trim();
let collection = null;
if (status.state.includes('(Conflict)')) {
collection = conflictTypes;
}
else if (actionParts[0] === 'Remote') {
switch (actionParts[1]) {
case 'Add':
case 'Changed':
collection = metadataMap;
break;
case 'Deleted':
collection = deleteTypes;
break;
default:
throw new Error(`Unknown Action: ${actionParts[1]}`);
}
}
if (collection != null) {
if (!collection.has(typeName)) {
collection.set(typeName, [fullName]);
}
else {
collection.get(typeName).push(fullName);
}
}
}
return {
map: metadataMap,
conflicts: conflictTypes,
deletes: deleteTypes
};
}
static async getSourceTrackingStatus(orgAliasOrUsername) {
if (!orgAliasOrUsername) {
return null;
}
const results = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_SOURCE_STATUS} --json -u ${orgAliasOrUsername}`);
// If there are no instances of the metadatatype SFDX just returns {status:0}
if (!results) {
return null;
}
let resultsArray;
try {
resultsArray = (0, ts_types_1.ensureArray)(results);
}
catch {
resultsArray = [results];
}
const statuses = [];
for (const result of resultsArray) {
statuses.push({
state: result.state,
fullName: result.fullName,
type: result.type,
filePath: result.filePath
});
/*
Actions: Add, Changed, Deleted
{
"state": "Local Add",
"fullName": "SF86_Template",
"type": "StaticResource",
"filePath": "force-app\\main\\default\\staticresources\\SF86_Template.xml"
},
{
"state": "Remote Add",
"fullName": "Admin",
"type": "Profile",
"filePath": null
},
{
"state": "Remote Changed (Conflict)",
"fullName": "Custom%3A Support Profile",
"type": "Profile",
"filePath": "force-app\\main\\default\\profiles\\Custom%3A Support Profile.profile-meta.xml"
},
*/
}
/* eslint-disable-next-line @typescript-eslint/no-unsafe-return */
return statuses;
}
static async getConfigValue(configName) {
const result = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_CONFIG_GET} ${configName} --json`);
return (result[0] != null
? result[0].value
: null);
}
static async setConfigValue(configName, configValue) {
const result = await sfdx_core_1.SfdxCore.command(`${constants_1.default.SFDX_CONFIG_SET} ${configName}=${configValue} --json`);
if (result.failures && result.failures.length > 0) {
throw new Error(JSON.stringify(result));
}
}
static async getMaxQueryLimit() {
return Number(await SfdxTasks.getConfigValue(constants_1.default.SFDX_CONFIG_MAX_QUERY_LIMIT));
}
static async setMaxQueryLimit(maxQueryLimit) {
await SfdxTasks.setConfigValue(constants_1.default.SFDX_CONFIG_MAX_QUERY_LIMIT, `${maxQueryLimit}`);
}
static async getDefaultOrgAlias() {
return SfdxTasks.getConfigValue(constants_1.default.SFDX_CONFIG_DEFAULT_USERNAME);
}
static async setDefaultOrgAlias(orgAlias) {
await SfdxTasks.setConfigValue(constants_1.default.SFDX_CONFIG_DEFAULT_USERNAME, orgAlias);
}
static async getUnsupportedMetadataTypes() {
const result = await utils_1.default.getRestResult(utils_2.RestAction.GET, constants_1.default.METADATA_COVERAGE_REPORT_URL);
if (!result || result.isError === true) {
return [];
}
const myMap = new Map(Object.entries(result.getContent().types));
const types = [];
for (const [key, value] of myMap) {
if (value.channels && !value.channels.metadataApi) {
types.push(key);
}
}
return utils_1.default.sortArray(types);
}
static async getFolderSOQLData(usernameOrAlias) {
if (!this.proFolderPaths) {
const allFolders = await sfdx_query_1.SfdxQuery.getFolders(usernameOrAlias);
this.proFolderPaths = new Map();
for (const folder of allFolders) {
if (!folder) {
continue;
}
const pathParts = this.getFolderFullPath(allFolders, folder, []);
this.proFolderPaths.set(folder.id, pathParts.join('/'));
}
}
return this.proFolderPaths;
}
// Recursively looks up a Folder's parent until it reaches the tree's root.
// This is only needed for Folder structures which are more than one level deep.
// SFDX only returns a entitie's direct parent.
static getFolderFullPath(folders, currentFolder, pathParts) {
if (currentFolder.developerName) {
pathParts.unshift(currentFolder.developerName.trim());
}
for (const folder of folders) {
if (folder.id === currentFolder.parentId) {
pathParts = this.getFolderFullPath(folders, folder, pathParts);
}
}
return pathParts;
}
static getJobInfo(results) {
const jobInfo = new SfdxJobInfo();
if (results && results[0]) {
// If there is a jobId then we have a batch job
// If not its is a single job
if (results[0].jobId) {
jobInfo.id = results[0].jobId;
jobInfo.batchId = results[0].id;
}
else {
jobInfo.id = results[0].id;
}
jobInfo.state = results[0].state;
jobInfo.createdDate = results[0].createdDate;
}
return jobInfo;
}
}
exports.SfdxTasks = SfdxTasks;
SfdxTasks.defaultMetaTypes = ['ApexClass', 'ApexPage', 'CustomApplication', 'CustomObject', 'CustomTab', 'PermissionSet', 'Profile'];
SfdxTasks.proFolderPaths = null;
//# sourceMappingURL=sfdx-tasks.js.map