@flxbl-io/sfp
Version:
sfp is a CLI tool to help you manage your Salesforce projects in an artifact centric model
170 lines • 16.1 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ArtifactFetcher_1 = __importDefault(require("../../core/artifacts/ArtifactFetcher"));
const ChangelogMarkdownGenerator_1 = __importDefault(require("./ChangelogMarkdownGenerator"));
const ReleaseChangelogUpdater_1 = __importDefault(require("./ReleaseChangelogUpdater"));
const fs = __importStar(require("fs-extra"));
const path = require("path");
const marked_1 = require("marked");
const TerminalRenderer = require('marked-terminal');
const retry = require('async-retry');
const simple_git_1 = require("simple-git");
const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger"));
const SfpPackageBuilder_1 = __importDefault(require("../../core/package/SfpPackageBuilder"));
const Git_1 = __importDefault(require("../../core/git/Git"));
const FileOutputHandler_1 = __importDefault(require("../../outputs/FileOutputHandler"));
marked_1.marked.setOptions({
// Define custom renderer
renderer: new TerminalRenderer(),
});
class ChangelogImpl {
constructor(logger, artifactDir, releaseName, workItemFilters, limit, workItemUrl, showAllArtifacts, directory, forcePush, branch, nopush, isDryRun, releaseConfigName, org) {
this.logger = logger;
this.artifactDir = artifactDir;
this.releaseName = releaseName;
this.workItemFilters = workItemFilters;
this.limit = limit;
this.workItemUrl = workItemUrl;
this.showAllArtifacts = showAllArtifacts;
this.directory = directory;
this.forcePush = forcePush;
this.branch = branch;
this.nopush = nopush;
this.isDryRun = isDryRun;
this.releaseConfigName = releaseConfigName;
this.org = org;
this.org = org?.toLowerCase();
}
async exec() {
return retry(async (bail, retryNum) => {
try {
return await this.execHandler();
}
catch (err) {
if (err instanceof simple_git_1.GitError) {
if (!err.message.includes('failed to push some refs')) {
// Do not retry for Git errors that are not related to push
bail(err);
}
else {
sfp_logger_1.default.log('Failed to push changelog', sfp_logger_1.LoggerLevel.WARN, this.logger);
sfp_logger_1.default.log(`Retrying...(${retryNum})`, sfp_logger_1.LoggerLevel.WARN, this.logger);
throw err;
}
}
else {
// Do not retry for non-Git errors
bail(err);
}
}
}, {
retries: 10,
minTimeout: 5,
randomize: true,
});
}
async execHandler() {
let git;
try {
let artifactFilePaths = ArtifactFetcher_1.default.fetchArtifacts(this.artifactDir);
if (artifactFilePaths.length === 0) {
throw new Error(`No artifacts found at ${path.resolve(process.cwd(), this.artifactDir)}`);
}
let artifactsToSfpPackage = {};
let packagesToChangelogFilePaths = {};
let artifactSourceBranch;
for (let artifactFilepath of artifactFilePaths) {
let sfpPackage = await SfpPackageBuilder_1.default.buildPackageFromArtifact(artifactFilepath, new sfp_logger_1.ConsoleLogger());
artifactsToSfpPackage[sfpPackage.packageName] = sfpPackage;
packagesToChangelogFilePaths[sfpPackage.packageName] = sfpPackage.changelogFilePath;
if (artifactSourceBranch == null) {
if (sfpPackage.branch) {
artifactSourceBranch = sfpPackage.branch;
}
else {
console.log(`${sfpPackage.packageName} artifact is missing branch information`);
console.log(`This will cause an error in the future. Re-create the artifact using the latest version of sfp to maintain compatibility.`);
}
}
}
if (!artifactSourceBranch)
throw new Error('Atleast one artifact must carry branch information');
//duplicate repo
let git = await Git_1.default.initiateRepoAtTempLocation(this.logger, null, this.branch);
sfp_logger_1.default.log(`Checking out branch ${this.branch}`, sfp_logger_1.LoggerLevel.INFO, this.logger);
let pathToChangelogDirectory = this.createDirectory(this.directory, git.getRepositoryPath());
let releaseChangelog;
if (fs.existsSync(path.join(pathToChangelogDirectory, `releasechangelog.json`))) {
releaseChangelog = JSON.parse(fs.readFileSync(path.join(pathToChangelogDirectory, `releasechangelog.json`), 'utf8'));
}
else {
releaseChangelog = {
orgs: [],
releases: [],
};
}
sfp_logger_1.default.log('Generating changelog...', sfp_logger_1.LoggerLevel.INFO, this.logger);
releaseChangelog = new ReleaseChangelogUpdater_1.default(releaseChangelog, this.releaseName, artifactsToSfpPackage, packagesToChangelogFilePaths, this.workItemFilters, this.org).update();
// Preview changelog in console
sfp_logger_1.default.log((0, marked_1.marked)(new ChangelogMarkdownGenerator_1.default(releaseChangelog, this.workItemUrl, 1, false).generate()), sfp_logger_1.LoggerLevel.INFO, this.logger);
if (this.isDryRun) {
const outputHandler = FileOutputHandler_1.default.getInstance();
if (this.releaseConfigName) {
outputHandler.appendOutput('release-changelog.md', `# ReleaseConfig: ${this.releaseConfigName}`);
}
outputHandler.appendOutput('release-changelog.md', new ChangelogMarkdownGenerator_1.default(releaseChangelog, this.workItemUrl, 1, false, false).generate());
}
fs.writeFileSync(path.join(pathToChangelogDirectory, `releasechangelog.json`), JSON.stringify(releaseChangelog, null, 4));
let payload = new ChangelogMarkdownGenerator_1.default(releaseChangelog, this.workItemUrl, this.limit, this.showAllArtifacts).generate();
fs.writeFileSync(path.join(pathToChangelogDirectory, `Release-Changelog.md`), payload);
if (!this.isDryRun) {
await git.commitFile([path.join(pathToChangelogDirectory, `releasechangelog.json`), path.join(pathToChangelogDirectory, `Release-Changelog.md`)]);
if (!this.nopush)
await git.pushToRemote(this.branch, this.forcePush);
}
sfp_logger_1.default.log(`Successfully generated changelog`, sfp_logger_1.LoggerLevel.INFO, this.logger);
return releaseChangelog;
}
finally {
if (git)
git.deleteTempoRepoIfAny();
}
}
createDirectory(directory, repoDir) {
if (this.directory) {
if (!fs.pathExistsSync(path.join(repoDir, directory))) {
fs.mkdirpSync(path.join(repoDir, directory));
}
repoDir = path.join(repoDir, this.directory);
}
return repoDir;
}
}
exports.default = ChangelogImpl;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2hhbmdlbG9nSW1wbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9pbXBsL2NoYW5nZWxvZy9DaGFuZ2Vsb2dJbXBsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwyRkFBaUY7QUFFakYsOEZBQXNFO0FBQ3RFLHdGQUFnRTtBQUNoRSw2Q0FBK0I7QUFDL0IsNkJBQThCO0FBQzlCLG1DQUFnQztBQUNoQyxNQUFNLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0FBQ3BELE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUNyQywyQ0FBc0M7QUFFdEMsbUVBQXFGO0FBQ3JGLDZGQUFxRTtBQUNyRSw2REFBcUM7QUFDckMsd0ZBQWdFO0FBSWhFLGVBQU0sQ0FBQyxVQUFVLENBQUM7SUFDZCx5QkFBeUI7SUFDekIsUUFBUSxFQUFFLElBQUksZ0JBQWdCLEVBQUU7Q0FDbkMsQ0FBQyxDQUFDO0FBRUgsTUFBcUIsYUFBYTtJQUM5QixZQUNZLE1BQWEsRUFDYixXQUFtQixFQUNuQixXQUFtQixFQUNuQixlQUF5QixFQUN6QixLQUFhLEVBQ2IsV0FBbUIsRUFDbkIsZ0JBQXlCLEVBQ3pCLFNBQWdCLEVBQ2hCLFNBQWtCLEVBQ2xCLE1BQWMsRUFDZCxNQUFjLEVBQ2QsUUFBaUIsRUFDakIsaUJBQXdCLEVBQ3hCLEdBQVk7UUFiWixXQUFNLEdBQU4sTUFBTSxDQUFPO1FBQ2IsZ0JBQVcsR0FBWCxXQUFXLENBQVE7UUFDbkIsZ0JBQVcsR0FBWCxXQUFXLENBQVE7UUFDbkIsb0JBQWUsR0FBZixlQUFlLENBQVU7UUFDekIsVUFBSyxHQUFMLEtBQUssQ0FBUTtRQUNiLGdCQUFXLEdBQVgsV0FBVyxDQUFRO1FBQ25CLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBUztRQUN6QixjQUFTLEdBQVQsU0FBUyxDQUFPO1FBQ2hCLGNBQVMsR0FB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