UNPKG

@dxatscale/sfprofiles

Version:
363 lines (300 loc) 14.9 kB
/* eslint-disable @typescript-eslint/no-unused-vars */ import { AuthInfo, Org } from '@salesforce/core'; import request from 'request-promise-native'; import SFPLogger, {LoggerLevel } from '@dxatscale/sfp-logger'; import retry from 'async-retry'; import Passwordgenerateimpl from '@impl/user/passwordgenerateimpl'; import queryApi from '../utils/queryExecutor'; import child_process from 'child_process'; import { Connection, SaveResult } from 'jsforce'; const ORDER_BY_FILTER = ' ORDER BY CreatedDate ASC'; export default class ScratchOrgUtils { private static sfdxAuthUrlFieldExists = false; public static async checkForSFDXAuthURLField(hubOrg: Org) { let conn = hubOrg.getConnection(); await retry( async (bail) => { const describeResult: any = await conn.sobject('ScratchOrgInfo').describe(); if (describeResult) { for (const field of describeResult.fields) { if (field.name === 'SfdxAuthUrl__c') { this.sfdxAuthUrlFieldExists = true; } } } }, { retries: 3, minTimeout: 30000 } ); } public static async getScratchOrgLimits(hubOrg: Org, apiversion: string) { let conn = hubOrg.getConnection(); let query_uri = `${conn.instanceUrl}/services/data/v${apiversion}/limits`; const limits = await request({ method: 'get', url: query_uri, headers: { Authorization: `Bearer ${conn.accessToken}`, }, json: true, }); SFPLogger.log(`Limits Fetched: ${JSON.stringify(limits)}`, LoggerLevel.TRACE); return limits; } public static async getScratchOrgRecordsAsMapByUser(hubOrg: Org) { let conn = hubOrg.getConnection(); let query = 'SELECT count(id) In_Use, SignupEmail FROM ActiveScratchOrg GROUP BY SignupEmail ORDER BY count(id) DESC'; const results = (await conn.query(query)) as any; SFPLogger.log(`Info Fetched: ${JSON.stringify(results)}`, LoggerLevel.DEBUG); let scratchOrgRecordAsMapByUser = ScratchOrgUtils.arrayToObject(results.records, 'SignupEmail'); return scratchOrgRecordAsMapByUser; } private static async getScratchOrgLoginURL(hubOrg: Org, username: string): Promise<any> { let conn = hubOrg.getConnection(); let query = `SELECT Id, SignupUsername, LoginUrl FROM ScratchOrgInfo WHERE SignupUsername = '${username}'`; SFPLogger.log('QUERY:' + query, LoggerLevel.DEBUG); const results = (await conn.query(query)) as any; SFPLogger.log(`Login URL Fetched: ${JSON.stringify(results)}`, LoggerLevel.DEBUG); return results.records[0].LoginUrl; } public static async createScratchOrg( id: number, adminEmail: string, config_file_path: string, expiry: number, hubOrg: Org, alias_prefix?: string ): Promise<ScratchOrg> { SFPLogger.log( 'Parameters: ' + id + ' ' + adminEmail + ' ' + config_file_path + ' ' + expiry + ' ', LoggerLevel.TRACE ); let result; let getSFDXCommand = `sfdx force:org:create -f ${config_file_path} -d ${expiry} -w 10 -v ${hubOrg.getUsername()} --json`; if (adminEmail) { getSFDXCommand += ` adminEmail=${adminEmail}`; } if (alias_prefix) { getSFDXCommand += ` --setalias ${alias_prefix}${id}`; } else { getSFDXCommand += ` --setalias SO${id}`; } result = child_process.execSync(getSFDXCommand, { stdio: 'pipe' }); const resultObject = JSON.parse(result); SFPLogger.log(JSON.stringify(result), LoggerLevel.TRACE); let scratchOrg: ScratchOrg = { alias: alias_prefix ? `${alias_prefix}${id}` : `SO${id}`, orgId: resultObject.result.orgId, username: resultObject.result.username, signupEmail: adminEmail ? adminEmail : '', }; //Get FrontDoor URL scratchOrg.loginURL = await this.getScratchOrgLoginURL(hubOrg, scratchOrg.username); //Generate Password let passwordData = await Passwordgenerateimpl.run(scratchOrg.username); scratchOrg.password = passwordData.password; //Get Sfdx Auth URL try { const authInfo = await AuthInfo.create({ username: scratchOrg.username }); scratchOrg.sfdxAuthUrl = authInfo.getSfdxAuthUrl(); } catch (error) { SFPLogger.log( `Unable to fetch authURL for ${scratchOrg.username}. Only Scratch Orgs created from DevHub using authenticated using auth:sfdxurl or auth:web will have access token and enabled for autoLogin`, LoggerLevel.INFO ); } if (!passwordData.password) { throw new Error('Unable to setup password to scratch org'); } else { SFPLogger.log(`Password successfully set for ${passwordData.username}`, LoggerLevel.INFO); } return scratchOrg; } public static async shareScratchOrgThroughEmail(emailId: string, scratchOrg: ScratchOrg, hubOrg: Org) { let hubOrgUserName = hubOrg.getUsername(); let body = `${hubOrgUserName} has fetched a new scratch org from the Scratch Org Pool!\n All the post scratch org scripts have been succesfully completed in this org!\n The Login url for this org is : ${scratchOrg.loginURL}\n Username: ${scratchOrg.username}\n Password: ${scratchOrg.password}\n Please use sfdx force:auth:web:login -r ${scratchOrg.loginURL} -a <alias> command to authenticate against this Scratch org</p> Thank you for using sfpowerkit!`; const options = { method: 'POST' as const, body: JSON.stringify({ inputs: [ { emailBody: body, emailAddresses: emailId, emailSubject: `${hubOrgUserName} created you a new Salesforce org`, senderType: 'CurrentUser', }, ], }), url: '/services/data/v50.0/actions/standard/emailSimple', }; await retry( async (bail) => { await hubOrg.getConnection().request(options); }, { retries: 3, minTimeout: 30000 } ); SFPLogger.log(`Succesfully send email to ${emailId} for ${scratchOrg.username}`, LoggerLevel.INFO); } public static async getScratchOrgRecordId(scratchOrgs: ScratchOrg[], hubOrg: Org) { if (scratchOrgs == undefined || scratchOrgs.length == 0) return; let hubConn = hubOrg.getConnection(); let scratchOrgIds = scratchOrgs .map(function (scratchOrg) { scratchOrg.orgId = scratchOrg.orgId.slice(0, 15); return `'${scratchOrg.orgId}'`; }) .join(','); let query = `SELECT Id, ScratchOrg FROM ScratchOrgInfo WHERE ScratchOrg IN ( ${scratchOrgIds} )`; SFPLogger.log('QUERY:' + query, LoggerLevel.TRACE); return await retry( async (bail) => { const results = (await hubConn.query(query)) as any; let resultAsObject = this.arrayToObject(results.records, 'ScratchOrg'); SFPLogger.log(JSON.stringify(resultAsObject), LoggerLevel.TRACE); scratchOrgs.forEach((scratchOrg) => { scratchOrg.recordId = resultAsObject[scratchOrg.orgId]['Id']; }); return results; }, { retries: 3, minTimeout: 3000 } ); } public static async setScratchOrgInfo(soInfo: any, hubOrg: Org): Promise<boolean> { let hubConn = hubOrg.getConnection(); if (!this.sfdxAuthUrlFieldExists) { delete soInfo.SfdxAuthUrl__c; SFPLogger.log('Removed sfdxAuthUrl info as SfdxAuthUrl__c field is not found on Org', LoggerLevel.TRACE); } SFPLogger.log(JSON.stringify(soInfo), LoggerLevel.TRACE); return await retry( async (bail) => { try { let result = await hubConn.sobject('ScratchOrgInfo').update(soInfo); SFPLogger.log('Setting Scratch Org Info:' + JSON.stringify(result), LoggerLevel.TRACE); return result.constructor !== Array ? (result as unknown as SaveResult).success : true; } catch (err) { SFPLogger.log('Failure at setting ScratchOrg Info' + err, LoggerLevel.TRACE); return false; } }, { retries: 3, minTimeout: 3000 } ); } public static async getScratchOrgsByTag(tag: string, hubOrg: Org, isMyPool: boolean, unAssigned: boolean) { let hubConn = hubOrg.getConnection(); return await retry( async (bail) => { let query; if (this.sfdxAuthUrlFieldExists) { if (!(tag === undefined || tag === null)) query = `SELECT Pooltag__c, Id, CreatedDate, ScratchOrg, ExpirationDate, SignupUsername, SignupEmail, Password__c, Allocation_status__c,LoginUrl,SfdxAuthUrl__c FROM ScratchOrgInfo WHERE Pooltag__c = '${tag}' AND Status = 'Active' `; else query = `SELECT Pooltag__c, Id, CreatedDate, ScratchOrg, ExpirationDate, SignupUsername, SignupEmail, Password__c, Allocation_status__c,LoginUrl,SfdxAuthUrl__c FROM ScratchOrgInfo WHERE Pooltag__c != null AND Status = 'Active' `; } else { if (!(tag === undefined || tag === null)) query = `SELECT Pooltag__c, Id, CreatedDate, ScratchOrg, ExpirationDate, SignupUsername, SignupEmail, Password__c, Allocation_status__c,LoginUrl FROM ScratchOrgInfo WHERE Pooltag__c = '${tag}' AND Status = 'Active' `; else query = `SELECT Pooltag__c, Id, CreatedDate, ScratchOrg, ExpirationDate, SignupUsername, SignupEmail, Password__c, Allocation_status__c,LoginUrl FROM ScratchOrgInfo WHERE Pooltag__c != null AND Status = 'Active' `; } if (isMyPool) { query = query + ` AND createdby.username = '${hubOrg.getUsername()}' `; } if (unAssigned) { // if new version compatible get Available / In progress query = query + `AND ( Allocation_status__c ='Available' OR Allocation_status__c = 'In Progress' ) `; } query = query + ORDER_BY_FILTER; SFPLogger.log('QUERY:' + query, LoggerLevel.TRACE); const results = (await hubConn.query(query)) as any; return results; }, { retries: 3, minTimeout: 3000 } ); } public static async getActiveScratchOrgsByInfoId(hubOrg: Org, scrathOrgIds: string) { let hubConn = hubOrg.getConnection(); return await retry( async (bail) => { let query = `SELECT Id, SignupUsername FROM ActiveScratchOrg WHERE ScratchOrgInfoId IN (${scrathOrgIds}) `; SFPLogger.log('QUERY:' + query, LoggerLevel.TRACE); const results = (await hubConn.query(query)) as any; return results; }, { retries: 3, minTimeout: 3000 } ); } public static async getCountOfActiveScratchOrgsByTag(tag: string, hubOrg: Org): Promise<number> { const hubConn = hubOrg.getConnection(); let query = `SELECT Id, CreatedDate, ScratchOrg, ExpirationDate, SignupUsername, SignupEmail, Password__c, Allocation_status__c,LoginUrl FROM ScratchOrgInfo WHERE Pooltag__c = '${tag}' AND Status = 'Active' `; SFPLogger.log('QUERY:' + query, LoggerLevel.TRACE); const queryUtil = new queryApi(hubConn); let result = await queryUtil.executeQuery(query, false); SFPLogger.log('RESULT:' + JSON.stringify(result), LoggerLevel.TRACE); return result.length; } public static async getCountOfActiveScratchOrgsByTagAndUsername(tag: string, hubOrg: Org): Promise<number> { let hubConn = hubOrg.getConnection(); const queryUtil = new queryApi(hubConn); let query = `SELECT Id, CreatedDate, ScratchOrg, ExpirationDate, SignupUsername, SignupEmail, Password__c, Allocation_status__c,LoginUrl FROM ScratchOrgInfo WHERE Pooltag__c = '${tag}' AND Status = 'Active' `; let result = await queryUtil.executeQuery(query, false); return result.length; } public static async getActiveScratchOrgRecordIdGivenScratchOrg( hubOrg: Org, apiversion: string, scratchOrgId: string ): Promise<any> { let hubConn = hubOrg.getConnection(); let query = `SELECT Id FROM ActiveScratchOrg WHERE ScratchOrg = '${scratchOrgId}'`; let queryUtil = new queryApi(hubConn); let result = await queryUtil.executeQuery(query, false); SFPLogger.log('Retrieve Active ScratchOrg Id:' + JSON.stringify(result), LoggerLevel.TRACE); return result[0].Id; } public static async deleteScratchOrg(hubOrg: Org, scratchOrgIds: string[]) { let hubConn = hubOrg.getConnection(); await retry( async (bail) => { await hubConn.sobject('ActiveScratchOrg').del(scratchOrgIds); }, { retries: 3, minTimeout: 3000 } ); } private static arrayToObject = (array, keyfield) => array.reduce((obj, item) => { obj[item[keyfield]] = item; return obj; }, {}); public static async checkForPreRequisite(hubOrg: Org) { await this.checkForSFDXAuthURLField(hubOrg); let hubConn = hubOrg.getConnection(); let query = `SELECT QualifiedApiName FROM FieldDefinition WHERE EntityDefinition.QualifiedApiName = 'ScratchOrgInfo' AND QualifiedApiName = 'Allocation_status__c'`; SFPLogger.log('QUERY:' + query, LoggerLevel.TRACE); let queryUtil = new queryApi(hubConn); let result = await queryUtil.executeQuery(query, true); return result.length > 0; } } export interface ScratchOrg { tag?: string; recordId?: string; orgId?: string; loginURL?: string; signupEmail?: string; username?: string; alias?: string; password?: string; isScriptExecuted?: boolean; expiryDate?: string; accessToken?: string; instanceURL?: string; status?: string; sfdxAuthUrl?: string; }