#!groovy
@Library('Utils_DXCO4SF@master') _ // Shared Library managed at https://partner-github.csc.com/Omnichannel-for-Salesforce/JenkinsSharedLibrary

pipeline {
    
    agent { 
        dockerfile {
             args '-u 0:0 -m=4g -v dxco4sfvol_pmdcache:/tmp/pmdcache -v dxco4sfvol_cache_sfdx:/root/.cache/sfdx -v dxco4sfvol_sfdx:/root/.sfdx' //Forces Container tu run as User Root , store cache dirs on locale volume
        } 
    }

    parameters {
            booleanParam(name: 'DEBUG_MODE', defaultValue: false, description: 'Debug mode for test cases')
            booleanParam(name: 'DO_NOT_REUSE_SCRATCH_ORG', defaultValue: false, description: 'Select if you do not want to reuse existing scratch orgs for this build')
            string(name: 'GLOBAL_KEY_PREFIX_OVERRIDE', defaultValue: 'none', description: 'Force a global key for external variables get')
            booleanParam(name: 'TEST_PACKAGE', defaultValue: false, description: 'True to test a managed package generated by JenkinsFile_Package')
    }

    environment {
        INCLUDE_BRANCHES_TEST = getEnvParam('INCLUDE_BRANCHES_TEST') // ex: '(DevNextVersion|Packaging)'
        // This job can be triggered manually, periodically, or by a PR hook
        IS_ALLOWED_FROM_HOOK = 'true'
        IS_ALLOWED_FROM_HOOK_ONLY_IF_PR = 'true'
        MUST_BE_TRIGGER_BY_USER = 'false'

		PROJECT_ARGS = getEnvParam('PROJECT_ARGS') // ex:  '-projectDir "./Projects" -projectName "DevRootSource"'

        PACKAGE_XML_FILE_MANAGED = getEnvParam('PACKAGE_XML_FILE_MANAGED') // ex: './Config/packageXml/package_DevRoot_Managed.xml'
        PACKAGE_XML_FILE_DEMO = getEnvParam('PACKAGE_XML_FILE_DEMO') // ex: './Config/packageXml/package_DevRoot_Managed.xml'
        PACKAGE_XML_FILE_MANAGED_AND_DEMO = getEnvParam('PACKAGE_XML_FILE_MANAGED_AND_DEMO') // ex: './Config/packageXml/package_DevRoot_Managed_And_Demo.xml'

        GENERATE_PERMISSION_SETS  = getEnvParam('GENERATE_PERMISSION_SETS',false) // ex: true

		APEX_PURGE_FOLDER = getEnvParam('APEX_PURGE_FOLDER') // ex: './Projects/DevRootSource/apex/purge'
		SFDX_ORG_ALIAS = getEnvParam('SFDX_ORG_ALIAS',false) // ex: 'DevRoot'
        DEFAULT_USER_EMAIL = getEnvParam('DEFAULT_USER_EMAIL') // ex: dxcselenium@gmail.com

        // Code quality checks
        MANAGED_PACKAGE_CONSISTENCY_CHECK = getEnvParam('MANAGED_PACKAGE_CONSISTENCY_CHECK',false) // ex: true
        SFDX_CONSISTENCY_CHECK = getEnvParam('SFDX_CONSISTENCY_CHECK') // ex: true
        SFDX_CONSISTENCY_PACKAGE_XML_FILES = getEnvParam('SFDX_CONSISTENCY_PACKAGE_XML_FILES') // ex: './Config/packageXml/package_DevRoot_Managed.xml,./Config/packageXml/package_DevRoot_xDemo.xml'
        SFDX_SOURCES_MAIN_FOLDER = getEnvParam('SFDX_SOURCES_MAIN_FOLDER') // ex: './Projects/DevRootSource/force-app/main/default'
        SFDX_SOURCES_MAIN_FOLDER_MANAGED = getEnvParam('SFDX_SOURCES_MAIN_FOLDER_MANAGED',false) // ex: './Projects/DevRootSource/force-app/main/default'
        PMD_PATH = getEnvParam('PMD_PATH') // ex: '$HOME/pmd-bin-6.12.0/bin/run.sh'
        CPD_MAX_DUPLICATIONS_ALLOWED_APEX = getEnvParam('CPD_MAX_DUPLICATIONS_ALLOWED_APEX') // ex: 55
        CPD_MAX_DUPLICATIONS_ALLOWED_ECMASCRIPT = getEnvParam('CPD_MAX_DUPLICATIONS_ALLOWED_ECMASCRIPT') // ex: 109
        CHECK_GROOVY_QUALITY = getEnvParam('CHECK_GROOVY_QUALITY')

        // Scratch org initialization
        INIT_PACKAGES_TO_INSTALL = getEnvParam('INIT_PACKAGES_TO_INSTALL',false) // ex: 'FinServ_Managed,FinServ_Unmanaged'
        INIT_PACKAGES_TO_INSTALL_MANAGED = getEnvParam('INIT_PACKAGES_TO_INSTALL_MANAGED',false) // ex: 'FinServ_Managed,FinServ_Unmanaged'

        INIT_ADDITIONAL_PACKAGEXML_FILES = getEnvParam('INIT_ADDITIONAL_PACKAGEXML_FILES',false) // ex: './Config/packageXml/package_DevRoot_xCommunitiesOnly.xml,./Config/packageXml/package_DevRoot_xSecuritySettingsOnly.xml'
        INIT_ADDITIONAL_PACKAGEXML_FILES_MANAGED = getEnvParam('INIT_ADDITIONAL_PACKAGEXML_FILES_MANAGED',false) // ex: './Config/packageXml/package_DevRoot_xCommunitiesOnly.xml,./Config/packageXml/package_DevRoot_xSecuritySettingsOnly.xml'

        INIT_PS_TO_ASSIGN = getEnvParam('INIT_PS_TO_ASSIGN',false) // ex: 'AdminCloudIRM,StdCloudIRM,OmnichannelCommunityAccess,OmnichannelCustomerCommunityAccess,OmnichannelPartnerCommunityAccess,OmnichannelStandardAccess,FinancialServicesCloudBasic,FinancialServicesCloudStandard'
        INIT_PS_TO_ASSIGN_MANAGED = getEnvParam('INIT_PS_TO_ASSIGN_MANAGED',false) // ex: 'AdminCloudIRM,StdCloudIRM,OmnichannelCommunityAccess,OmnichannelCustomerCommunityAccess,OmnichannelPartnerCommunityAccess,OmnichannelStandardAccess,FinancialServicesCloudBasic,FinancialServicesCloudStandard'

        TEST_SCRATCH_ORG_NAME_EXT_PACKAGED = getEnvParam('TEST_SCRATCH_ORG_NAME_EXT_PACKAGED',false) // ex: 'PI'
        TEST_SCRATCH_ORG_NAME_EXT_DEMO = getEnvParam('TEST_SCRATCH_ORG_NAME_EXT_DEMO',false) // ex: 'DI'
        TEST_SCRATCH_ORG_NAME_EXT_MANAGED = getEnvParam('TEST_SCRATCH_ORG_NAME_EXT_MANAGED',false) // ex: 'MI'

        INIT_APEX_CODE_FOLDER_PACKAGED = getEnvParam('INIT_APEX_CODE_FOLDER_PACKAGED',false) // ex: './Projects/DevRootSource/apex/onlyPackagedInit'
        INIT_APEX_CODE_FOLDER_DEMO = getEnvParam('INIT_APEX_CODE_FOLDER_DEMO',false) // ex: './Projects/DevRootSource/apex/create'
        INIT_APEX_CODE_FOLDER_MANAGED = getEnvParam('INIT_APEX_CODE_FOLDER_MANAGED',false) // ex: './Projects/DevRootSource/apex/create'

        SCRATCH_ORG_COMMUNITIES_TO_CHECK = getEnvParam('SCRATCH_ORG_COMMUNITIES_TO_CHECK',false) // ex: distributor,insured,company

        // Apex test classes
        CHECK_APEX_TEST_CLASSES_PACKAGED = getEnvParam('CHECK_APEX_TEST_CLASSES_PACKAGED') // ex: true
        CHECK_APEX_TEST_CLASSES_DEMO = getEnvParam('CHECK_APEX_TEST_CLASSES_DEMO') // ex: true
        CHECK_APEX_TEST_CLASSES_MANAGED = getEnvParam('CHECK_APEX_TEST_CLASSES_MANAGED',false) // ex: true

        // Selenium 
        AUTOMATED_TESTS_RUN_PACKAGED = getEnvParam('AUTOMATED_TESTS_RUN_PACKAGED',false) // ex: true
        AUTOMATED_TESTS_RUN_DEMO = getEnvParam('AUTOMATED_TESTS_RUN_DEMO',false) // ex: true
        AUTOMATED_TESTS_RUN_MANAGED = getEnvParam('AUTOMATED_TESTS_RUN_MANAGED',false) // ex: true

        TEST_CASES_INIT_LIST_FILE = getEnvParam('TEST_CASES_INIT_LIST_FILE',false) // ex: './PlayerScripts/DeploymentTestsPackaged.txt' 

        TEST_CASES_LIST_FILE_PACKAGED = getEnvParam('TEST_CASES_LIST_FILE_PACKAGED') // ex: './PlayerScripts/DeploymentTestsPackaged.txt' 
        TEST_CASES_LIST_FILE_DEMO = getEnvParam('TEST_CASES_LIST_FILE_DEMO') // ex: './PlayerScripts/DeploymentTestsDemo.txt'  
        TEST_CASES_LIST_FILE_MANAGED = getEnvParam('TEST_CASES_LIST_FILE_MANAGED',false) // ex: './PlayerScripts/DeploymentTestsManaged.txt'  

        TEST_CASES_CONFIG_FILE = getEnvParam('TEST_CASES_CONFIG_FILE') // ex: 'config_Player_https--____cloud-irm-dev-root-developer-edition.eu18.force.com__.ini'
        TEST_CASES_CONFIG_FILE_TEMPLATE = getEnvParam('TEST_CASES_CONFIG_FILE_TEMPLATE') // ex: 'config_Player_https--____cloud-irm-dev-root-developer-edition.eu18.force.com__.ini'
        TEST_CASES_RUN_MODE = getEnvParam('TEST_CASES_RUN_MODE') // ex: parallel or linear
        MAX_PARALLEL_TESTS_NB = getEnvParam('MAX_PARALLEL_TESTS_NB') // ex: 5
        MAX_PARALLEL_TESTS_NB_PARALLEL_STAGES = getEnvParam('MAX_PARALLEL_TESTS_NB_PARALLEL_STAGES') // ex: 3

        // Declare variables here so they can be updated by parallel stages and found in later stages
        SFDX_ORG_ALIAS_PACKAGED = "${SFDX_ORG_ALIAS}"
        COMMUNITIES_BASE_URL_PACKAGED = 'toBeSetLater'
        SCRATCH_ORG_USERNAME_PACKAGED = 'toBeSetLater'
        SCRATCH_ORG_PASSWORD_PACKAGED = 'toBeSetLater'

        SFDX_ORG_ALIAS_DEMO = "${SFDX_ORG_ALIAS}"
        COMMUNITIES_BASE_URL_DEMO = 'toBeSetLater'
        SCRATCH_ORG_USERNAME_DEMO = 'toBeSetLater'
        SCRATCH_ORG_PASSWORD_DEMO = 'toBeSetLater'

        SFDX_ORG_ALIAS_MANAGED = "${SFDX_ORG_ALIAS}"
        COMMUNITIES_BASE_URL_MANAGED = 'toBeSetLater'
        SCRATCH_ORG_USERNAME_MANAGED = 'toBeSetLater'
        SCRATCH_ORG_PASSWORD_MANAGED = 'toBeSetLater'
    }

    // Automatic triggers
    triggers { 
        cron((env.BRANCH_NAME != null && ['DevNextVersion','DemoQuali','DemoProd'].contains(env.BRANCH_NAME))?'00 00 * * *':'') // Periodic trigger only for some branches
    }

    // Build options
    options { 
        timeout(time: 2, unit: 'HOURS') 
        disableConcurrentBuilds()
        buildDiscarder(logRotator(daysToKeepStr: '7', numToKeepStr: '30', artifactDaysToKeepStr: '7',artifactNumToKeepStr: '30'))
    } 

    stages {

        stage('Initialization') {

            parallel {

                // Initialization
                stage('Initialize groovy') {
                    steps {
                        script {
                                CMDGRVINIT = "groovy SfdxManagement.groovy"
                                dxco4sf.executeCommand(CMDGRVINIT)   
                        }
                    }
                }

                // Build Initialization
                stage('Initialize build') {
                    steps {
                        script {
                            IS_PULL_REQUEST = false
                            // Job initialization & checks
                            dxco4sf.startJob(includedBranches: INCLUDE_BRANCHES_TEST,
                                            isAllowedFromHook: Boolean.valueOf(IS_ALLOWED_FROM_HOOK),
                                            isAllowedFromHookOnlyIfPR: Boolean.valueOf(IS_ALLOWED_FROM_HOOK_ONLY_IF_PR),
                                            mustBeTriggerByUser: Boolean.valueOf(MUST_BE_TRIGGER_BY_USER) ); 
                            
                            // Analyze params to detect if build if about a Pull Request
                            if (env.BRANCH_NAME.startsWith('PR-')) {
                                IS_PULL_REQUEST = true 
                                TEST_CASES_CONFIG_FILE = TEST_CASES_CONFIG_FILE_TEMPLATE
                            }
                            if (params.TEST_PACKAGE == true) {
                                TEST_CASES_CONFIG_FILE = TEST_CASES_CONFIG_FILE_TEMPLATE
                            }
                            echo "IS_PULL_REQUEST: ${IS_PULL_REQUEST}"
                            echo "TEST_CASES_CONFIG_FILE: ${TEST_CASES_CONFIG_FILE}"

                            // Manage scratch org user email if PR
                            V_USER_EMAIL = env.DEFAULT_USER_EMAIL 
                            if (IS_PULL_REQUEST == true) {
                                if (env.CHANGE_AUTHOR_EMAIL != null)
                                    V_USER_EMAIL = env.CHANGE_AUTHOR_EMAIL
                                else if (params.SCRATCH_ORG_USER_EMAIL != null)
                                    V_USER_EMAIL = params.SCRATCH_ORG_USER_EMAIL 
                            }

                            // Define global key prefix
                            GLOBAL_KEY_PREFIX = env.BRANCH_NAME + '_' + GIT_COMMIT ;
                            if (params.GLOBAL_KEY_PREFIX_OVERRIDE != null && params.GLOBAL_KEY_PREFIX_OVERRIDE != '' && params.GLOBAL_KEY_PREFIX_OVERRIDE != 'none') {
                                GLOBAL_KEY_PREFIX = params.GLOBAL_KEY_PREFIX_OVERRIDE
                                echo 'GLOBAL_KEY_PREFIX: '+GLOBAL_KEY_PREFIX+' (overridden via Parameters)'
                            }
                            else {
                                // If Test is to check demos are ok, do not reuse tests from previous runs, even if the commit is the same
                                if (IS_PULL_REQUEST == false && params.TEST_PACKAGE == false) {
                                    GLOBAL_KEY_PREFIX = null
                                }
                                echo 'GLOBAL_KEY_PREFIX: '+GLOBAL_KEY_PREFIX
                            }
                        }
                    } 
                }
            }

        }

        // Test sources of SFDX project
        stage('Sources') {
            parallel {

                // Check consistency between packageXml & DX project (Disabled)
                stage('Check SFDX/Package.xml consistency') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(SFDX_CONSISTENCY_CHECK)
                        } 
                    steps {
                        script {
                            echo "Check consistency between packageXml files and sfdx ${env.GIT_BRANCH}"
                            CMDCHKCNS = "sfdx essentials:check-sfdx-project-consistency -p ${SFDX_CONSISTENCY_PACKAGE_XML_FILES} -i ${SFDX_SOURCES_MAIN_FOLDER} -d \"Document,EmailTemplate\" --failIfError"
                            dxco4sf.executeCommand(CMDCHKCNS)                    
                        } 
                    }
                }

                // Check consistency between packageXml & DX project (Disabled)
                stage('Check Managed package consistency') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(MANAGED_PACKAGE_CONSISTENCY_CHECK)
                        } 
                    steps {
                        script {
                            echo "Check managed package consistency using essentials & isvte"
                            CMDCHKMPG = "groovy SfdxManagement.groovy -runCheckPackageConsistency ${env.PROJECT_ARGS} -packageXmlFile ${env.PACKAGE_XML_FILE_MANAGED}" //-jsonLog activate if u wanna check results"
                            dxco4sf.executeCommand(CMDCHKMPG)                    
                        } 
                    }
                } 

                // Check consistency between packageXml & DX project
                stage('Check apex quality') {
                    when { 
                            equals expected: false, actual: params.TEST_PACKAGE 
                        }                     
                    steps {
                        script {
                            echo 'Code quality check using PMD & CPD'
                            CODECHECKRES = dxco4sf.checkCodeQuality(project_args: env.PROJECT_ARGS,
                                                     pmd_path: env.PMD_PATH,
                                                     cpd_max_duplications_allowed : [
                                                         apex: env.CPD_MAX_DUPLICATIONS_ALLOWED_APEX,
                                                         ecmascript: env.CPD_MAX_DUPLICATIONS_ALLOWED_ECMASCRIPT
                                                     ],
                                                     globalKeyPrefix : GLOBAL_KEY_PREFIX
                                                     )   
                        }
                    }
                }

                // Check consistency between packageXml & DX project
                stage('Check Javascript quality') {
                    when { 
                            equals expected: false, actual: params.TEST_PACKAGE 
                        }  
                    steps {
                        script {
                            echo 'Javascript checks using eslint'
                            CMDCHKJS = 'npm run check-javascript-quality'
                            dxco4sf.executeCommand(CMDCHKJS) 
                        }
                    }
                }

                // Generate permission sets
                stage('Regenerate permission sets') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(env.GENERATE_PERMISSION_SETS) 
                            equals expected: true, actual: IS_PULL_REQUEST 
                        }
                    steps {
                        script {
                            CMDSFDXGENPS = 'npm run generate-permission-sets'
                            dxco4sf.executeCommand(CMDSFDXGENPS)
                        }
                    }            
                }

                // Lint groovy
                stage('Check Groovy quality') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(env.CHECK_GROOVY_QUALITY) 
                        }
                    steps {
                        script {
                            CMDLINTGROOVY = 'npm run lint-groovy'
                            dxco4sf.executeCommand(CMDLINTGROOVY)
                        }
                    }            
                }                

            }
        }

        // Org preparation ( creation if scratch org,  or purge some data in existing one)
        stage('SFDC Org') {
            parallel {

                // Initialize environment with packaged items
                stage('Initialize scratch org (futurely packaged)') {
                    when { 
                            equals expected: true, actual: IS_PULL_REQUEST
                            equals expected: false, actual: params.TEST_PACKAGE  
                        }   
                    steps {
                        script { 
                            // Create scratch org
                            echo 'Create scratch org'
                            CMDCRTSCRATCH = "groovy SfdxManagement.groovy -runFullOrgCreation ${env.PROJECT_ARGS} -scratchOrgUserEmail '${V_USER_EMAIL}' -scratchOrgNameKey '${env.GIT_BRANCH}-${env.TEST_SCRATCH_ORG_NAME_EXT_PACKAGED}' -scratchOrgDuration 1 -packagesToInstall '${env.INIT_PACKAGES_TO_INSTALL}' -noPush -initWithFilteredMetadatas -packageXmlFile ${env.PACKAGE_XML_FILE_MANAGED}  -additionalPackageXmlFiles '${env.INIT_ADDITIONAL_PACKAGEXML_FILES}' -metadatasDeployFolder 'tmp/deployScratchOrgTest${env.TEST_SCRATCH_ORG_NAME_EXT_PACKAGED}' -metadatasDeployFolderOutput 'tmp/deployScratchOrgTest${env.TEST_SCRATCH_ORG_NAME_EXT_PACKAGED}Filtered' -ignoreMyConfigFile -apexCodeFile '${env.INIT_APEX_CODE_FOLDER_PACKAGED}' -permSetsToAssign '${env.INIT_PS_TO_ASSIGN}' -globalKeyPrefix '${GLOBAL_KEY_PREFIX}' -jsonLog"+((params.DO_NOT_REUSE_SCRATCH_ORG == true)?' -doNotReuseScratchOrg':'')
                            CMDCRTSCRATCH_LOG = dxco4sf.executeCommand(CMDCRTSCRATCH)
                            CMDCRTSCRATCH_LOG_OBJ = dxco4sf.getJsonObjFromLog(CMDCRTSCRATCH_LOG)     
                            SFDX_ORG_ALIAS_PACKAGED = CMDCRTSCRATCH_LOG_OBJ.scratchOrgAlias
                            SCRATCH_ORG_USERNAME_PACKAGED = CMDCRTSCRATCH_LOG_OBJ.scratchOrgUsername
                            SCRATCH_ORG_PASSWORD_PACKAGED = CMDCRTSCRATCH_LOG_OBJ.scratchOrgPassword
                            CMDCRTSCRATCH_LOG_OBJ = null // Unset variables that are not serializable
                            echo "Variables set: \n SFDX_ORG_ALIAS_PACKAGED: ${SFDX_ORG_ALIAS_PACKAGED} \n SCRATCH_ORG_USERNAME_PACKAGED: ${SCRATCH_ORG_USERNAME_PACKAGED} \n SCRATCH_ORG_PASSWORD_PACKAGED: ${SCRATCH_ORG_PASSWORD_PACKAGED}"

                            // Direct link to open scratch org
                            echo 'Get scratch org open hyperlink for issues investigation'
                            CMDORGOPEN = "sfdx force:org:open --urlonly -u ${SFDX_ORG_ALIAS_PACKAGED}"
                            CMDORGOPEN_LOG = dxco4sf.executeCommand(CMDORGOPEN)
                            CMDORGOPEN_LOG = null

                            // Get Communities base URL
                            echo 'Get communities base URL'
                            CMDCOMURL = "groovy SfdxManagement.groovy -runApexCode ${env.PROJECT_ARGS} -apexCodeFile './Scripts/apex/getCommunitiesBaseUrl.apex' -scratchOrgAlias ${SFDX_ORG_ALIAS_PACKAGED} -jsonLog"
                            CMDCOMURL_LOG = dxco4sf.executeCommand(CMDCOMURL)
                            CMDCOMURL_LOG_OBJ = dxco4sf.getJsonObjFromLog(CMDCOMURL_LOG)  
                            COMMUNITIES_BASE_URL_PACKAGED = CMDCOMURL_LOG_OBJ['getCommunitiesBaseUrl.apex'].returnValue
                            CMDCOMURL_LOG_OBJ = null // Unset variables that are not serializable

                            // Wait communities to be active before going further
                            def SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls = SCRATCH_ORG_COMMUNITIES_TO_CHECK.split(',')
                            for (int i = 0; i< SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls.size(); i++) {
                                def community = SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls[i] ;
                                def communityBaseUrl = COMMUNITIES_BASE_URL_PACKAGED.replace('https','http')+community
                                CMD_CHECK_COMMUNITY_ACTIVE = "groovy SfdxManagement.groovy -runWaitCommunityActive -url ${communityBaseUrl} -timeout 10 -jsonLog" ;
                                dxco4sf.executeCommand(CMD_CHECK_COMMUNITY_ACTIVE)                            
                            }

                        } 
                    }                           
                }

                // Initialize environment with packaged items
                stage('Initialize scratch org (demo)') {
                    when { 
                            equals expected: true, actual: IS_PULL_REQUEST 
                            equals expected: false, actual: params.TEST_PACKAGE 
                        }   
                    steps {
                        script {
                            // Append Package.XML
                            echo "Prepare retrieve by appending ${PACKAGE_XML_FILE_MANAGED} and ${PACKAGE_XML_FILE_DEMO} into ${PACKAGE_XML_FILE_MANAGED_AND_DEMO}"
                            APPENDXMLCOMMAND = "sfdx essentials:packagexml:append -p '${PACKAGE_XML_FILE_MANAGED},${PACKAGE_XML_FILE_DEMO}' -o '${PACKAGE_XML_FILE_MANAGED_AND_DEMO}'" 
                            dxco4sf.executeCommand(APPENDXMLCOMMAND) 

                            // Create scratch org
                            echo 'Create scratch org'
                            CMDCRTSCRATCH2 = "groovy SfdxManagement.groovy -runFullOrgCreation ${env.PROJECT_ARGS} -scratchOrgUserEmail '${V_USER_EMAIL}' -scratchOrgNameKey '${env.GIT_BRANCH}-${env.TEST_SCRATCH_ORG_NAME_EXT_DEMO}' -scratchOrgDuration 1 -packagesToInstall '${env.INIT_PACKAGES_TO_INSTALL}' -noPush -initWithFilteredMetadatas -packageXmlFile ${env.PACKAGE_XML_FILE_MANAGED_AND_DEMO}  -additionalPackageXmlFiles '${env.INIT_ADDITIONAL_PACKAGEXML_FILES}' -metadatasDeployFolder 'tmp/deployScratchOrgTest${env.TEST_SCRATCH_ORG_NAME_EXT_DEMO}' -metadatasDeployFolderOutput 'tmp/deployScratchOrgTest${env.TEST_SCRATCH_ORG_NAME_EXT_DEMO}Filtered' -ignoreMyConfigFile -apexCodeFile '${env.INIT_APEX_CODE_FOLDER_DEMO}' -permSetsToAssign '${env.INIT_PS_TO_ASSIGN}' -globalKeyPrefix '${GLOBAL_KEY_PREFIX}' -jsonLog"+((params.DO_NOT_REUSE_SCRATCH_ORG == true)?' -doNotReuseScratchOrg':'')
                            CMDCRTSCRATCH_LOG2 = dxco4sf.executeCommand(CMDCRTSCRATCH2)
                            CMDCRTSCRATCH_LOG_OBJ2 = dxco4sf.getJsonObjFromLog(CMDCRTSCRATCH_LOG2)     
                            SFDX_ORG_ALIAS_DEMO = CMDCRTSCRATCH_LOG_OBJ2.scratchOrgAlias
                            SCRATCH_ORG_USERNAME_DEMO = CMDCRTSCRATCH_LOG_OBJ2.scratchOrgUsername
                            SCRATCH_ORG_PASSWORD_DEMO = CMDCRTSCRATCH_LOG_OBJ2.scratchOrgPassword
                            CMDCRTSCRATCH_LOG_OBJ2 = null   // Unset variables that are not serializable
                            echo "Variables set: \n SFDX_ORG_ALIAS_DEMO: ${SFDX_ORG_ALIAS_DEMO} \n SCRATCH_ORG_USERNAME_DEMO: ${SCRATCH_ORG_USERNAME_DEMO} \n SCRATCH_ORG_PASSWORD_DEMO: ${SCRATCH_ORG_PASSWORD_DEMO}"

                            // Direct link to open scratch org
                            echo 'Get scratch org open hyperlink for issues investigation'
                            CMDORGOPEN2 = "sfdx force:org:open --urlonly -u ${SFDX_ORG_ALIAS_DEMO}"
                            CMDORGOPEN_LOG2 = dxco4sf.executeCommand(CMDORGOPEN2)
                            CMDORGOPEN_LOG2 = null

                            // Get Communities base URL
                            echo 'Get communities base URL'
                            CMDCOMURL2 = "groovy SfdxManagement.groovy -runApexCode ${env.PROJECT_ARGS} -apexCodeFile './Scripts/apex/getCommunitiesBaseUrl.apex' -scratchOrgAlias ${SFDX_ORG_ALIAS_DEMO} -jsonLog"
                            CMDCOMURL_LOG2 = dxco4sf.executeCommand(CMDCOMURL2)
                            CMDCOMURL_LOG_OBJ2 = dxco4sf.getJsonObjFromLog(CMDCOMURL_LOG2)  
                            COMMUNITIES_BASE_URL_DEMO = CMDCOMURL_LOG_OBJ2['getCommunitiesBaseUrl.apex'].returnValue
                            CMDCOMURL_LOG_OBJ2 = null // Unset variables that are not serializable

                            // Wait communities to be active before going further
                            def SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls2 = SCRATCH_ORG_COMMUNITIES_TO_CHECK.split(',')
                            for (int i = 0; i < SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls2.size(); i++) {
                                def community = SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls2[i] ;
                                def communityBaseUrl = COMMUNITIES_BASE_URL_DEMO.replace('https','http')+community
                                CMD_CHECK_COMMUNITY_ACTIVE2 = "groovy SfdxManagement.groovy -runWaitCommunityActive -url ${communityBaseUrl} -timeout 10 -jsonLog" ;
                                dxco4sf.executeCommand(CMD_CHECK_COMMUNITY_ACTIVE2)                            
                            }

                        } 
                    }                           
                }

                // Initialize environment with packaged items
                stage('Initialize scratch org (Managed)') {
                    when { 
                            equals expected: true, actual: params.TEST_PACKAGE  
                        }   
                    steps {
                        script { 
                            // Create scratch org
                            echo 'Create scratch org'
                            CMDCRTSCRATCH3 = "groovy SfdxManagement.groovy -runFullOrgCreation ${env.PROJECT_ARGS} -scratchOrgUserEmail '${V_USER_EMAIL}' -scratchOrgNameKey '${env.GIT_BRANCH}-${env.TEST_SCRATCH_ORG_NAME_EXT_MANAGED}' -scratchOrgDuration 1 -packagesToInstall '${env.INIT_PACKAGES_TO_INSTALL_MANAGED}' -noPush -initWithFilteredMetadatas -additionalPackageXmlFiles '${INIT_ADDITIONAL_PACKAGEXML_FILES_MANAGED}' -sfdxSourcesFolder '${SFDX_SOURCES_MAIN_FOLDER_MANAGED}' -metadatasDeployFolder 'tmp/${env.TEST_SCRATCH_ORG_NAME_EXT_MANAGED}' -metadatasDeployFolderOutput 'tmp/${env.TEST_SCRATCH_ORG_NAME_EXT_MANAGED}Filtered' -ignoreMyConfigFile -apexCodeFile '${INIT_APEX_CODE_FOLDER_MANAGED}' -permSetsToAssign '${INIT_PS_TO_ASSIGN_MANAGED}' -globalKeyPrefix '${GLOBAL_KEY_PREFIX}' -jsonLog"+((params.DO_NOT_REUSE_SCRATCH_ORG == true)?' -doNotReuseScratchOrg':'')
                            CMDCRTSCRATCH_LOG3 = dxco4sf.executeCommand(CMDCRTSCRATCH3)
                            CMDCRTSCRATCH_LOG_OBJ3 = dxco4sf.getJsonObjFromLog(CMDCRTSCRATCH_LOG3)     
                            SFDX_ORG_ALIAS_MANAGED = CMDCRTSCRATCH_LOG_OBJ3.scratchOrgAlias
                            SCRATCH_ORG_USERNAME_MANAGED = CMDCRTSCRATCH_LOG_OBJ3.scratchOrgUsername
                            SCRATCH_ORG_PASSWORD_MANAGED = CMDCRTSCRATCH_LOG_OBJ3.scratchOrgPassword
                            CMDCRTSCRATCH_LOG_OBJ = null // Unset variables that are not serializable
                            echo "Variables set: \n SFDX_ORG_ALIAS_MANAGED: ${SFDX_ORG_ALIAS_MANAGED} \n SCRATCH_ORG_USERNAME_MANAGED: ${SCRATCH_ORG_USERNAME_MANAGED} \n SCRATCH_ORG_PASSWORD_PACKAGED: ${SCRATCH_ORG_PASSWORD_MANAGED}"

                            // Direct link to open scratch org
                            echo 'Get scratch org open hyperlink for issues investigation'
                            CMDORGOPEN = "sfdx force:org:open --urlonly -u ${SFDX_ORG_ALIAS_MANAGED}"
                            CMDORGOPEN_LOG = dxco4sf.executeCommand(CMDORGOPEN)
                            CMDORGOPEN_LOG = null

                            // Get Communities base URL
                            echo 'Get communities base URL'
                            CMDCOMURL = "groovy SfdxManagement.groovy -runApexCode ${env.PROJECT_ARGS} -apexCodeFile './Scripts/apex/getCommunitiesBaseUrl.apex' -scratchOrgAlias ${SFDX_ORG_ALIAS_MANAGED} -jsonLog"
                            CMDCOMURL_LOG = dxco4sf.executeCommand(CMDCOMURL)
                            CMDCOMURL_LOG_OBJ = dxco4sf.getJsonObjFromLog(CMDCOMURL_LOG)  
                            COMMUNITIES_BASE_URL_MANAGED = CMDCOMURL_LOG_OBJ['getCommunitiesBaseUrl.apex'].returnValue
                            echo "Variables set: \n COMMUNITIES_BASE_URL_MANAGED: ${COMMUNITIES_BASE_URL_MANAGED}"
                            CMDCOMURL_LOG_OBJ = null // Unset variables that are not serializable

                            // Wait communities to be active before going further
                            def SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls = SCRATCH_ORG_COMMUNITIES_TO_CHECK.split(',')
                            for (int i = 0; i< SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls.size(); i++) {
                                def community = SCRATCH_ORG_COMMUNITIES_TO_CHECK_ls[i] ;
                                def communityBaseUrl = COMMUNITIES_BASE_URL_MANAGED.replace('https','http')+community
                                CMD_CHECK_COMMUNITY_ACTIVE = "groovy SfdxManagement.groovy -runWaitCommunityActive -url ${communityBaseUrl} -timeout 10 -jsonLog" ;
                                dxco4sf.executeCommand(CMD_CHECK_COMMUNITY_ACTIVE)                            
                            }

                        } 
                    }                           
                }

                // Purge
                stage('Purge existing org data') {
                    when { 
                            equals expected: false, actual: IS_PULL_REQUEST 
                            equals expected: false, actual: params.TEST_PACKAGE 
                        }            
                    steps {
                        script {
                            echo 'Purge ' + SFDX_ORG_ALIAS
                            CMDPURGEDEVROOT = "groovy SfdxManagement.groovy -runApexCode ${PROJECT_ARGS} -apexCodeFile ${APEX_PURGE_FOLDER} -sourceEnvName ${SFDX_ORG_ALIAS} -scratchOrgAlias ${SFDX_ORG_ALIAS}"
                            dxco4sf.executeCommand(CMDPURGEDEVROOT)
                        }
                    }
                }
            }
        }


        // Apex Test classes execution
        stage('Tests') {
            parallel {
                // Execute apex test classes (packaged)
                stage ('Apex test classes (futurely packaged)') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(CHECK_APEX_TEST_CLASSES_PACKAGED) 
                            equals expected: false, actual: params.TEST_PACKAGE 
                        }               
                    steps {
                        script {
                            dir ('.') {
                                echo 'Execute apex test classes'
                                CMDAPEXTESTRUN = "groovy SfdxManagement.groovy -runTestClasses ${env.PROJECT_ARGS} -packageXmlFile ${env.PACKAGE_XML_FILE_MANAGED} -scratchOrgAlias ${SFDX_ORG_ALIAS_PACKAGED} -globalKeyPrefix ${GLOBAL_KEY_PREFIX}"
                                dxco4sf.executeCommand(CMDAPEXTESTRUN)
                            }
                        }
                    }
                }

                // Execute apex test classes (demo)
                stage ('Apex test classes (demo)') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(CHECK_APEX_TEST_CLASSES_DEMO) 
                            equals expected: false, actual: params.TEST_PACKAGE 
                        }              
                    steps {
                        script {
                            dir ('.') {
                                echo 'Execute apex test classes'
                                CMDAPEXTESTRUN2 = "groovy SfdxManagement.groovy -runTestClasses ${env.PROJECT_ARGS} -packageXmlFile ${env.PACKAGE_XML_FILE_DEMO} -scratchOrgAlias ${SFDX_ORG_ALIAS_DEMO} -globalKeyPrefix ${GLOBAL_KEY_PREFIX}"
                                dxco4sf.executeCommand(CMDAPEXTESTRUN2)
                            }
                        }
                    }
                }

                // Execute apex test classes ( Managed)
                stage ('Apex test classes (Managed package)') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(CHECK_APEX_TEST_CLASSES_MANAGED) 
                            equals expected: true, actual: params.TEST_PACKAGE 
                        }               
                    steps {
                        script {
                            dir ('.') {
                                echo 'Execute apex test classes'
                                CMDAPEXTESTRUN = "groovy SfdxManagement.groovy -runTestClasses ${env.PROJECT_ARGS} -scratchOrgAlias ${SFDX_ORG_ALIAS_MANAGED} -globalKeyPrefix ${GLOBAL_KEY_PREFIX}"
                                dxco4sf.executeCommand(CMDAPEXTESTRUN)
                            }
                        }
                    }
                }

                // Selenium scripts (futurely packaged items)
                stage('Selenium (futurely packaged)') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(AUTOMATED_TESTS_RUN_PACKAGED) 
                            equals expected: false, actual: params.TEST_PACKAGE 
                        }   
                    steps {
                        script {
                            dir ('.') {
                                // Do a first step to pass page with record of phone number if org is new ( scratch org created for PR validation )
                                if (IS_PULL_REQUEST == true) {
                                    echo "Run Test Cases (Initialization) ${TEST_CASES_INIT_LIST_FILE} in ${SFDX_ORG_ALIAS_PACKAGED} org"
                                    dxco4sf.executeTestCases(playerDeploymentTestsFile: TEST_CASES_INIT_LIST_FILE,
                                                            playerConfigFile: TEST_CASES_CONFIG_FILE ,
                                                            envName: SFDX_ORG_ALIAS_PACKAGED,
                                                            maxParallelTests: 1,
                                                            communitiesBaseUrl : COMMUNITIES_BASE_URL_PACKAGED,
                                                            sfdcUsername : SCRATCH_ORG_USERNAME_PACKAGED,
                                                            sfdcPassword : SCRATCH_ORG_PASSWORD_PACKAGED                                                
                                                            );
                                }

                                // Build parameters to send to executeTestCase
                                def seleniumParams = [ playerDeploymentTestsFile: TEST_CASES_LIST_FILE_PACKAGED,
                                                        playerConfigFile: TEST_CASES_CONFIG_FILE ,
                                                        envName: SFDX_ORG_ALIAS_PACKAGED,
                                                        maxParallelTests: MAX_PARALLEL_TESTS_NB_PARALLEL_STAGES ]
                                // Add parameters if new scratch org
                                if (IS_PULL_REQUEST == true) {
                                    seleniumParams.communitiesBaseUrl = COMMUNITIES_BASE_URL_PACKAGED
                                    seleniumParams.sfdcUsername = SCRATCH_ORG_USERNAME_PACKAGED
                                    seleniumParams.sfdcPassword = SCRATCH_ORG_PASSWORD_PACKAGED
                                    seleniumParams.globalKeyPrefix = GLOBAL_KEY_PREFIX   
                                }

                                // Manage debug mode if requested when launching job
                                if (params.DEBUG_MODE == true) {
                                    seleniumParams.debugMode = true 
                                }

                                // Run Selenium business tests campaign
                                echo "Run Test Cases (Initialization) ${TEST_CASES_LIST_FILE_PACKAGED} in ${SFDX_ORG_ALIAS_PACKAGED} org"
                                dxco4sf.executeTestCases(seleniumParams);
                                seleniumParams = null // Unset variables that are not serializable
                            }
                        }
                    }
                } 

                // Selenium scripts (Demo items)
                stage('Selenium (demo)') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(AUTOMATED_TESTS_RUN_DEMO) 
                            equals expected: false, actual: params.TEST_PACKAGE 
                        }                       
                    steps {
                        script {
                            dir ('.') {
                                // Do a first step to pass page with record of phone number if org is new ( scratch org created for PR validation )
                                if (IS_PULL_REQUEST == true) {
                                    echo "Run Test Cases (Initialization) ${TEST_CASES_INIT_LIST_FILE} in ${SFDX_ORG_ALIAS_DEMO} org"
                                    dxco4sf.executeTestCases(playerDeploymentTestsFile: TEST_CASES_INIT_LIST_FILE,
                                                            playerConfigFile: TEST_CASES_CONFIG_FILE ,
                                                            envName: SFDX_ORG_ALIAS_DEMO,
                                                            maxParallelTests: 1,
                                                            communitiesBaseUrl : COMMUNITIES_BASE_URL_DEMO,
                                                            sfdcUsername : SCRATCH_ORG_USERNAME_DEMO,
                                                            sfdcPassword : SCRATCH_ORG_PASSWORD_DEMO
                                                            );
                                }

                                // Build parameters to send to executeTestCase
                                def seleniumParams2 = [ playerDeploymentTestsFile: TEST_CASES_LIST_FILE_DEMO,
                                                        playerConfigFile: TEST_CASES_CONFIG_FILE ,
                                                        envName: SFDX_ORG_ALIAS_DEMO,
                                                        maxParallelTests: MAX_PARALLEL_TESTS_NB_PARALLEL_STAGES ]
                                // Add parameters if new scratch org
                                if (IS_PULL_REQUEST == true) {
                                    seleniumParams2.communitiesBaseUrl = COMMUNITIES_BASE_URL_DEMO
                                    seleniumParams2.sfdcUsername = SCRATCH_ORG_USERNAME_DEMO
                                    seleniumParams2.sfdcPassword = SCRATCH_ORG_PASSWORD_DEMO
                                    seleniumParams2.globalKeyPrefix = GLOBAL_KEY_PREFIX   
                                }

                                // Manage debug mode if requested when launching job
                                if (params.DEBUG_MODE == true) {
                                    seleniumParams2.debugMode = true 
                                }

                                // Run Selenium business tests campaign
                                echo "Run Test Cases (Initialization) ${TEST_CASES_LIST_FILE_DEMO} in ${SFDX_ORG_ALIAS_DEMO} org"
                                dxco4sf.executeTestCases(seleniumParams2);
                                seleniumParams2 = null // Unset variables that are not serializable
                            }
                        }
                    }
                } 

                // Selenium cripts (Managed package)
                stage('Selenium (Managed package)') {
                    when { 
                            equals expected: true, actual: Boolean.valueOf(AUTOMATED_TESTS_RUN_MANAGED) 
                            equals expected: true, actual: params.TEST_PACKAGE 
                        }   
                    steps {
                        script {
                            dir ('.') {
                                // Do a first step to pass page with record of phone number if org is new ( scratch org created for PR validation )
                                echo "Run Test Cases (Initialization) ${TEST_CASES_INIT_LIST_FILE} in ${SFDX_ORG_ALIAS_MANAGED} org"
                                dxco4sf.executeTestCases(playerDeploymentTestsFile: TEST_CASES_INIT_LIST_FILE,
                                                        playerConfigFile: TEST_CASES_CONFIG_FILE ,
                                                        envName: SFDX_ORG_ALIAS_MANAGED,
                                                        maxParallelTests: 1,
                                                        communitiesBaseUrl : COMMUNITIES_BASE_URL_MANAGED,
                                                        sfdcUsername : SCRATCH_ORG_USERNAME_MANAGED,
                                                        sfdcPassword : SCRATCH_ORG_PASSWORD_MANAGED                                                
                                                        );


                                // Build parameters to send to executeTestCase
                                def seleniumParams = [ playerDeploymentTestsFile: TEST_CASES_LIST_FILE_MANAGED,
                                                        playerConfigFile: TEST_CASES_CONFIG_FILE ,
                                                        envName: SFDX_ORG_ALIAS_MANAGED,
                                                        maxParallelTests: MAX_PARALLEL_TESTS_NB_PARALLEL_STAGES ]

                                // Add parameters
                                seleniumParams.communitiesBaseUrl = COMMUNITIES_BASE_URL_MANAGED
                                seleniumParams.sfdcUsername = SCRATCH_ORG_USERNAME_MANAGED
                                seleniumParams.sfdcPassword = SCRATCH_ORG_PASSWORD_MANAGED
                                seleniumParams.globalKeyPrefix = GLOBAL_KEY_PREFIX   


                                // Manage debug mode if requested when launching job
                                if (params.DEBUG_MODE == true) {
                                    seleniumParams.debugMode = true 
                                }

                                // Run Selenium business tests campaign
                                echo "Run Test Cases (Initialization) ${TEST_CASES_LIST_FILE_MANAGED} in ${SFDX_ORG_ALIAS_MANAGED} org"
                                dxco4sf.executeTestCases(seleniumParams);
                                seleniumParams = null // Unset variables that are not serializable
                            }
                        }
                    }
                } 

            }
        }
    }

    // Job post actions
    post {
        always {
            script {
                dxco4sf.endJob();
            }
        }

        // In case of PR check success or failure , notify #pull-requests channel on slack & delete scratch orgs (only if success )
        success{
            script {
                if (IS_PULL_REQUEST == true) {
                    // Send slack notif
                    dxco4sf.slackSendNotif(color: 'good', channel: "#pull-requests", message: "Pull request ${env.CHANGE_TITLE} check is in success.\n${env.CHANGE_URL}")
                    // Delete scratch orgs if success, else keep it for future retries
                    if (SFDX_ORG_ALIAS_PACKAGED != SFDX_ORG_ALIAS){
                        echo "Delete scratch org ${SFDX_ORG_ALIAS_PACKAGED}"
                        CMDDELSCRATCH_P = "groovy SfdxManagement.groovy -runDeleteScratchOrg ${env.PROJECT_ARGS} -scratchOrgAlias ${SFDX_ORG_ALIAS_PACKAGED}"
                        dxco4sf.executeCommand(CMDDELSCRATCH_P)
                    }
                    if (SFDX_ORG_ALIAS_DEMO != SFDX_ORG_ALIAS){
                        echo "Delete scratch org ${SFDX_ORG_ALIAS_DEMO}"
                        CMDDELSCRATCH_D = "groovy SfdxManagement.groovy -runDeleteScratchOrg ${env.PROJECT_ARGS} -scratchOrgAlias ${SFDX_ORG_ALIAS_DEMO}"
                        dxco4sf.executeCommand(CMDDELSCRATCH_D)
                    }
                }
            }
        }
        failure{
            script {
                if (IS_PULL_REQUEST == true) {
                    // Send slack notif
                    dxco4sf.slackSendNotif(color: 'danger', channel: "#pull-requests", message: "Pull request ${env.CHANGE_TITLE} check has failed \n${env.CHANGE_URL}\n${env.CHANGE_AUTHOR_DISPLAY_NAME} must perform the corrections")
                }
            }
        }


    } 
}

