UNPKG

@flxbl-io/sfp

Version:

sfp is a CLI tool to help you manage your Salesforce projects in an artifact centric model

363 lines 36.3 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 }; }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); const SfpCommand_1 = __importDefault(require("../SfpCommand")); const core_1 = require("@salesforce/core"); const fs = __importStar(require("fs-extra")); const path = require("path"); const ArtifactFetcher_1 = __importDefault(require("../core/artifacts/ArtifactFetcher")); const SFPStatsSender_1 = __importDefault(require("../core/stats/SFPStatsSender")); const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger")); const GetFormattedTime_1 = __importDefault(require("../core/utils/GetFormattedTime")); const DefaultShell_1 = __importDefault(require("../core/utils/DefaultShell")); const SfpPackage_1 = require("../core/package/SfpPackage"); const sfp_logger_2 = require("@flxbl-io/sfp-logger"); const SfpPackageBuilder_1 = __importDefault(require("../core/package/SfpPackageBuilder")); const Git_1 = __importDefault(require("../core/git/Git")); const GroupConsoleLogs_1 = __importDefault(require("../ui/GroupConsoleLogs")); const PackageVersionLister_1 = __importDefault(require("../core/package/version/PackageVersionLister")); const SFPOrg_1 = __importDefault(require("../core/org/SFPOrg")); const ExecuteCommand_1 = __importDefault(require("@flxbl-io/sfdx-process-wrapper/lib/commandExecutor/ExecuteCommand")); const sfp_logger_3 = require("@flxbl-io/sfp-logger"); const GitTags_1 = __importDefault(require("../core/git/GitTags")); const sfdxflags_1 = require("../flags/sfdxflags"); const core_2 = require("@oclif/core"); core_1.Messages.importMessagesDirectory(__dirname); const messages = core_1.Messages.loadMessages('@flxbl-io/sfp', 'publish'); class Publish extends SfpCommand_1.default { async execute() { let nPublishedArtifacts = 0; let failedArtifacts = []; let executionStartTime = Date.now(); let succesfullyPublishedPackageNamesForTagging = []; let npmrcFilesToCleanup = []; this.git = await Git_1.default.initiateRepo(new sfp_logger_2.ConsoleLogger()); try { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_HEADER)(`command: ${(0, sfp_logger_1.COLOR_KEY_MESSAGE)(`publish`)}`)); sfp_logger_1.default.log((0, sfp_logger_1.COLOR_HEADER)(`target: ${this.flags.scriptpath ? this.flags.scriptpath : 'NPM'}`)); sfp_logger_1.default.log((0, sfp_logger_1.COLOR_HEADER)(`Publish promoted artifacts only: ${this.flags.publishpromotedonly ? true : false}`)); sfp_logger_1.default.printHeaderLine('', sfp_logger_1.COLOR_HEADER, sfp_logger_3.LoggerLevel.INFO); let packageVersionList; if (this.flags.publishpromotedonly) { let hubOrg = await SFPOrg_1.default.create({ aliasOrUsername: this.flags.devhubalias }); let packageVersionLister = new PackageVersionLister_1.default(hubOrg); packageVersionList = await packageVersionLister.listAllReleasedVersions(process.cwd()); } let artifacts = ArtifactFetcher_1.default.findArtifacts(this.flags.artifactdir); let artifactFilePaths = ArtifactFetcher_1.default.fetchArtifacts(this.flags.artifactdir); // Pattern captures two named groups, the "package" name and "version" number let pattern = new RegExp('(?<package>^.*)(?:_sfpowerscripts_artifact_)(?<version>.*)(?:\\.zip)'); for (let artifact of artifacts) { let packageName; let packageVersionNumber; let match = path.basename(artifact).match(pattern); if (match !== null) { packageName = match.groups.package; packageVersionNumber = match.groups.version; } else { // artifact filename doesn't match pattern continue; } let sfpPackage = await this.getPackageInfo(artifactFilePaths, packageName, packageVersionNumber); let packageType = sfpPackage.package_type; let packageVersionId = sfpPackage.package_version_id; if (this.flags.publishpromotedonly && packageType === SfpPackage_1.PackageType.Unlocked) { let isReleased = this.isPackageVersionIdReleased(packageVersionList, packageVersionId); if (!isReleased) { failedArtifacts.push(`${packageName} v${packageVersionNumber}`); sfp_logger_1.default.log(`Skipping ${packageName} Version ${packageVersionNumber}. Package Version Id ${packageVersionId} has not been promoted.`); process.exitCode = 1; continue; } } try { if (this.flags.npm) { await this.publishUsingNpm(sfpPackage, packageVersionNumber, npmrcFilesToCleanup); } else { await this.publishUsingScript(packageName, packageVersionNumber, artifact); } succesfullyPublishedPackageNamesForTagging.push({ name: packageName, version: packageVersionNumber.replace('-', '.'), type: packageType, tag: `${packageName}_v${packageVersionNumber.replace('-', '.')}`, commitId: sfpPackage.sourceVersion }); nPublishedArtifacts++; } catch (err) { failedArtifacts.push(`${packageName} v${packageVersionNumber}`); sfp_logger_1.default.log(err.message); process.exitCode = 1; } } if (this.flags.gittag) { await this.createGitTags(succesfullyPublishedPackageNamesForTagging); await this.pushGitTags(succesfullyPublishedPackageNamesForTagging); } if (this.flags.gittagage && this.flags.gittaglimit) { await this.deleteGitTagsOlderThan(succesfullyPublishedPackageNamesForTagging, this.flags.gittagage, this.flags.gittaglimit); } else if (this.flags.gittagage) { await this.deleteGitTagsOlderThan(succesfullyPublishedPackageNamesForTagging, this.flags.gittagage); } else if (this.flags.gittaglimit) { await this.deleteExcessGitTags(succesfullyPublishedPackageNamesForTagging, this.flags.gittaglimit); } } catch (err) { sfp_logger_1.default.log(err.message); // Fail the task when an error occurs process.exitCode = 1; } finally { if (npmrcFilesToCleanup.length > 0) { npmrcFilesToCleanup.forEach((npmrcFile) => { fs.unlinkSync(npmrcFile); }); } let totalElapsedTime = Date.now() - executionStartTime; sfp_logger_1.default.printHeaderLine('', sfp_logger_1.COLOR_HEADER, sfp_logger_3.LoggerLevel.INFO); sfp_logger_1.default.log((0, sfp_logger_1.COLOR_SUCCESS)(`${nPublishedArtifacts} artifacts published in ${(0, sfp_logger_1.COLOR_TIME)((0, GetFormattedTime_1.default)(totalElapsedTime))} with {${(0, sfp_logger_1.COLOR_ERROR)(failedArtifacts.length)}} errors`)); if (failedArtifacts.length > 0) { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_ERROR)(`Packages Failed to Publish`, failedArtifacts)); } sfp_logger_1.default.printHeaderLine('', sfp_logger_1.COLOR_HEADER, sfp_logger_3.LoggerLevel.INFO); let tags = { publish_promoted_only: this.flags.publishpromotedonly ? 'true' : 'false', }; if (this.flags.tag != null) { tags['tag'] = this.flags.tag; } SFPStatsSender_1.default.logGauge('publish.duration', totalElapsedTime, tags); SFPStatsSender_1.default.logGauge('publish.succeeded', nPublishedArtifacts, tags); if (failedArtifacts.length > 0) { SFPStatsSender_1.default.logGauge('publish.failed', failedArtifacts.length, tags); } } } async publishUsingNpm(sfpPackage, packageVersionNumber, npmrcFilesToCleanup) { let publishGroupSection = new GroupConsoleLogs_1.default(`Publishing ${sfpPackage.packageName}`).begin(); let artifactRootDirectory = path.dirname(sfpPackage.sourceDir); // NPM does not accept packages with uppercase characters let name = sfpPackage.packageName.toLowerCase() + '_sfpowerscripts_artifact'; //Check whether the user has already passed in @ if (this.flags.scope) { let scope = this.flags.scope.replace(/@/g, '').toLowerCase(); name = `@${scope}/` + name; } let packageJson = { name: name, version: packageVersionNumber, repository: sfpPackage.repository_url, }; fs.writeFileSync(path.join(artifactRootDirectory, 'package.json'), JSON.stringify(packageJson, null, 4)); if (this.flags.npmrcpath) { fs.copyFileSync(this.flags.npmrcpath, path.join(artifactRootDirectory, '.npmrc')); npmrcFilesToCleanup.push(path.join(artifactRootDirectory, '.npmrc')); } let cmd = `npm publish`; //Do a tag based on the branch if (sfpPackage.branch) { cmd += ` --tag ${sfpPackage.branch}`; sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Publishing ${sfpPackage.packageName} Version ${packageVersionNumber} with tag ${sfpPackage.branch}...`)); } let npmPublishExecutor = new ExecuteCommand_1.default(new sfp_logger_2.ConsoleLogger(), sfp_logger_3.LoggerLevel.INFO, true); await npmPublishExecutor.execCommand(cmd, artifactRootDirectory); publishGroupSection.end(); } async publishUsingScript(packageName, packageVersionNumber, artifact) { let publishGroupSection = new GroupConsoleLogs_1.default(`Publishing ${packageName}`).begin(); let cmd; if (process.platform !== 'win32') { cmd = `${(0, DefaultShell_1.default)()} -e ${this.flags.scriptpath} ${packageName} ${packageVersionNumber} ${artifact} ${this.flags.publishpromotedonly ? true : false}`; } else { cmd = `cmd.exe /c ${this.flags.scriptpath} ${packageName} ${packageVersionNumber} ${artifact} ${this.flags.publishpromotedonly ? true : false}`; } sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Publishing ${packageName} Version ${packageVersionNumber}...`)); let scriptExecutor = new ExecuteCommand_1.default(new sfp_logger_2.ConsoleLogger(), sfp_logger_3.LoggerLevel.INFO, true); await scriptExecutor.execCommand(cmd, process.cwd()); publishGroupSection.end(); } validateFlags() { if (this.flags.scriptpath === undefined && this.flags.npm === undefined) throw new Error('Either --scriptpath or --npm flag must be provided'); if (this.flags.scriptpath && !fs.existsSync(this.flags.scriptpath)) throw new Error(`Script path ${this.flags.scriptpath} does not exist`); if (this.flags.npm && !this.flags.scope) throw new Error('--scope parameter is required for NPM'); } async pushGitTags(sucessfullyPublishedPackages) { if (this.flags.pushgittag) { let tagsForPushing = []; for (let succesfullyPublishedPackage of sucessfullyPublishedPackages) { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Pushing Git Tags to Repo ${succesfullyPublishedPackage.tag}`)); tagsForPushing.push(succesfullyPublishedPackage.tag); } await this.git.pushTags(tagsForPushing); } } async createGitTags(sucessfullyPublishedPackages) { for (let sucessFullyPublishedPackage of sucessfullyPublishedPackages) { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Creating Git Tags in Repo ${sucessFullyPublishedPackage.tag}`)); await this.git.addAnnotatedTag(sucessFullyPublishedPackage.tag, `${sucessFullyPublishedPackage.name} ${sucessFullyPublishedPackage.type} Package ${sucessFullyPublishedPackage.version}`, sucessFullyPublishedPackage.commitId); } } //Exclude the latest git tag up to a specified number of tags, and then deletes the excess tags that exceed that limit. async deleteExcessGitTags(tags, limit) { //const pkgs = ProjectConfig.getAllPackages(this.git.getRepositoryPath()); const tagsToDelete = []; await Promise.all(tags.map(async (tag) => { const gitTags = new GitTags_1.default(this.git, tag.name); const tags = await gitTags.limitTags(limit); tagsToDelete.push(...tags); })); if (tagsToDelete.length > 0) { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)('Removing the following Git tag(s):')); for (let tag of tagsToDelete) { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(tag)); } await this.git.deleteTags(tagsToDelete); } } //Deletes Git tags that are older than a specified number of days. async deleteGitTagsOlderThan(tags, daysToKeep, limit) { const tagsToDelete = []; await Promise.all(tags.map(async (tag) => { const gitTags = new GitTags_1.default(this.git, tag.name); const tags = await gitTags.filteredOldTags(daysToKeep, limit); tagsToDelete.push(...tags); })); if (tagsToDelete.length > 0) { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)('Removing the following Git tag(s):')); for (let tag of tagsToDelete) { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(tag)); } await this.git.deleteTags(tagsToDelete); } } isPackageVersionIdReleased(packageVersionList, packageVersionId) { let packageVersion = packageVersionList.find((pkg) => { return pkg.SubscriberPackageVersionId === packageVersionId; }); if (packageVersion) return true; else return false; } /** * Get sourceDirectory and packageMetadata of artifact with package name and version * @param artifacts * @param packageName * @param packageVersionNumber */ async getPackageInfo(artifacts, packageName, packageVersionNumber) { for (let artifact of artifacts) { let sfpPackage = await SfpPackageBuilder_1.default.buildPackageFromArtifact(artifact, new sfp_logger_2.ConsoleLogger()); if (sfpPackage.packageName === packageName && sfpPackage.versionNumber === packageVersionNumber.replace('-', '.')) { return sfpPackage; } } throw new Error(`Unable to find artifact metadata for ${packageName} Version ${packageVersionNumber.replace('-', '.')}`); } } _a = Publish; Publish.description = messages.getMessage('commandDescription'); Publish.aliases = ['orchestrator:publish']; Publish.examples = [ `$ sfp publish --npm`, ]; Publish.requiresUsername = false; Publish.requiresDevhubUsername = false; Publish.flags = { artifactdir: core_2.Flags.directory({ required: true, char: 'd', description: messages.getMessage('artifactDirectoryFlagDescription'), default: 'artifacts', }), publishpromotedonly: core_2.Flags.boolean({ char: 'p', description: messages.getMessage('publishPromotedOnlyFlagDescription'), dependsOn: ['devhubalias'], }), 'devhubalias': sfdxflags_1.optionalDevHubFlag, scriptpath: core_2.Flags.file({ char: 'f', description: messages.getMessage('scriptPathFlagDescription'), }), tag: core_2.Flags.string({ char: 't', description: messages.getMessage('tagFlagDescription'), }), gittag: core_2.Flags.boolean({ description: messages.getMessage('gitTagFlagDescription'), default: false, }), gittaglimit: core_2.Flags.integer({ description: messages.getMessage('gitTagLimitFlagDescription'), }), gittagage: core_2.Flags.integer({ description: messages.getMessage('gitTagAgeFlagDescription'), }), pushgittag: core_2.Flags.boolean({ description: messages.getMessage('gitPushTagFlagDescription'), default: false, }), npm: core_2.Flags.boolean({ description: messages.getMessage('npmFlagDescription'), exclusive: ['scriptpath'], }), scope: core_2.Flags.string({ description: messages.getMessage('scopeFlagDescription'), dependsOn: ['npm'], parse: async (scope) => scope.replace(/@/g, '').toLowerCase(), }), npmtag: core_2.Flags.string({ description: messages.getMessage('npmTagFlagDescription'), dependsOn: ['npm'], required: false, deprecated: { message: '--npmtag is deprecated, sfp will automatically tag the artifact with the branch name', }, }), npmrcpath: core_2.Flags.file({ description: messages.getMessage('npmrcPathFlagDescription'), dependsOn: ['npm'], required: false, }), logsgroupsymbol: sfdxflags_1.logsgroupsymbol, loglevel: sfdxflags_1.loglevel }; exports.default = Publish; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGlzaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb21tYW5kcy9wdWJsaXNoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsK0RBQXVDO0FBQ3ZDLDJDQUE0QztBQUM1Qyw2Q0FBK0I7QUFDL0IsNkJBQThCO0FBQzlCLHdGQUE4RTtBQUM5RSxrRkFBMEQ7QUFDMUQsbUVBTThCO0FBQzlCLHNGQUE4RDtBQUM5RCw4RUFBc0Q7QUFDdEQsMkRBQXFFO0FBQ3JFLHFEQUFxRDtBQUNyRCwwRkFBa0U7QUFDbEUsMERBQWtDO0FBQ2xDLDhFQUFzRDtBQUN0RCx3R0FBZ0Y7QUFDaEYsZ0VBQXdDO0FBQ3hDLHVIQUErRjtBQUMvRixxREFBbUQ7QUFDbkQsa0VBQTBDO0FBQzFDLGtEQUF1RztBQUN2RyxzQ0FBb0M7QUFFcEMsZUFBUSxDQUFDLHVCQUF1QixDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQzVDLE1BQU0sUUFBUSxHQUFHLGVBQVEsQ0FBQyxZQUFZLENBQUMsZUFBZSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBRW5FLE1BQXFCLE9BQVEsU0FBUSxvQkFBVTtJQTBFcEMsS0FBSyxDQUFDLE9BQU87UUFDaEIsSUFBSSxtQkFBbUIsR0FBVyxDQUFDLENBQUM7UUFDcEMsSUFBSSxlQUFlLEdBQWEsRUFBRSxDQUFDO1FBRW5DLElBQUksa0JBQWtCLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRXBDLElBQUksMENBQTBDLEdBTXhDLEVBQUUsQ0FBQztRQUVULElBQUksbUJBQW1CLEdBQWEsRUFBRSxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxHQUFHLEdBQUcsTUFBTSxhQUFHLENBQUMsWUFBWSxDQUFDLElBQUksMEJBQWEsRUFBRSxDQUFDLENBQUM7UUFFdkQsSUFBSSxDQUFDO1lBQ0Qsb0JBQVMsQ0FBQyxHQUFHLENBQUMsSUFBQSx5QkFBWSxFQUFDLFlBQVksSUFBQSw4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