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