import java.util.regex.Matcher

/**
 * Pipeline to construct a build version of Silverpeas Mobile. The execution of the pipeline depends
 * on the latest successful build version of Silverpeas as it fetches the build result report
 * from the successful Jenkins job in order to update correctly its dependencies on both Silverpeas
 * Core and Silverpeas Components. As the version lifecycle of the project can differ from the
 * Silverpeas one, this pipeline releases a version timestamped with the date of the build;
 * meaning this build version can be as well as the same of the latest one of Silverpeas than it can
 * be different.
 *
 * This pipeline expects the following environment variables to be set:
 * STABLE_BRANCH     the SCM branch in which the current stable version of the project is currently
 *                   maintained
 * IMAGE_FOR_STABLE  the version of the Docker image to be used by this pipeline for stable version
 *                   of the project.
 *
 * Because this pipeline is based upon some convention rules, some expectations have to be
 * fulfilled:
 * Jenkins Job name : the name of the Jenkins job executing this pipeline has to be named as
 *                    '[ANY WORD]_[TYPE_BRANCH]_[ANY WORD]' with TYPE_BRANCH the type of the SCM
 *                    branch: 'Master' for the current development version, 'Stable' for the current
 *                    stable version, the project's branch name for older stable versions.
 * Dependent Jenkins job name: the name of the job producing a build version of Silverpeas upon
 *                             which this project depend must be formatted as
 *                             Silverpeas_[TYPE_BRANCH]_AutoDeploy with TYPE_BRANCH the type of
 *                             the SCM branch: 'Master' for the current development version,
 *                             'Stable' for the current stable version, the project's branch name
 *                             for older stable versions.
 *
 * This pipeline requires the following parameters:
 * SKIP_TEST     (optional) a boolean indicating if the execution of the test should be skipped.
 *               False by default.
 */

// versions of the Docker image to use with the different SCM branch names of the projects
def imageVersions = [
        '6.1.x' : '6.1',
        '6.2.x' : '6.2.1',
        '6.3.x' : '6.3.3',
        '6.4.x' : '6.4',
        'master': 'latest'
]

// SCM branches of Silverpeas for which CI is managed in a old way
def versions_for_old_ci = ['6.1.x', '6.2.x']

String branchType = getBranchTypeFromJobName()
String branch = getBranch(branchType)
String imageVersion = getDockerImageVersion(imageVersions, branch)

