UNPKG

@flxbl-io/sfp

Version:

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

212 lines 16.9 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; }; Object.defineProperty(exports, "__esModule", { value: true }); const path = require("path"); const fs = __importStar(require("fs-extra")); const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger")); const glob_1 = require("glob"); const AdmZip = require("adm-zip"); const semver = require("semver"); const tar = require("tar"); class ArtifactFetcher { /** * Decider for which artifact retrieval method to use * Returns empty array if no artifacts are found * @param artifactDirectory * @param sfdx_package */ static fetchArtifacts(artifactDirectory, sfdx_package, logger) { let result = []; if (!fs.existsSync(artifactDirectory)) { throw new Error(`Artifact directory ${path.resolve(artifactDirectory)} does not exist`); } let artifacts = this.findArtifacts(artifactDirectory, sfdx_package); sfp_logger_1.default.log(`Artifacts: ${JSON.stringify(artifacts)}`, sfp_logger_1.LoggerLevel.TRACE, logger); for (let artifact of artifacts) { let artifactFilePaths; if (path.extname(artifact) === '.zip') { artifactFilePaths = ArtifactFetcher.fetchArtifactFilePathsFromZipFile(artifact); } else if (path.extname(artifact) === '.tgz') { artifactFilePaths = ArtifactFetcher.fetchArtifactFilePathsFromTarball(artifact); } else { throw new Error(`Unhandled artifact format ${artifact}, neither tar or zip file`); } result.push(artifactFilePaths); } return result; } /** * Helper method for retrieving the ArtifactFilePaths of an artifact folder * @param packageMetadataFilePath */ static fetchArtifactFilePathsFromFolder(packageMetadataFilePath) { let sourceDirectory = path.join(path.dirname(packageMetadataFilePath), `source`); let changelogFilePath = path.join(path.dirname(packageMetadataFilePath), `changelog.json`); let artifactFilePaths = { packageMetadataFilePath: packageMetadataFilePath, sourceDirectoryPath: sourceDirectory, changelogFilePath: changelogFilePath, }; ArtifactFetcher.existsArtifactFilepaths(artifactFilePaths); return artifactFilePaths; } /** * Helper method for retrieving ArtifactFilePaths of an artifact zip * @param artifact */ static fetchArtifactFilePathsFromZipFile(artifact) { let unzippedArtifactsDirectory = `.sfpowerscripts/unzippedArtifacts/${this.makefolderid(8)}`; fs.mkdirpSync(unzippedArtifactsDirectory); let zip = new AdmZip(artifact); // Overwrite existing files zip.extractAllTo(unzippedArtifactsDirectory, true); let artifactName = path.basename(artifact).match(/.*sfpowerscripts_artifact/)?.[0]; if (artifactName == null) { throw new Error(`Failed to fetch artifact file paths for ${artifact}`); } let packageMetadataFilePath = path.join(unzippedArtifactsDirectory, artifactName, 'artifact_metadata.json'); let sourceDirectory = path.join(unzippedArtifactsDirectory, artifactName, `source`); let changelogFilePath = path.join(unzippedArtifactsDirectory, artifactName, `changelog.json`); let artifactFilePaths = { packageMetadataFilePath: packageMetadataFilePath, sourceDirectoryPath: sourceDirectory, changelogFilePath: changelogFilePath, }; ArtifactFetcher.existsArtifactFilepaths(artifactFilePaths); return artifactFilePaths; } /** * Helper method for retrieving ArtifactFilePaths of a tarball * @param artifact */ static fetchArtifactFilePathsFromTarball(artifact) { let unzippedArtifactsDirectory = `.sfpowerscripts/unzippedArtifacts/${this.makefolderid(8)}`; fs.mkdirpSync(unzippedArtifactsDirectory); tar.x({ file: artifact, cwd: unzippedArtifactsDirectory, sync: true, }); let packageMetadataFilePath = path.join(unzippedArtifactsDirectory, 'package', 'artifact_metadata.json'); let sourceDirectory = path.join(unzippedArtifactsDirectory, 'package', `source`); let changelogFilePath = path.join(unzippedArtifactsDirectory, 'package', `changelog.json`); let artifactFilePaths = { packageMetadataFilePath: packageMetadataFilePath, sourceDirectoryPath: sourceDirectory, changelogFilePath: changelogFilePath, }; ArtifactFetcher.existsArtifactFilepaths(artifactFilePaths); return artifactFilePaths; } /** * Find zip and tarball artifacts * Artifact format/s: * sfpowerscripts_artifact_<version>.zip, * [sfdx_package]_sfpowerscripts_artifact_[version].zip, * [sfdx_package]_sfpowerscripts_artifact_[version].tgz */ static findArtifacts(artifactDirectory, sfdx_package) { let pattern; if (sfdx_package) { pattern = `**/*${sfdx_package}_sfpowerscripts_artifact*.@(zip|tgz)`; } else { pattern = `**/*sfpowerscripts_artifact*.@(zip|tgz)`; } let artifacts = (0, glob_1.globSync)(pattern, { cwd: artifactDirectory, absolute: true, }); if (sfdx_package && artifacts.length > 1) { sfp_logger_1.default.log(`Found more than one artifact for ${sfdx_package}`, sfp_logger_1.LoggerLevel.INFO); let latestArtifact = ArtifactFetcher.getLatestArtifact(artifacts); sfp_logger_1.default.log(`Using latest artifact ${latestArtifact}`, sfp_logger_1.LoggerLevel.INFO); return [latestArtifact]; } else return artifacts; } /** * Get the artifact with the latest semantic version * @param artifacts */ static getLatestArtifact(artifacts) { // Consider zip & tarball artifacts only artifacts = artifacts.filter((artifact) => { let ext = path.extname(artifact); return ext === '.zip' || ext === '.tgz'; }); let pattern = new RegExp('(?:^.*)(?:_sfpowerscripts_artifact[_-])(?<version>.*)(?:\\.zip|\\.tgz)$'); let versions = artifacts.map((artifact) => { let match = path.basename(artifact).match(pattern); let version = match?.groups.version; if (version) return version; else throw new Error('Corrupted artifact detected with no version number'); }); // Pick artifact with latest semantic version let sortedVersions = semver.sort(versions); let latestVersion = sortedVersions.pop(); return artifacts.find((artifact) => artifact.includes(latestVersion)); } /** * Verify that artifact filepaths exist on the file system * @param artifactFilePaths */ static existsArtifactFilepaths(artifactFilePaths) { Object.values(artifactFilePaths).forEach((filepath) => { if (!fs.existsSync(filepath)) throw new Error(`Artifact filepath ${filepath} does not exist`); }); } /** * Decider for task outcome if the artifact cannot be found * @param artifacts_filepaths * @param isToSkipOnMissingArtifact */ static missingArtifactDecider(artifacts, isToSkipOnMissingArtifact) { if (artifacts.length === 0 && !isToSkipOnMissingArtifact) { throw new Error(`Artifact not found, Please check the inputs`); } else if (artifacts.length === 0 && isToSkipOnMissingArtifact) { sfp_logger_1.default.log(`Skipping task as artifact is missing, and 'Skip If no artifact is found' ${isToSkipOnMissingArtifact}`); return true; } } static makefolderid(length) { let result = ''; let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let charactersLength = characters.length; for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } } exports.default = ArtifactFetcher; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXJ0aWZhY3RGZXRjaGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvcmUvYXJ0aWZhY3RzL0FydGlmYWN0RmV0Y2hlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsNkJBQThCO0FBQzlCLDZDQUErQjtBQUMvQixtRUFBc0U7QUFDdEUsK0JBQWdDO0FBQ2hDLGtDQUFtQztBQUNuQyxpQ0FBa0M7QUFDbEMsMkJBQTRCO0FBRTVCLE1BQXFCLGVBQWU7SUFDaEM7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsY0FBYyxDQUFDLGlCQUF5QixFQUFFLFlBQXFCLEVBQUUsTUFBZTtRQUMxRixJQUFJLE1BQU0sR0FBZSxFQUFFLENBQUM7UUFFNUIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsaUJBQWlCLENBQUMsRUFBRSxDQUFDO1lBQ3BDLE1BQU0sSUFBSSxLQUFLLENBQUMsc0JBQXNCLElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUM1RixDQUFDO1FBRUQsSUFBSSxTQUFTLEdBQWEsSUFBSSxDQUFDLGFBQWEsQ0FBQyxpQkFBaUIsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUU5RSxvQkFBUyxDQUFDLEdBQUcsQ0FBQyxjQUFjLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLEVBQUUsRUFBRSx3QkFBVyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVwRixLQUFLLElBQUksUUFBUSxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQzdCLElBQUksaUJBQTJCLENBQUM7WUFDaEMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLE1BQU0sRUFBRSxDQUFDO2dCQUNwQyxpQkFBaUIsR0FBRyxlQUFlLENBQUMsaUNBQWlDLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDcEYsQ0FBQztpQkFBTSxJQUFJ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