/********************************************************************************************************/
/**************************************** FUNCTIONS *****************************************************/
/********************************************************************************************************/

def getEnvParam(String configVarName,Boolean mandatory) {
    // If Pull Request, use target branch config file
    def branchName = (env.GIT_BRANCH != null)?env.GIT_BRANCH:env.BRANCH_NAME
    if (branchName.startsWith('PR-'))
        branchName = env.CHANGE_TARGET

    // Get in branch config file
    def params = readYaml file: "./JenkinsFiles/jkf-config-${branchName}.yml"
    def returnValue = params[configVarName] 

    // Uncomment for testing PR DevOps: DO NOT FORGET TO COMMENT AGAIN AFTER !!
    // >>>>>>>>>>>>>>>>>>>
    /*
    if (returnValue == null ) {
        def paramsCommon = readYaml file: './JenkinsFiles/jkf-config-TestDeploy.yml' 
        returnValue = paramsCommon[configVarName]
    } */
    // <<<<<<<<<<<<<<<<<<<<

    // If not found in config file, try in default config file
    if (returnValue == null ) {
        def paramsCommon = readYaml file: './JenkinsFiles/jkf-config-default.yml' 
        returnValue = paramsCommon[configVarName]
    }

    if (mandatory) {
        assert returnValue != null , "${configVarName} should be set in yml file !"
    }
    echo "Variable ${configVarName} : ${returnValue}"
    return returnValue 
}

def getEnvParam(String configVarName) {
    return getEnvParam(configVarName,true)
}
