pipeline {
    agent { label "amd64 && linux" }

    options {
        buildDiscarder(logRotator(numToKeepStr: '135', daysToKeepStr: '21'))
        gitLabConnection('GitLabConnectionJenkins')
    }

    stages {
        stage('clean previous runs and update gitlab commit status'){
            steps{
                deleteDir()
                updateGitlabCommitStatus(name: 'Build linux', state: 'running')
            }
        }

        stage('Get build parameters'){
            parallel{
                stage('Get build options'){
                    when {
                        allOf {
                            expression { env.gitlabTriggerPhrase != null }
                            expression { env.gitlabTriggerPhrase.contains('BUILD_OPTIONS') }
                        }
                    }
                    steps {
                        script{
                            BUILD_OPTIONS = sh(script: 'echo "$gitlabTriggerPhrase" | grep BUILD_OPTIONS | awk -F "BUILD_OPTIONS="  \'{print \$2}\' | cut -d"\"" -f2', returnStdout: true).trim()
                            println BUILD_OPTIONS
                        }
                    }
                    post{
                        always {
                            script{                        
                                if (currentBuild.currentResult == 'FAILURE'){
                                    addGitLabMRComment(comment: ":red_circle: ${env.JOB_NAME} FAILURE when getting the additional build parameters :worried:<br/>Build results: [Jenkins [${env.JOB_NAME} ${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}" )
                                }
                            }
                        }
                    }
                }

                stage('Get SDK branch'){
                    steps {
                        script{
                            env.SDK_BRANCH = sh(script: 'echo "$gitlabMergeRequestDescription" | grep SDK_SUBMODULE_TEST | awk -F "SDK_SUBMODULE_TEST="  \'{print \$2}\' | cut -d" " -f1', returnStdout: true).trim()
                            if (SDK_BRANCH == ""){
                                echo "SDK_BRANCH was not found on description so develop will be used by default"
                                env.SDK_BRANCH = "develop"
                            }
                            println SDK_BRANCH
                        }
                    }
                    post{
                        always {
                            script{                        
                                if (currentBuild.currentResult == 'FAILURE'){
                                    addGitLabMRComment(comment: ":red_circle: ${env.JOB_NAME} FAILURE when getting the SDK branch :worried:<br/>Build results: [Jenkins [${env.JOB_NAME} ${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}" )
                                }
                            }
                        }
                    }
                }
            }
        }

    stage('Checkout sources'){
        parallel{
        stage('Checkout MEGAcmd with prebuildmerge'){
            steps{
            checkout([
                $class: 'GitSCM',
                branches: [[name: "origin/${env.gitlabSourceBranch}"]],
                userRemoteConfigs: [[ url: "${env.GIT_URL_MEGACMD}", credentialsId: "12492eb8-0278-4402-98f0-4412abfb65c1" ]],
                extensions: [
                [$class: "UserIdentity",name: "jenkins", email: "jenkins@jenkins"],
                [$class: 'PreBuildMerge', options: [fastForwardMode: 'FF', mergeRemote: "origin", mergeStrategy: 'DEFAULT', mergeTarget: "${env.gitlabTargetBranch}"]]
                            ]
            ])
            }
        }
        stage('Checkout SDK'){
            steps{
            dir('sdk'){
                checkout([
                $class: 'GitSCM',
                branches: [[name: "origin/${SDK_BRANCH}"]],
                userRemoteConfigs: [[ url: "${env.GIT_URL_SDK}", credentialsId: "12492eb8-0278-4402-98f0-4412abfb65c1" ]],
                extensions: [
                    [$class: "UserIdentity",name: "jenkins", email: "jenkins@jenkins"],
                    [$class: "CloneOption", depth: 1, shallow: true, noTags: false, reference: '']
                ]
                ])
            }
            script{
                megacmd_sources_workspace = WORKSPACE
                sdk_sources_workspace = "${megacmd_sources_workspace}/sdk"
            }
            }
        }
        }
    }

        stage("Build MEGAcmd"){
            matrix {
                axes {
                    axis {
                        name 'SANITIZERS'
                        values 'ubsan', 'asan', 'tsan'
                    }
                    axis {
                        name 'BUILD_SYSTEM'
                        values 'autotools', 'c-make'
                    }
                }
		excludes {
		    exclude {
			axis {
			    name 'BUILD_SYSTEM'
			    values 'c-make'
			}
			axis {
			    name 'SANITIZERS'
			    notValues 'ubsan'
			}
		    }
		}
                stages{
                    stage('Build MEGAcmd container image'){
                        options{
                            timeout(time: 3, unit: 'HOURS')
                        }
                        environment{
                            DOCKER_BUILDKIT=1
                        }
                        steps {
                            sh "docker build -t meganz/megacmd-${BUILD_SYSTEM}-${SANITIZERS}:${env.BUILD_NUMBER} -f ${megacmd_sources_workspace}/build-with-docker/Dockerfile.${BUILD_SYSTEM} --build-arg=BUILD_OPT_SANITIZERS=${SANITIZERS} --ulimit=core=-1 --cpuset-cpus=0,1 -- ${megacmd_sources_workspace}"
                        }
                    }
                }
            }
        }

        stage('Test MEGAcmd') {
            matrix {
                axes {
                    axis {
                        name 'SANITIZERS'
                        values 'ubsan', 'asan', 'tsan'
                    }
                    axis {
                        name 'TYPE'
                        values 'unit', 'integration'
                    }
                }
                stages {
                    stage('Run MEGAcmd unit tests'){
                        when{
                            expression {
                                env.TYPE == "unit"
                            }
                        }
                        options{
                            timeout(time: 10, unit: 'MINUTES')
                        }
                        environment{
                            ASAN_OPTIONS='atexit=1,print_stats=1,log_path=/tmp/test-results/megacmd-unit-tests-asan-report'
                            TSAN_OPTIONS='log_path=/tmp/test-results/megacmd-unit-tests-tsan-report'
                            UBSAN_OPTIONS='log_path=/tmp/test-results/megacmd-unit-tests-ubsan-report'
                        }
                        steps {
                            dir('test-results') {
                                sh "docker run --user \$(id -u):\$(id -g) --env HOME=/tmp --env ASAN_OPTIONS --env TSAN_OPTIONS --rm --mount type=bind,src='${megacmd_sources_workspace}/test-results',target=/tmp/test-results -- meganz/megacmd-autotools-${SANITIZERS}:${env.BUILD_NUMBER} /usr/local/bin/mega-cmd-unit-tests --gtest_output=xml:/tmp/test-results/${SANITIZERS}-megacmd-unit-tests.xml --gtest_shuffle"
                            }
                        }
                    }
                    stage('Run MEGAcmd integration tests'){
                        when{
                            expression {
                                env.TYPE == "integration"
                            }
                        }
                        options{
                            timeout(time: 10, unit: 'MINUTES')
                        }
                        environment{
                            MEGACMD_TEST_USER=''
                            MEGACMD_TEST_PASS=credentials('MEGACMD_TESTS_PASSWORD')
                            ASAN_OPTIONS='atexit=1,print_stats=1,log_path=/tmp/test-results/megacmd-integration-tests-asan-report'
                            TSAN_OPTIONS='log_path=/tmp/test-results/megacmd-integration-tests-tsan-report'
                            UBSAN_OPTIONS='log_path=/tmp/test-results/megacmd-unit-integration-ubsan-report'
                        }
                        steps {
                            lock(label: 'testing_accounts_megacmd', variable: 'MEGACMD_TEST_USER', quantity: 1, resource: null){
                                dir('test-results') {
                                    script {
                                        try {
                                            sh "docker run --user \$(id -u):\$(id -g) --env HOME=/tmp --env MEGACMD_TEST_PASS --env MEGACMD_TEST_USER --env ASAN_OPTIONS --env TSAN_OPTIONS --rm --mount type=bind,src='${megacmd_sources_workspace}/test-results',target=/tmp/test-results -- meganz/megacmd-autotools-${SANITIZERS}:${env.BUILD_NUMBER} /usr/local/bin/mega-cmd-integration-tests --gtest_output=xml:/tmp/test-results/${SANITIZERS}-megacmd-integration-tests.xml --gtest_shuffle"
                                        } catch(e) {
                                            if (env.SANITIZERS == 'tsan'){
                                                echo "${env.SANITIZERS} sanitizer build are expected to fail for now, will keep the build as successful"
                                            } else {
                                                sh "exit 1"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    post{
        always{
            script{
                if (currentBuild.currentResult == 'SUCCESS'){
                    addGitLabMRComment(comment: ":white_check_mark: ${currentBuild.projectName} :penguin: <b>Linux</b> SUCCEEDED :muscle:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${env.GIT_COMMIT}" )
                    updateGitlabCommitStatus(name: 'Build linux', state: 'success')
                }                                
                if (currentBuild.currentResult == 'FAILURE'){
                    addGitLabMRComment(comment: ":red_circle: ${currentBuild.projectName} :penguin: <b>Linux</b> FAILURE  :worried:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${env.GIT_COMMIT}" )
                    updateGitlabCommitStatus(name: 'Build linux', state: 'failed')
                }
                if (currentBuild.currentResult == 'ABORTED'){
                    addGitLabMRComment(comment: ":interrobang: ${currentBuild.projectName} :penguin: <b>Linux</b> ABORTED  :confused:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${env.GIT_COMMIT}" )
                    updateGitlabCommitStatus(name: 'Build linux', state: 'canceled')
                }                                
                if (currentBuild.currentResult == 'UNSTABLE'){
                    addGitLabMRComment(comment: ":interrobang: ${currentBuild.projectName} :penguin: <b>Linux</b> UNSTABLE  :confused:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${env.GIT_COMMIT}" )
                    updateGitlabCommitStatus(name: 'Build linux', state: 'failed')
                }
            }
            sh "docker image rm -- meganz/megacmd-autotools-ubsan:${env.BUILD_NUMBER} meganz/megacmd-autotools-asan:${env.BUILD_NUMBER} meganz/megacmd-autotools-tsan:${env.BUILD_NUMBER} || true"
            junit "**/test-results/ubsan-*.xml"
            archiveArtifacts artifacts: "**/test-results/megacmd-*-tests-*-report.*"
        }

    }
}
