import java.util.regex.Matcher

/**
 * Pipeline to release a stable version of the Silverpeas Web Browser Edition library from a given
 * build version of the project.
 *
 * In order to get the build version, the pipeline requires the Jenkins job aimed at constructing
 * such build version to be named 'Silverpeas_WebBrowserEdition_AutoDeploy'.
 *
 * This pipeline requires the following parameters:
 * BUILD_VERSION the build version of Silverpeas Web Browser Edition from which the release has to
 * be done.
 *
 * The build is performed within a dedicated Docker image in order to ensure the reproducibility of
 * the builds and to containerize them from the host OS.
 */

// versions of the Docker image to use with the different SCM branch names of the projects
def imageVersions = [
        '1.0.x'            : '6.3.3',
        '1.1.x'            : '6.4',
        'main'             : 'latest'
]

String imageVersion = getDockerImageVersion(imageVersions)

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 {
    string(
        description: 'The build version of Silverpeas WBE from which the release has to be done',
        name: 'BUILD_VERSION'
    )
  }

  environment {
    gitRepo = 'https://github.com/Silverpeas/Silverpeas-WebBrowserEdition'
    gitCredential = 'cacc0467-7c85-41d1-bf4e-eaa470dd5e59'
    branch = getBranch()
    commit = ''
    version = ''
    nextVersion = ''
    parentVersion = ''
    silverpeasVersion = ''
    artifact = 'target/release.yaml'
  }

  stages {
    stage('Prepare the release') {
      steps {
        copyArtifacts projectName: "Silverpeas_WebBrowserEdition_AutoDeploy", flatten: true,
            selector: specific(params.BUILD_VERSION)
        script {
          def lastBuild = readYaml file: 'build.yaml'
          version = lastBuild.release
          commit = lastBuild.commit
          nextVersion = getNextVersion(version)
        }
      }
    }
    stage('Checkout the build version') {
      steps {
        git url: gitRepo, branch: branch, credentialsId: gitCredential
        sh """
          git checkout ${commit}
          git checkout -b release-${version}
          """
        script {
          def pom = readMavenPom()
          parentVersion = pom.parent.version
          silverpeasVersion = pom.properties['silverpeas.version']
        }
      }
    }
    stage('Check POM parent version') {
      when {
        expression { !isStableVersion(parentVersion) }
      }
      steps {
        error "The POM parent must be at a stable version"
      }
    }
    stage('Check Silverpeas version') {
      when {
        expression { !isStableVersion(silverpeasVersion) }
      }
      steps {
        error "The dependency on Silverpeas must be at a stable version"
      }
    }
    stage('Release') {
      environment {
        GIT_AUTH = credentials("${gitCredential}")
      }
      steps {
        sh """
          mvn -U versions:set -DgenerateBackupPoms=false -DnewVersion=${version}
          mvn clean deploy -Dmaven.test.skip=true -Pdeployment -Prelease-sign-artifacts
          git commit -am "Release of ${version} from ${params.BUILD_VERSION} (commit ${commit})"
          git tag ${version}
          """
        sh '''
          git config --local credential.helper "!f() { echo username=\\${GIT_AUTH_USR}; echo password=\\$GIT_AUTH_PSW; }; f"
          git push origin --tags
          '''
      }
    }
    stage('Create the stable branch for the new release') {
      when {
        expression { branch == 'main' }
      }
      environment {
        GIT_AUTH = credentials("${gitCredential}")
      }
      steps {
        sh """
          git checkout -b ${version}.x
          sed -i -e "s/<next.release>[0-9.]\\+/<next.release>${version}.1/g" pom.xml
          mvn -U versions:set -DgenerateBackupPoms=false -DnewVersion=${version}.1-SNAPSHOT
          mvn clean install -Dmaven.test.skip=true
          git commit -am "Prepare branch ${version}.x for bug fixes"
          """
        sh '''
          git config --local credential.helper "!f() { echo username=\\${GIT_AUTH_USR}; echo password=\\$GIT_AUTH_PSW; }; f"
          '''
        sh """
          git push origin HEAD:${version}.x
          """
      }
    }
    stage('Prepare the development of the next version') {
      environment {
        GIT_AUTH = credentials("${gitCredential}")
      }
      steps {
        sh """
          git checkout ${branch}
          sed -i -e "s/<next.release>[0-9.]\\+/<next.release>${nextVersion}/g" pom.xml
          mvn -U versions:set -DgenerateBackupPoms=false -DnewVersion=${nextVersion}-SNAPSHOT
          mvn clean install -Dmaven.test.skip=true
          git commit -am "${version} has been released from build ${params.BUILD_VERSION} (${commit}).\\
Prepare for development iteration of next version ${nextVersion}"
          """
        sh '''
          git config --local credential.helper "!f() { echo username=\\${GIT_AUTH_USR}; echo password=\\$GIT_AUTH_PSW; }; f"
          git push origin HEAD:main
          '''
      }
    }
    stage('Create YAML release report') {
      steps {
        script {
          writeYaml file: artifact, data: ['release'   : version,
                                           'from'      : ['version': params.BUILD_VERSION,
                                                          'commit' : commit.trim()],
                                           'parent'    : parentVersion,
                                           'silverpeas': silverpeasVersion]
        }
      }
    }
  }
  post {
    success {
      script {
        currentBuild.displayName = version
      }
      archiveArtifacts artifacts: artifact, fingerprint: true
    }
    always {
      step([$class                  : 'Mailer',
            notifyEveryUnstableBuild: true,
            recipients              : "miguel.moquillon@silverpeas.org, silveryocha@chastagnier.com",
            sendToIndividuals       : true])
    }
  }
}

String getBranch() {
  Matcher matcher = params.BUILD_VERSION =~ '^(\\d+.\\d+).\\d+$'
  matcher ? "${matcher[0][1]}.x" : 'main'
}

String getDockerImageVersion(imageVersions) {
  String currentBranch = getBranch()
  imageVersions[currentBranch]
}

String getNextVersion(String version) {
  String[] parts = version.split('\\.')
  "${parts[0]}.${(parts[1] as Integer) + 1}"
}

String isStableVersion(String version) {
  Matcher matcher = version =~ '^(\\d+.\\d+(.\\d)*)$'
  return matcher.matches()
}