pipeline {

    agent {
        docker {
            image "silverpeas/silverbuild:${imageVersion}"
            args '''
          -v $HOME/.m2/settings.xml:/home/silverbuild/.m2/settings.xml 
          -v $HOME/.m2/settings-security.xml:/home/silverbuild/.m2/settings-security.xml 
          -v $HOME/.gitconfig:/home/silverbuild/.gitconfig 
          -v $HOME/.ssh:/home/silverbuild/.ssh 
          -v $HOME/.gnupg:/home/silverbuild/.gnupg
          '''
        }
    }

    parameters {
        booleanParam(
                defaultValue: false,
                description: 'Flag indicating if the execution of the tests should be skipped',
                name: 'SKIP_TEST'
        )
    }

    environment {
        nexusRepo = 'https://nexus3.silverpeas.org/repository/builds'
        gitRepo = 'https://github.com/Silverpeas/silverpeasmobile'
        gitCredential = 'cacc0467-7c85-41d1-bf4e-eaa470dd5e59'
        parentVersion = ''
        buildVersion = ''
        previousBuildVersion = ''
        release = ''
        silverpeasVersion = ''
        pom = null
        triggerBuild = null
        artifact = 'target/build.yaml'
    }

    stages {
        stage('Resolve dependency on Silverpeas') {
            steps {
                script {
                    echo "Working on branch ${branch}"
                    String silverpeasJobName = "Silverpeas_${branchType}_AutoDeploy"
                    copyArtifacts projectName: silverpeasJobName, flatten: true
                    def silverpeasBuild = readYaml file: 'build.yaml'
                    parentVersion = silverpeasBuild.parent
                    silverpeasVersion = silverpeasBuild.version
                    sh 'rm -f build.yaml'
                }
                echo "Parent version is ${parentVersion}"
                echo "Silverpeas version is ${silverpeasVersion}"
            }
        }
        stage('Prepare the project') {
            steps {
                git credentialsId: gitCredential,
                        branch: branch,
                        url: gitRepo
                script {
                    copyArtifacts projectName: env.JOB_NAME, flatten: true
                    def mobileBuild = readYaml file: 'build.yaml'
                    previousBuildVersion = mobileBuild.version
                    String previousCommit = mobileBuild.commit
                    String currentCommit = sh script: 'git rev-parse HEAD', returnStdout: true
                    String commit = currentCommit.trim()
                    echo "Current commit is ${commit} and last build commit is ${previousCommit}"
                    triggerBuild = (silverpeasVersion > previousBuildVersion) ||
                            (commit != previousCommit)
                }
                script {
                    pom = readMavenPom()
                    release = pom.properties['next.release']
                    buildNumber = (new Date()).format('yyMMdd')
                    buildVersion = "${release}-build${buildNumber}"
                    if (triggerBuild) {
                        echo "Build version will be ${buildVersion}"
                    } else {
                        echo 'No changes and no update in Silverpeas since the last build'
                    }
                }
            }
        }
        stage('Build the project') {
            when {
                expression { triggerBuild }
            }
            stages {
                stage('Check POM parent version') {
                    when {
                        expression { pom.parent.version.contains('SNAPSHOT') }
                    }
                    steps {
                        error "The parent POM must be at a stable or a build version for this project to be deployed. Current version is ${pom.parent.version}"
                    }
                }
                stage('Update POM parent') {
                    when {
                        expression {
                            !pom.parent.version.matches(/[0-9.]+/) && parentVersion && pom.parent.version != parentVersion
                        }
                    }
                    steps {
                        withCredentials([usernamePassword(credentialsId: gitCredential,
                                usernameVariable: 'GIT_AUTH_USR', passwordVariable: 'GIT_AUTH_PSW')]) {
                            sh '''
          git config --local credential.helper "!f() { echo username=\\${GIT_AUTH_USR}; echo password=\\$GIT_AUTH_PSW; }; f"
          '''
                            sh """
          mvn -U versions:update-parent -DgenerateBackupPoms=false -DparentVersion="[${parentVersion}]"
          git commit -am "Update parent POM to version ${parentVersion}"
          git push origin HEAD:${branch}
          """
                        }
                    }
                }
                stage('Update dependency on Silverpeas') {
                    when {
                        expression {
                            pom.properties['silverpeas.version'] != silverpeasVersion
                        }
                    }
                    steps {
                        withCredentials([usernamePassword(credentialsId: gitCredential,
                                usernameVariable: 'GIT_AUTH_USR', passwordVariable: 'GIT_AUTH_PSW')]) {
                            sh '''
          git config --local credential.helper "!f() { echo username=\\${GIT_AUTH_USR}; echo password=\\$GIT_AUTH_PSW; }; f"
          '''
                            sh """
          sed -i -e "s/<silverpeas.version>[0-9a-zA-Z.-]\\+/<silverpeas.version>${silverpeasVersion}/g" pom.xml
          git commit -am "Update dependency on Silverpeas to version ${silverpeasVersion}"
          git push origin HEAD:${branch}
          """
                        }
                    }
                }
                stage('Build and Publish') {
                    steps {
                        script {
                            String skipTest = params.SKIP_TEST ? '-Dmaven.test.skip=true' : ''
                            sh "mvn -U versions:set -DgenerateBackupPoms=false -DnewVersion=${buildVersion}"
                            if (versions_for_old_ci.contains(branch)) {
                                sh "mvn clean deploy -DaltDeploymentRepository=silverpeas::default::${nexusRepo} -Pdeployment -Pcoverage ${skipTest} -Djava.awt.headless=true -Dcontext=ci"
                            } else {
                                sh """
              /opt/wildfly-for-tests/wildfly-*.Final/bin/standalone.sh -c standalone-full.xml &> /dev/null &
              mvn clean deploy -DaltDeploymentRepository=silverpeas::default::${nexusRepo} -Pdeployment -Pcoverage  ${skipTest} -Djava.awt.headless=true -Dcontext=ci
              /opt/wildfly-for-tests/wildfly-*.Final/bin/jboss-cli.sh --connect :shutdown
              """
                            }
                        }
                    }
                }
            }
        }
        stage('Create YAML build report') {
            steps {
                script {
                    sh 'mkdir -p target'
                    if (triggerBuild) {
                        sh 'rm -f build.yaml'
                        String commit = sh script: 'git rev-parse HEAD', returnStdout: true
                        writeYaml file: artifact, data: ['version'   : buildVersion,
                                                         'parent'    : parentVersion,
                                                         'silverpeas': silverpeasVersion,
                                                         'release'   : release,
                                                         'commit'    : commit.trim(),
                                                         'tested'    : !params.SKIP_TEST]
                    } else {
                        sh 'mv build.yaml target/'
                    }
                }
            }
        }
    }
    post {
        success {
            script {
                currentBuild.displayName = triggerBuild ? buildVersion : previousBuildVersion
            }
            archiveArtifacts artifacts: artifact, fingerprint: true
        }
        always {
            step([$class                  : 'Mailer',
                  notifyEveryUnstableBuild: true,
                  recipients              : "miguel.moquillon@silverpeas.org, silveryocha@chastagnier.com, sebastien.vuillet@silverpeas.org",
                  sendToIndividuals       : true])
        }
    }
}

String getBranchTypeFromJobName() {
    Matcher matcher = env.JOB_NAME =~ /.+_([\-a-zA-Z0-9.]+)_.+/
    String type = (matcher.matches() ? matcher[0][1] : '')
    if (type == '') {
        error 'The Jenkins job is misnamed! Expecting to find the branch type in it'
    }
    return type;
}

String getBranch(String branchType) {
    String typeInLowerCase = branchType.toLowerCase()
    return typeInLowerCase == 'stable' ? env.STABLE_BRANCH : typeInLowerCase
}

String getDockerImageVersion(imageVersions, branch) {
    Matcher matcher = branch =~ '^(\\d+.\\d+\\..*)$'
    matcher ? imageVersions["${matcher[0][1]}"] : imageVersions[branch]
}