sfdx-hardis
Version:
Swiss-army-knife Toolbox for Salesforce. Allows you to define a complete CD/CD Pipeline. Orchestrate base commands and assist users with interactive wizards
116 lines • 5.16 kB
JavaScript
import { GitProvider } from "../gitProvider/index.js";
import { uxLog } from "./index.js";
import c from "chalk";
import path from "path";
import fs from "fs-extra";
import yaml from "js-yaml";
import { listMajorOrgs } from "./orgConfigUtils.js";
import { SfError } from "@salesforce/core";
let _cachedPullRequests = null;
export async function getPullRequestScopedSfdxHardisConfig(pr) {
const configFromPrDescription = getYamlFromPrDescription(pr);
let configFromFile = null;
const prConfigFileName = path.join("scripts", "actions", `.sfdx-hardis.${pr.idStr}.yml`);
if (fs.existsSync(prConfigFileName)) {
try {
const prConfig = await fs.readFile(prConfigFileName, 'utf8');
configFromFile = yaml.load(prConfig);
}
catch (err) {
throw new SfError(`[PullRequestUtils] Error reading/parsing PR config file ${prConfigFileName} for PR ${pr.idStr}: ${err}`);
}
}
if (!configFromFile && !configFromPrDescription) {
return null;
}
if (!configFromFile) {
return configFromPrDescription;
}
if (!configFromPrDescription) {
return configFromFile;
}
// Merge config from file and from PR description (PR description has precedence). Log when a property has been overridden
const mergedConfig = { ...configFromFile };
for (const [key, value] of Object.entries(configFromPrDescription)) {
if (Object.prototype.hasOwnProperty.call(mergedConfig, key)) {
uxLog("log", this, c.grey(`[PullRequestUtils] Overriding PR config property '${key}' from PR description for PR ${pr.idStr} ${pr.webUrl}`));
}
mergedConfig[key] = value;
}
return mergedConfig;
}
function getYamlFromPrDescription(pr) {
const yamlStart = pr.description.indexOf("```yaml");
const yamlEnd = pr.description.indexOf("```", yamlStart + 1);
if (yamlStart !== -1 && yamlEnd !== -1) {
const yamlContent = pr.description.substring(yamlStart + 7, yamlEnd).trim();
try {
const parsedYaml = yaml.load(yamlContent);
return parsedYaml;
}
catch (err) {
throw new SfError(`[PullRequestUtils] Error parsing YAML from PR description for PR ${pr.idStr} ${pr.webUrl}: ${err}`);
}
}
return null;
}
export async function listAllPullRequestsForCurrentScope(checkOnly) {
if (_cachedPullRequests) {
return _cachedPullRequests;
}
const gitProvider = await GitProvider.getInstance();
if (!gitProvider) {
uxLog("warning", this, c.yellow('[GitProvider] No git provider configured, skipping retrieval of pull requests'));
return [];
}
const pullRequestInfo = await gitProvider.getPullRequestInfo();
if (!pullRequestInfo) {
uxLog("warning", this, c.yellow('[GitProvider] No pull request info available, skipping retrieval of pull requests'));
return [];
}
const majorOrgs = await listMajorOrgs();
// Source & target are not the same if we are in checkOnly mode or deployment mode
let sourceBranchToUse = '';
let targetBranchToUse = '';
if (checkOnly) {
sourceBranchToUse = pullRequestInfo.sourceBranch;
targetBranchToUse = pullRequestInfo.targetBranch;
}
else {
const prTargetOrgDef = majorOrgs.find(o => o.branchName === pullRequestInfo.targetBranch);
if (prTargetOrgDef) {
if (!prTargetOrgDef.mergeTargets || prTargetOrgDef.mergeTargets.length === 0) {
uxLog("warning", this, c.yellow(`[GitProvider] No merge targets defined for target branch ${prTargetOrgDef.branchName}, cannot retrieve pull requests.`));
return [];
}
sourceBranchToUse = prTargetOrgDef.branchName;
targetBranchToUse = prTargetOrgDef.mergeTargets[0]; // Use first merge target as target branch
}
else {
uxLog("warning", this, c.yellow(`[GitProvider] Target branch ${pullRequestInfo.targetBranch} not found in major orgs list, cannot retrieve pull requests.\nPR: ${JSON.stringify(pullRequestInfo, null, 2)}`));
return [];
}
}
const childBranchesNames = recursiveGetChildBranches(targetBranchToUse, majorOrgs);
const pullRequests = await gitProvider.listPullRequestsInBranchSinceLastMerge(sourceBranchToUse, targetBranchToUse, [...childBranchesNames]);
pullRequests.reverse(); // Oldest PR first
// Add current PR if not already present
if (!pullRequests.some(pr => pr.idStr === pullRequestInfo.idStr)) {
pullRequests.push(pullRequestInfo);
}
_cachedPullRequests = pullRequests;
return pullRequests;
}
function recursiveGetChildBranches(branchName, majorOrgs, collected = new Set()) {
const directChildren = majorOrgs
.filter((o) => o.mergeTargets.includes(branchName))
.map((o) => o.branchName);
for (const child of directChildren) {
if (!collected.has(child)) {
collected.add(child);
recursiveGetChildBranches(child, majorOrgs, collected);
}
}
return collected;
}
//# sourceMappingURL=pullRequestUtils.js.map