@Library('jenkins-pipeline-shared-libraries')_

def changeAuthor = env.ghprbAuthorRepoGitUrl ? util.getGroup(env.ghprbAuthorRepoGitUrl) : (env.ghprbPullAuthorLogin ?: CHANGE_AUTHOR)
def changeBranch = env.ghprbSourceBranch ?: CHANGE_BRANCH
def changeTarget = env.ghprbTargetBranch ?: CHANGE_TARGET

BUILD_FAILED_IMAGES = []

pipeline {
    agent { 
        label 'kie-rhel8 && docker && kie-mem24g && !built-in' 
    }
    tools {
        jdk 'kie-jdk11'
        maven 'kie-maven-3.8.6'
    }
    options {
        timeout(time: 120, unit: 'MINUTES')
    }
    environment {
        CI = true

        // Linked to node label
        CONTAINER_ENGINE='docker'
        CONTAINER_ENGINE_TLS_OPTIONS=''
    }
    stages {
        stage('Initialization') {
            steps {
                script {
                    clean()

                    // Set the mirror url only if exist
                    if (env.MAVEN_MIRROR_REPOSITORY != null
                            && env.MAVEN_MIRROR_REPOSITORY != '') {
                        env.MAVEN_MIRROR_URL = env.MAVEN_MIRROR_REPOSITORY
                    }

                    githubscm.checkoutIfExists('kogito-images', changeAuthor, changeBranch, 'kiegroup', changeTarget, true)

                    //Ignore self-signed certificates if MAVEN_MIRROR_URL is defined
                    if (env.MAVEN_MIRROR_URL != '') {
                        runPythonCommand('python3 scripts/update-tests.py --ignore-self-signed-cert')
                    }

                    if (isProdCI()) {
                        // Prod fix to be able to build the image as a community one
                        sh """
                            echo '' > content_sets.yaml
                            sed -i 's|from: "registry.redhat.io/ubi8|from: "registry.access.redhat.com/ubi8|g' rhpam-kogito-*.yaml
                            sed -i 's/\\(| KOGITO_VERSION.* | .* |\\)/\\1\\n      | QUARKUS_PLUGIN | io.quarkus:quarkus-maven-plugin |\\n      | QUARKUS_PLATFORM_GROUP_ID | io.quarkus.platform |/g' tests/features/*.feature
                            git diff
                        """
                    }
                }
            }
        }
        stage('Validate CeKit Image and Modules descriptors') {
            steps {
                script {
                    sh '''
                        curl -Ls https://github.com/kiegroup/kie-cloud-tools/releases/download/v1.3.4/cekit-image-validator-runner.tgz --output cekit-image-validator-runner.tgz
                        tar -xzvf cekit-image-validator-runner.tgz
                        chmod +x cekit-image-validator-runner
                    '''
                    sh './cekit-image-validator-runner modules/'
                    sh './cekit-image-validator-runner image.yaml'
                    getImages().each { image -> sh "./cekit-image-validator-runner ${image}-overrides.yaml" }
                }
            }
        }
        stage('Prepare offline kogito-examples') {
            steps {
                runPythonCommand('make clone-repos')
            }
        }
        stage('Build & Test Images') {
            steps {
                script {
                    parallelStages = [:]
                    getImages().each { image ->
                        initWorkspace(image)
                        String workspacePath = getWorkspacePath(image)
                        parallelStages["Build&Test ${image}"] = {
                            stage("Build ${image}") {
                                try {
                                    dir(workspacePath) {
                                        buildImage(image)
                                    }
                                } catch (err) {
                                    registerBuildFailedImage(image)
                                    util.archiveConsoleLog(image)
                                    throw err
                                }
                            }
                            stage("Test ${image}") {
                                dir(workspacePath) {
                                    try {
                                        testImage(image)
                                    } catch (err) {
                                        echo "Testing error(s) for image ${image}"
                                    } finally {
                                        junit testResults: 'target/test/results/*.xml', allowEmptyResults: true
                                        archiveArtifacts artifacts: 'target/test/results/*.xml', allowEmptyArchive: true
                                    }
                                }
                            }
                        }
                    }
                    parallel parallelStages
                }
            }
            post {
                always {
                    script {
                        cleanWorkspaces()
                    }
                }
            }
        }
    }
    post {
        always {
            script {
                clean()
            }
        }
        unsuccessful {
            script {
                def additionalInfo = ''
                if (getBuildFailedImages()){
                    additionalInfo += 'Build failures on those images:\n'
                    getBuildFailedImages().each {
                        additionalInfo += "- ${it}\n"
                    }
                }
                pullrequest.postComment(util.getMarkdownTestSummary('PR', additionalInfo, "${BUILD_URL}", 'GITHUB'))
            }
        }
    }
}

void clean() {
    cleanWorkspaces()
    cleanImages()

    // Clean Cekit cache, in case we reuse an old node
    sh "rm -rf \$HOME/.cekit/cache"
}

void cleanImages() {
    sh "docker rm -f \$(docker ps -a -q) || date"
    sh "docker rmi -f \$(docker images -q) || date"
}

void launchParallelForEachImage(stageNamePrefix, executeOnImage) {
    parallelStages = [:]
    getImages().each { image ->
        parallelStages["${stageNamePrefix} ${image}"] = {
            dir(getWorkspacePath(image)) {
                executeOnImage(image)
            }
        }
    }
    parallel parallelStages
}

void buildImage(String imageName) {
    runPythonCommand("make build-image ${getMakeBuildImageArgs()} image_name=${imageName} ignore_test=true ignore_tag=${isProdCI()}")
}

void testImage(String imageName) {
    runPythonCommand("make build-image ${getMakeBuildImageArgs()} image_name=${imageName} ignore_build=true ignore_tag=${isProdCI()}")
}

String getMakeBuildImageArgs() {
    List args = [ "cekit_option='--work-dir .'" ]
    args.add("BUILD_ENGINE=${CONTAINER_ENGINE}")
    if (env.CONTAINER_ENGINE_TLS_OPTIONS) {
        args.add("BUILD_ENGINE_TLS_OPTIONS=${CONTAINER_ENGINE_TLS_OPTIONS}")   
    }
    return args.join(' ')
}

void registerBuildFailedImage(String imageName) {
    lock("${BUILD_URL} build failed") {
        BUILD_FAILED_IMAGES.add(imageName)
    }
}

List getBuildFailedImages() {
    return BUILD_FAILED_IMAGES
}

void initWorkspace(String image) {
    sh "mkdir -p ${getWorkspacePath(image)}"
    sh "rsync -av --progress . ${getWorkspacePath(image)} --exclude workspaces"
}

void cleanWorkspaces() {
    sh "rm -rf ${getWorkspacesPath()}"
}

String getWorkspacesPath() {
    return "${WORKSPACE}/workspaces"
}

String getWorkspacePath(String image) {
    return "${getWorkspacesPath()}/${image}"
}

String[] getImages() {
    if (isProdCI()) {
        return [ 
            'rhpam-kogito-builder-rhel8', 
            'rhpam-kogito-runtime-jvm-rhel8', 
            'rhpam-kogito-runtime-native-rhel8' 
        ]
    }
    return [ 'kogito-builder', 'kogito-runtime-jvm', 'kogito-runtime-native' ]
}

void runPythonCommand(String cmd, boolean stdout = false) {
    return sh(returnStdout: stdout, script: """
source ~/virtenvs/cekit/bin/activate 
${cmd}
""")
}

boolean isProdCI() {
    return env.PROD_CI ? env.PROD_CI.toBoolean() : false
}
