UNPKG

@flxbl-io/sfp

Version:

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

339 lines 34.7 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 bottleneck_1 = __importDefault(require("bottleneck")); const PoolBaseImpl_1 = require("./PoolBaseImpl"); const ScratchOrgInfoFetcher_1 = __importDefault(require("./services/fetchers/ScratchOrgInfoFetcher")); const ScratchOrgLimitsFetcher_1 = __importDefault(require("./services/fetchers/ScratchOrgLimitsFetcher")); const ScratchOrgInfoAssigner_1 = __importDefault(require("./services/updaters/ScratchOrgInfoAssigner")); const rimraf = __importStar(require("rimraf")); const fs = __importStar(require("fs-extra")); const PoolError_1 = require("./PoolError"); const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger")); const neverthrow_1 = require("neverthrow"); const SFPStatsSender_1 = __importDefault(require("../../stats/SFPStatsSender")); const os_1 = require("os"); const OrgDetailsFetcher_1 = __importDefault(require("../../org/OrgDetailsFetcher")); const ScratchOrgOperator_1 = __importDefault(require("../ScratchOrgOperator")); const PoolFetchImpl_1 = __importDefault(require("./PoolFetchImpl")); const sfp_logger_2 = require("@flxbl-io/sfp-logger"); const sfp_logger_3 = require("@flxbl-io/sfp-logger"); const GetFormattedTime_1 = __importDefault(require("../../utils/GetFormattedTime")); const path_1 = __importDefault(require("path")); class PoolCreateImpl extends PoolBaseImpl_1.PoolBaseImpl { constructor(hubOrg, pool, poolScriptExecutor, logLevel) { super(hubOrg); this.pool = pool; this.poolScriptExecutor = poolScriptExecutor; this.logLevel = logLevel; this.totalAllocated = 0; this.limiter = new bottleneck_1.default({ maxConcurrent: this.pool.batchSize, }); this.scriptExecutorWrappedForBottleneck = this.limiter.wrap(this.scriptExecutor); } async onExec() { await this.hubOrg.refreshAuth(); const scriptExecPromises = []; //fetch current status limits this.limits = await new ScratchOrgLimitsFetcher_1.default(this.hubOrg).getScratchOrgLimits(); //Create Service classes this.scratchOrgInfoFetcher = new ScratchOrgInfoFetcher_1.default(this.hubOrg); this.scratchOrgInfoAssigner = new ScratchOrgInfoAssigner_1.default(this.hubOrg); //Create Operator this.scratchOrgOperator = new ScratchOrgOperator_1.default(this.hubOrg); // Setup Logging Directory rimraf.sync('script_exec_outputs'); fs.mkdirpSync('script_exec_outputs'); //Compute allocation try { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)('Computing Allocation..'), sfp_logger_1.LoggerLevel.INFO); try { this.totalToBeAllocated = await this.computeAllocation(); } catch (error) { return (0, neverthrow_1.err)({ success: 0, failed: 0, message: `Unable to access fields on ScratchOrgInfo, Please check the profile being used`, errorCode: PoolError_1.PoolErrorCodes.PrerequisiteMissing, }); } if (this.totalToBeAllocated === 0) { if (this.limits.ActiveScratchOrgs.Remaining > 0 || this.pool.snapshotPool) { return (0, neverthrow_1.err)({ success: 0, failed: 0, message: `The tag provided ${this.pool.tag} is currently at the maximum capacity , No scratch orgs will be allocated`, errorCode: PoolError_1.PoolErrorCodes.Max_Capacity, }); } else { return (0, neverthrow_1.err)({ success: 0, failed: 0, message: `There is no capacity to create a pool at this time, Please try again later`, errorCode: PoolError_1.PoolErrorCodes.No_Capacity, }); } } if (!this.pool.snapshotPool) { //Generate Scratch Orgs this.pool.scratchOrgs = await this.generateScratchOrgs(this.pool, this.scratchOrgOperator, this.scratchOrgInfoAssigner); } else { this.pool.scratchOrgs = await this.fetchScratchOrgsFromSnapshotPool(this.pool, this.scratchOrgInfoFetcher, this.scratchOrgInfoAssigner); } } catch (error) { return (0, neverthrow_1.err)({ success: 0, failed: this.pool.failedToCreate, message: `All requested scratch orgs failed to provision, Please check your code or config \n Failed with ${error.message}`, errorCode: PoolError_1.PoolErrorCodes.UnableToProvisionAny, }); } // Assign workers to executed scripts for (const scratchOrg of this.pool.scratchOrgs) { const result = this.scriptExecutorWrappedForBottleneck(scratchOrg, this.hubOrg.getUsername()); scriptExecPromises.push(result); } await Promise.all(scriptExecPromises); this.pool = await this.finalizeGeneratedScratchOrgs(this.pool, this.scratchOrgOperator, this.scratchOrgInfoFetcher); if (!this.pool.scratchOrgs || this.pool.scratchOrgs.length == 0) { return (0, neverthrow_1.err)({ success: 0, failed: this.pool.failedToCreate, message: `All requested scratch orgs failed to provision, Please check your code or config`, errorCode: PoolError_1.PoolErrorCodes.UnableToProvisionAny, }); } return (0, neverthrow_1.ok)(this.pool); } async computeAllocation() { //Compute current pool requirement const activeCount = await this.scratchOrgInfoFetcher.getCountOfActiveScratchOrgsByTag(this.pool.tag); return this.allocateScratchOrgsPerTag(this.limits.ActiveScratchOrgs.Remaining, activeCount, this.pool); } allocateScratchOrgsPerTag(remainingScratchOrgs, countOfActiveScratchOrgs, pool) { pool.current_allocation = countOfActiveScratchOrgs; pool.to_allocate = 0; pool.to_satisfy_max = pool.maxAllocation - pool.current_allocation > 0 ? pool.maxAllocation - pool.current_allocation : 0; if (pool.snapshotPool && pool.to_satisfy_max > 0) { pool.to_allocate = pool.to_satisfy_max; } else if (pool.to_satisfy_max > 0 && pool.to_satisfy_max <= remainingScratchOrgs) { pool.to_allocate = pool.to_satisfy_max; } else if (pool.to_satisfy_max > 0 && pool.to_satisfy_max > remainingScratchOrgs) { pool.to_allocate = remainingScratchOrgs; } sfp_logger_1.default.log(`${os_1.EOL}Current Allocation of ScratchOrgs in the pool ${this.pool.tag}: ` + pool.current_allocation, sfp_logger_1.LoggerLevel.INFO); sfp_logger_1.default.log('Remaining Active scratchOrgs in the org: ' + remainingScratchOrgs, sfp_logger_1.LoggerLevel.INFO); sfp_logger_1.default.log('ScratchOrgs to be allocated: ' + pool.to_allocate, sfp_logger_1.LoggerLevel.INFO); return pool.to_allocate; } async generateScratchOrgs(pool, scratchOrgOperator, scratchOrgInfoAssigner) { //Generate Scratch Orgs sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)('Generate Scratch Orgs..'), sfp_logger_1.LoggerLevel.INFO); const scratchOrgPromises = new Array(); const scratchOrgCreationLimiter = new bottleneck_1.default({ maxConcurrent: pool.batchSize, }); addDescriptionToScratchOrg(pool); const startTime = Date.now(); for (let i = 1; i <= pool.to_allocate; i++) { const scratchOrgPromise = scratchOrgCreationLimiter.schedule(() => scratchOrgOperator.create(`SO` + i, this.pool.configFilePath, this.pool.expiry, this.pool.waitTime, this.pool)); scratchOrgPromises.push(scratchOrgPromise); } sfp_logger_1.default.log(`Waiting for all scratch org request to complete, Please wait`); //Wait for all orgs to be created const scratchOrgCreationResults = await Promise.allSettled(scratchOrgPromises); //Only worry about scrath orgs that have suceeded const isFulfilled = (p) => p.status === 'fulfilled'; const isRejected = (p) => p.status === 'rejected'; let scratchOrgs = scratchOrgCreationResults.filter(isFulfilled).map((p) => p.value); const rejectedScratchOrgs = scratchOrgCreationResults.filter(isRejected).map((p) => p.reason); for (const reason of rejectedScratchOrgs) { if (reason.message.includes(`The client has timed out`)) { //Log how many we were able to create const elapsedTime = Date.now() - startTime; sfp_logger_1.default.log(`A scratch org creation was rejected due to saleforce not responding within the set wait time of ${pool.waitTime} mins \n` + `Time elasped so far ${(0, sfp_logger_1.COLOR_KEY_MESSAGE)((0, GetFormattedTime_1.default)(elapsedTime))},You might need to inrease the wait time further and rety `); } else sfp_logger_1.default.log(`A scratch org creation was rejected due to ${reason.message}`); } //Log how many we were able to create const elapsedTime = Date.now() - startTime; sfp_logger_1.default.log(`Created ${(0, sfp_logger_2.COLOR_SUCCESS)(scratchOrgs.length)} of ${pool.to_allocate} successfully with ${(0, sfp_logger_3.COLOR_ERROR)(rejectedScratchOrgs.length)} failures in ${(0, sfp_logger_1.COLOR_KEY_MESSAGE)((0, GetFormattedTime_1.default)(elapsedTime))}`); SFPStatsSender_1.default.logElapsedTime(`pool.scratchorg.creation.time`, elapsedTime, { pool: pool.tag }); if (scratchOrgs && scratchOrgs.length > 0) { //Splice scratchorgs that are having incorrect status of deleted , Why salesforce why?? let index = scratchOrgs.length; while (index--) { try { const orgDetails = await new OrgDetailsFetcher_1.default(scratchOrgs[index].username).getOrgDetails(); if (orgDetails.status === 'Deleted') { throw new Error(`Throwing away scratch org ${this.pool.scratchOrgs[index].alias} as it has a status of deleted`); } } catch (error) { scratchOrgs.splice(index, 1); } } scratchOrgs = await this.scratchOrgInfoFetcher.getScratchOrgRecordId(scratchOrgs); const scratchOrgInprogress = []; scratchOrgs.forEach((scratchOrg) => { scratchOrgInprogress.push({ Id: scratchOrg.recordId, Pooltag__c: this.pool.tag, Password__c: scratchOrg.password, SfdxAuthUrl__c: scratchOrg.sfdxAuthUrl, Allocation_status__c: 'In Progress', }); }); if (scratchOrgInprogress.length > 0) { //set pool tag await scratchOrgInfoAssigner.setScratchOrgInfo(scratchOrgInprogress); } return scratchOrgs; } else throw new Error(`No scratch orgs were sucesfully generated`); function addDescriptionToScratchOrg(pool) { const configClonePath = path_1.default.join('.sfpowerscripts', 'scratchorg-configs', `${makeFileId(8)}.json`); fs.mkdirpSync('.sfpowerscripts/scratchorg-configs'); fs.copyFileSync(pool.configFilePath, configClonePath); const scratchOrgDefn = fs.readJSONSync(configClonePath); if (!scratchOrgDefn.description) scratchOrgDefn.description = JSON.stringify({ requestedBy: 'sfp', pool: pool.tag, requestedAt: new Date().toISOString(), }); else scratchOrgDefn.description = scratchOrgDefn.description.concat(' ', JSON.stringify({ requestedBy: 'sfp', pool: pool.tag, requestedAt: new Date().toISOString(), })); fs.writeJSONSync(configClonePath, scratchOrgDefn, { spaces: 4 }); pool.configFilePath = configClonePath; } function makeFileId(length) { let result = ''; const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const charactersLength = characters.length; for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } } async fetchScratchOrgsFromSnapshotPool(pool, scratchOrgInfoFetcher, scratchOrgInfoAssigner) { //Generate Scratch Orgs sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Fetching Scratch Orgs from snapshot pool ${this.pool.snapshotPool}`), sfp_logger_1.LoggerLevel.INFO); let scratchOrgs = (await new PoolFetchImpl_1.default(this.hubOrg, this.pool.snapshotPool, false, true, undefined, undefined, undefined, true, this.pool.to_allocate).execute()); scratchOrgs = await scratchOrgInfoFetcher.getScratchOrgRecordId(scratchOrgs); const scratchOrgInprogress = []; if (scratchOrgs && scratchOrgs.length > 0) { scratchOrgs.forEach((scratchOrg) => { scratchOrgInprogress.push({ Id: scratchOrg.recordId, Pooltag__c: this.pool.tag, Password__c: scratchOrg.password, SfdxAuthUrl__c: scratchOrg.sfdxAuthUrl, Allocation_status__c: 'In Progress', }); }); if (scratchOrgInprogress.length > 0) { //set pool tag await scratchOrgInfoAssigner.setScratchOrgInfo(scratchOrgInprogress); } return scratchOrgs; } else { throw new Error('No scratch orgs were found to be fetched'); } } async finalizeGeneratedScratchOrgs(pool, scratchOrgOperator, scratchOrgInfoFetcher) { pool.failedToCreate = 0; for (let i = pool.scratchOrgs.length - 1; i >= 0; i--) { const scratchOrg = pool.scratchOrgs[i]; if (scratchOrg.isScriptExecuted) { continue; } sfp_logger_1.default.log(`Failed to execute scripts for ${scratchOrg.username} with alias ${scratchOrg.alias} due to ${scratchOrg.failureMessage}`, sfp_logger_1.LoggerLevel.ERROR); try { //Delete scratchorgs that failed to execute script const activeScratchOrgRecordId = await scratchOrgInfoFetcher.getActiveScratchOrgRecordIdGivenScratchOrg(scratchOrg.orgId); await scratchOrgOperator.delete([activeScratchOrgRecordId]); console.log(`Succesfully deleted scratchorg ${scratchOrg.username}`); } catch (error) { sfp_logger_1.default.log(`Unable to delete the scratchorg ${scratchOrg.username}.. due to\n` + error, sfp_logger_1.LoggerLevel.ERROR); } pool.failedToCreate += 1; pool.scratchOrgs.splice(i, 1); } return pool; } async scriptExecutor(scratchOrg) { sfp_logger_1.default.log(`Executing Preparation Job ${scratchOrg.alias} with username: ${scratchOrg.username}`, sfp_logger_1.LoggerLevel.INFO); const startTime = Date.now(); const result = await this.poolScriptExecutor.execute(scratchOrg, this.hubOrg, this.logLevel); if (result.isOk()) { scratchOrg.isScriptExecuted = true; const submitInfoToPool = await this.scratchOrgInfoAssigner.setScratchOrgInfo({ Id: scratchOrg.recordId, Allocation_status__c: 'Available', }); if (!submitInfoToPool) { scratchOrg.isScriptExecuted = false; scratchOrg.failureMessage = 'Unable to set the scratch org record in Pool'; SFPStatsSender_1.default.logCount('prepare.org.failed'); } else { SFPStatsSender_1.default.logCount('prepare.org.succeeded'); } SFPStatsSender_1.default.logElapsedTime('prepare.org.singlejob.elapsed_time', Date.now() - startTime, { poolname: this.pool.tag, }); } else { scratchOrg.isScriptExecuted = false; scratchOrg.failureMessage = result.error.message; SFPStatsSender_1.default.logCount('prepare.org.failed'); } return scratchOrg; } } exports.default = PoolCreateImpl; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9vbENyZWF0ZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29yZS9zY3JhdGNob3JnL3Bvb2wvUG9vbENyZWF0ZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUNBLDREQUFvQztBQUVwQyxpREFBOEM7QUFFOUMsc0dBQThFO0FBQzlFLDBHQUFrRjtBQUNsRix3R0FBZ0Y7QUFDaEYsK0NBQWlDO0FBQ2pDLDZDQUErQjtBQUUvQiwyQ0FBd0Q7QUFDeEQsbUVBQWlGO0FBQ2pGLDJDQUE2QztBQUM3QyxnRkFBd0Q7QUFDeEQsMkJBQXlCO0FBQ3pCLG9GQUE0RDtBQUM1RCwrRUFBdUQ7QUFDdkQsb0VBQTRDO0FBQzVDLHFEQUFxRDtBQUNyRCxxREFBbUQ7QUFDbkQsb0ZBQTREO0FBQzVELGdEQUF3QjtBQUV4QixNQUFxQixjQUFlLFNBQVEsMkJBQVk7SUFVcEQsWUFDSSxNQUFXLEVBQ0gsSUFBZ0IsRUFDaEIsa0JBQW1DLEVBQ25DLFFBQXFCO1FBRTdCLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUpOLFNBQUksR0FBSixJQUFJLENBQVk7UUFDaEIsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFpQjtRQUNuQyxhQUFRLEdBQVIsUUFBUSxDQUFhO1FBTnpCLG1CQUFjLEdBQVcsQ0FBQyxDQUFDO1FBUy9CLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxvQkFBVSxDQUFDO1lBQzFCLGFBQWEsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVM7U0FDckMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLGtDQUFrQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUNyRixDQUFDO0lBRVMsS0FBSyxDQUFDLE1BQU07UUFDbEIsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFD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