UNPKG

@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
"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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