import java.util.regex.Matcher

/**
 * Pipeline to construct and to register a Docker image dedicated to the build of Silverpeas
 * projects.
 *
 * Some parameters for this pipeline are required as they are used as arguments in the image building.
 * The version of the Docker image to build is also provided as a parameter for this pipeline.
 *
 * Whatever the version of the image to build, the latest Dockerfile (the one in the branch
 * "master" will be used). Any Docker image tagged with the same version will be overridden by the
 * the new Docker image.
 *
 * It requires the following parameters:
 * IMAGE_VERSION      the version number of the image to build. The version of the image should
 *                    match the version number of the Silverpeas platform for which the projects
 *                    will be built. For the next major or minor version of the Silverpeas platform
 *                    in development, 'latest' is the recommended choice. Accepts only versions
 *                    in 2 digits (the extra digits are removed).
 * WILDFLY_VERSION    the version of Wildfly prepared for running the integration tests
 * JAVA_VERSION       the version of Java on which the Silverpeas platform is based.
 * SONAR_JAVA_VERSION the version of Java on which the Sonar analysis tool should be run.
 */
pipeline {

  agent any

  parameters {
    string(
        description: 'Version of Wildfly to use in integration tests',
        name: 'WILDFLY_VERSION'
    )
    string(
        defaultValue: '11',
        description: 'Version of Java to build a Silverpeas project',
        name: 'JAVA_VERSION'
    )
    string(
        defaultValue: '17',
        description: 'Version of Java to run a Sonar static quality analysis',
        name: 'SONAR_JAVA_VERSION'
    )
    string(
        defaultValue: 'latest',
        description: 'Version of the Docker image to build. Should match the Silverpeas version or ' +
            'latest for the current major or minor version of Silverpeas in development',
        name: 'IMAGE_VERSION'
    )
  }

  environment {
    registryCredential = 'dockerhub-mmoquillon'
    gitRepo = 'https://github.com/Silverpeas/docker-silverpeas-build'
    gitCredential = 'cacc0467-7c85-41d1-bf4e-eaa470dd5e59'
    imageName = 'silverpeas/silverbuild'
    imageTag = normalizeTag(params.IMAGE_VERSION)
  }

  stages {
    stage('Check the Docker image version to build') {
      when {
        expression { !isVersionCorrect() }

      }
      steps {
        error "Image version not accepted: ${params.IMAGE_VERSION}"
      }
    }
    stage('Checkout the project') {
      steps {
        git([url: gitRepo, credentialsId: gitCredential])
      }
    }
    stage ('Switch branch for non-latest version') {
      when {
        expression { params.IMAGE_VERSION != 'latest' }
      }
      steps {
        // for each Docker image for a stable version of Silverpeas, we should have a dedicated
        // branch because the build of a Silverpeas project in that version can depend on the libs
        // of the underlying OS in the Docker image. The limitation here is when such OS isn't
        // anymore supported and hence provided in Docker Hub.
        sh """
          git branch -r | echo ${imageTag}.x &> /dev/null
          if [ \$? -eq 0 ]; then git switch ${imageTag}.x; else git checkout -b ${imageTag}; git push origin HEAD:${imageTag}.x; endif
        """
      }
    }
    stage('Update current latest version') {
      environment {
        GIT_AUTH = credentials("${gitCredential}")
      }
      when {
        expression { params.IMAGE_VERSION == 'latest' }
      }
      steps {
        script {
          String buildNb = sh script: 'grep -oP "(?<=build=)\\d+" Dockerfile', returnStdout: true
          String status = sh script: """
            sed -i -e "s/WILDFLY_VERSION=[0-9.]\\+/WILDFLY_VERSION=${params.WILDFLY_VERSION}/g" Dockerfile
            sed -i -e "s/JAVA_VERSION=[0-9]\\+/JAVA_VERSION=${params.JAVA_VERSION}/g" Dockerfile
            sed -i -e "s/SONAR_JAVA_VERSION=[0-9]\\+/SONAR_JAVA_VERSION=${params.SONAR_JAVA_VERSION}/g" Dockerfile
            sed -i -e "s/version=[0-9.]\\+/version=${params.IMAGE_VERSION}/g" Dockerfile
            git diff --quiet
            """, returnStatus: true
          if (status == '1') {
            sh """
              sed -i -e "s/build=.\\+/build=${(buildNb as int) + 1}/g" Dockerfile
              git commit -am "Upgrade for Wildfly ${params.WILDFLY_VERSION} and Java ${params.JAVA_VERSION}"
              git push origin HEAD:master
              """
          }
        }
      }
    }
    stage('Publish stable version') {
      when {
        expression { params.IMAGE_VERSION != 'latest' }
      }
      steps {
        script {
          def tag = normalizeTag(params.IMAGE_VERSION)
          def dockerImage = docker.build("${imageName}:${tag}",
            "--build-arg WILDFLY_VERSION=${params.WILDFLY_VERSION} " +
                "--build-arg JAVA_VERSION=${params.JAVA_VERSION} " +
                "--build-arg SONAR_JAVA_VERSION=${params.SONAR_JAVA_VERSION} " +
                " .")
          docker.withRegistry('', registryCredential) {
            dockerImage.push()
          }
        }
      }
    }
    stage('Publish latest version') {
      when {
        expression { params.IMAGE_VERSION == 'latest' }
      }
      steps {
        script {
          def dockerImage = docker.build "${imageName}:latest"
          docker.withRegistry('', registryCredential) {
            dockerImage.push()
          }
        }
      }
    }
  }
  post {
    success {
      script {
        currentBuild.displayName = params.IMAGE_VERSION
      }
    }
    always {
      step([$class                  : 'Mailer',
            notifyEveryUnstableBuild: true,
            recipients              : "miguel.moquillon@silverpeas.org, silveryocha@chastagnier.com",
            sendToIndividuals       : true])
    }
  }
}

boolean isVersionCorrect() {
  if (params.IMAGE_VERSION == 'latest') {
    return true
  }
  Matcher matcher = params.IMAGE_VERSION =~ '^(\\d+.\\d+(.\\d+)?)$'
  return matcher.matches()
}

/**
 * Gets from the specified version the correct expected Docker image tag. The Docker image tag
 * will be in two digits. For example, for a version '6.4.2', the Docker image tag will be '6.4'.
 * @param version the version of the current docker image to build (id est its tag).
 * @return the normalized Docker image tag (in two digits)
 */
boolean normalizeTag(version) {
  Matcher matcher = version =~ '^(\\d+.\\d+)..+$'
  matcher ? matcher[0][1] : version
}