#!groovy

@Library('infraLib') _

def bumpVersionBranch = 'master'

pipeline {
  agent {
    label 'linux-agents'
  }

  options {
    ansiColor('xterm')
    disableConcurrentBuilds()
    disableResume()
    timeout(60)
    timestamps()
    buildDiscarder logRotator(artifactDaysToKeepStr: '',
                              artifactNumToKeepStr: '',
                              daysToKeepStr: '',
                              numToKeepStr: '15')
  }

  environment {
    PROJECT_GROUP = 'dna'

    API_PROJECT    = 'api'
    SQITCH_PROJECT = 'api-db-migrations'

    AWS_PROFILE    = 'gdb-whitelist-dev'
    AWS_ACCOUNT_ID = '814622134907'
    AWS_REGION     = 'us-east-1'

    ECR_REGISTRY               = "${env.AWS_ACCOUNT_ID}.dkr.ecr.${env.AWS_REGION}.amazonaws.com"
    API_ECR_REPOSITORY_NAME    = "${env.PROJECT_GROUP}/${env.API_PROJECT}"
    API_ECR_REGISTRY_URI       = "${env.ECR_REGISTRY}/${env.API_ECR_REPOSITORY_NAME}"
    SQITCH_ECR_REPOSITORY_NAME = "${env.PROJECT_GROUP}/${env.SQITCH_PROJECT}"
    SQITCH_ECR_REGISTRY_URI    = "${env.ECR_REGISTRY}/${env.SQITCH_ECR_REPOSITORY_NAME}"

    LOWER_ENVIRONMENT_PREFIX = "dev"
    UPPER_ENVIRONMENT_PREFIX = "uat"

    OCTOPUS_CLI_SERVER  = 'https://octopus.delphi.zone'
    OCTOPUS_CLI_API_KEY = utility.getSecretValueById('infra/jenkins/octopus_api_key', 'gdb-delphi-dev')
    OCTOPUS_CHANNEL     = octopus.setOctoChannel(env.BRANCH_NAME)
    DEPLOY_ENV          = octopus.setDeploymentEnvV4(params.DEPLOY_ENV_CHOICE,
                                                     env.PROJECT_GROUP,
                                                     env.BRANCH_NAME,
                                                     env.LOWER_ENVIRONMENT_PREFIX,
                                                     env.UPPER_ENVIRONMENT_PREFIX)
    API_OCTOPUS_PROJECT    = "${env.PROJECT_GROUP}.${env.API_PROJECT}"
    SQITCH_OCTOPUS_PROJECT = "${env.PROJECT_GROUP}.${env.SQITCH_PROJECT}"

    NOTIFICATIONS_CHANNEL = '#dna-deployments'

    PYPI_INDEX_URL = 'https://artifacts.apollo.stream/repository/pypi-all/simple'

    POSTGRES_IMAGE = '483193324480.dkr.ecr.us-east-1.amazonaws.com/postgres:13.5'
  }

  parameters {
    separator(name: "separator-dna-api-deployment",
              sectionHeader: 'Deployment parameters')
    choice(
      choices: [
        'default',
        'dev',
        'uat',
        'prod',
        'skip_deployment'
      ],
      description: 'Set environment for deployment.',
      name: 'DEPLOY_ENV_CHOICE'
    )
    choice(
      choices: [
        'default',
        'yes',
        'no'
      ],
      description: 'By default deploy is only triggered for develop/release/master branch',
      name: 'TRIGGER_DEPLOY'
    )
    choice(
      choices: [
        'error',
        'overwrite',
        'skip_build'
      ],
      description: "Docker image upload mode - overwrite if the image with such tag already exists, raise error if exists, or skip build part if exists.",
      name: 'IMAGE_UPLOAD_MODE'
    )
    choice(
      choices: [
        'no',
        'yes'
      ],
      description: "Don't raise errors in case release already exists",
      name: 'SKIP_RELEASE_CREATION'
    )
  }

  stages {
    stage('Wrapper') {
      when {
        not {
          allOf {
            changelog 'Bump version'
            branch "${bumpVersionBranch}"
          } /** end: allOf */
        } /** end: not */
      } /** end: when */
      stages {
        stage('Bump Version') {
          when {
            branch "${bumpVersionBranch}"
          } /** end: when */
          stages {
            stage('Patch') {
              when {
                changelog '#patch'
              } /** end: when */
              steps {
                sh 'make version/patch'
              } /** end: steps */
            } /** end: stage */

            stage('Minor') {
              when {
                anyOf {
                  changelog '#minor'
                  branch "${bumpVersionBranch}"
                } /** end: anyOf */
              } /** end: when */
              steps {
                sh 'make version/minor'
              } /** end: steps */
            } /** end: stage */

            stage('Major') {
              when {
                changelog '#major'
              } /** end: when */
              steps {
                sh 'make version/major'
              } /** end: steps */
            } /** end: stage */
          } /** end: stages */
          post {
            success {
              script {
                sshagent(['dna-ci-rw']) {
                  sh """
                    #!/usr/bin/env bash
                    set +x
                    export GIT_SSH_COMMAND="ssh -oStrictHostKeyChecking=no"
                    git push origin HEAD:${env.BRANCH_NAME}
                    git push origin v\$(cat VERSION)
                  """
                } /** end: sshagent */
              } /** end: script */
            } /** end: success */
          } /** end: post */
        } /** end: stage */

        stage('BuildWrapper') {
          environment {
            VERSION = octopus.getVersion(env.BRANCH_NAME,env.WORKSPACE)
          } /** end: environment */

          stages {
            stage('Build') {
              stages {
                stage('Version') {
                  steps {
                    script { currentBuild.displayName = env.VERSION }
                  } /** end: steps */
                } /** end: stage */
                stage('DB migrations') {
                  options { retry(2) }
                  steps {
                    sh "make docker/login"
                    sh "make docker/sqitch/build"
                  } /** end: steps */
                } /** end: stage */
                stage('DNA API') {
                  options { retry(2) }
                  steps {
                    sh "make docker/login"
                    sh "make docker/image/build"
                  } /** end: steps */
                } /** end: stage */
              } /** end: stages */
            } /** end: stage */

            stage('Test') {
              options { retry(2) }
              when {
                not {
                  expression { return params.SKIP_TEST }
                } /** end: not */
              } /** end: when */
              steps {
                sh label: 'test', script: '''
                  make docker/test
                '''
              } /** end: steps */
              post {
                always {
                  sh "sudo chown \$(whoami):\$(whoami) -R ${env.WORKSPACE}"
                  junit allowEmptyResults: false, testResults: "report.xml"
                  cobertura autoUpdateHealth: false,
                    autoUpdateStability: false,
                    coberturaReportFile: 'coverage.xml',
                    failUnhealthy: false,
                    failUnstable: false,
                    maxNumberOfBuilds: 0,
                    onlyStable: false,
                    zoomCoverageChart: false
                  sh 'make docker/clean'
                } /** end: always */
              } /** end: post */
            } /** end: stage */

            stage('Static') {
              when {
                not {
                  expression { return params.SKIP_STATIC }
                } /** end: not */
              } /** end: when */
              parallel {
                stage('Checkstyle') {
                  steps {
                    sh label: 'checkstyle', script: '''
                      make docker/checkstyle
                    '''
                  } /** end: steps */
                  post {
                    always {
                      sh "sudo chown \$(whoami):\$(whoami) -R ${env.WORKSPACE}"
                    } /** end: always */
                  } /** end: post */
                } /** end: stage */
                stage('Security') {
                  steps {
                    sh label: 'check dependencies', script: '''
                      make docker/security
                    '''
                  } /** end: steps */
                  post {
                    always {
                      sh "sudo chown \$(whoami):\$(whoami) -R ${env.WORKSPACE}"
                    } /** end: always */
                  } /** end: post */
                } /** end: stage */
              } /** end: parallel */
            } /** end: stage */

            stage('SonarQube Analysis') {
              when {
                allOf {
                  branch 'develop' // there is a limit to a single branch in the sonarqube community edition
                }
              }
              environment {
                SONAR_HOST_URL         = "https://sonar.delphiplatform.io"
                SONAR_PROJECT_BASE_DIR = "${env.WORKSPACE}"
                SONAR_TOKEN            = utility.getSecretValueById('infra/jenkins/common/sonar_login_token', 'gdb-infra-dev')
              }
              steps {
                script {
                  docker.image("sonarsource/sonar-scanner-cli").inside {
                    sh script: """
set +x
sonar-scanner \
  -Dsonar.projectKey=dna.api \
  -Dsonar.projectBaseDir=${env.SONAR_PROJECT_BASE_DIR} \
  -Dsonar.host.url=${env.SONAR_HOST_URL} \
  -Dsonar.login=${env.SONAR_TOKEN} \
  -Dsonar.projectVersion=${env.VERSION}
"""
                  }
                }
              } /** end: steps */
            } /** end: stage */

            stage('Deploy') {
              when {
                anyOf {
                  branch 'master'
                  branch 'develop'
                  branch comparator: 'GLOB', pattern: 'hotfix/*'
                  branch comparator: 'GLOB', pattern: 'hotfix*'
                  expression { return params.TRIGGER_DEPLOY.equals('yes') }
                } /** end: anyOf */
              } /** end: when */
              stages {
                stage('DB migrations') {
                  stages {
                    stage('Check version') {
                      when {
                        expression {
                          return params.IMAGE_UPLOAD_MODE == 'error' && octopus.ecrImageTagExists(env.VERSION,
                                                                                                  env.SQITCH_ECR_REPOSITORY_NAME,
                                                                                                  env.AWS_PROFILE)
                        } /** end: expression */
                      } /** end: when */
                      steps { error "Image with ${env.VERSION} version tag already exists. To ignore this error set IMAGE_UPLOAD_MODE parameter to overwrite or skip_build"}
                    } /** end: stage */
                    stage('Push to ECR') {
                      when {
                        expression {
                          return params.IMAGE_UPLOAD_MODE == 'overwrite' || !octopus.ecrImageTagExists(env.VERSION,
                                                                                                       env.SQITCH_ECR_REPOSITORY_NAME,
                                                                                                       env.AWS_PROFILE)
                        }
                      }
                      stages {
                        stage('Scan image') {
                          steps {
                            script {
                              octopus.prismaCloudScanImage(env.VERSION,
                                                           env.SQITCH_ECR_REPOSITORY_NAME,
                                                           env.AWS_PROFILE)
                            }
                          } /** end: steps */
                        } /** end: stage */
                        stage('Push image') {
                          steps {
                            sh label: 'push', script: '''
                              make docker/sqitch/push
                            '''
                          } /** end: steps */
                        } /** end: stage */
                      } /** end: stages */
                    } /** end: stage */
                    stage('Create a release in octopus') {
                      //Check if release already exists. If it does, raise error or skip it, based on given param
                      when {
                        expression { return params.SKIP_RELEASE_CREATION.equals('no') || !octopus.releaseExists(env.SQITCH_OCTOPUS_PROJECT,env.VERSION) }
                      }
                      steps {
                        echo octopus.createRelease(env.SQITCH_OCTOPUS_PROJECT,
                                                   env.VERSION,
                                                   env.OCTOPUS_CHANNEL)
                      } /** end: steps */
                    } /** end: stage */
                    stage('Deploy release in octopus') {
                      when {
                        not { expression { return env.DEPLOY_ENV.equals('skip_deployment') } }
                      }
                      steps {
                        echo octopus.deployRelease(env.SQITCH_OCTOPUS_PROJECT,
                                                   env.DEPLOY_ENV,
                                                   env.VERSION,
                                                   env.OCTOPUS_CHANNEL)
                      } /** end: steps */
                    } /** end: stage */
                  } /** end: stages */
                } /** end: stage */
                stage('DNA API') {
                  stages {
                    stage('Check version') {
                      when {
                        expression {
                          return params.IMAGE_UPLOAD_MODE == 'error' && octopus.ecrImageTagExists(env.VERSION,
                                                                                                  env.API_ECR_REPOSITORY_NAME,
                                                                                                  env.AWS_PROFILE)
                        } /** end: expression */
                      } /** end: when */
                      steps { error "Image with ${env.VERSION} version tag already exists. To ignore this error set IMAGE_UPLOAD_MODE parameter to overwrite or skip_build"}
                    } /** end: stage */
                    stage('Push to ECR') {
                      when {
                        expression {
                          return params.IMAGE_UPLOAD_MODE == 'overwrite' || !octopus.ecrImageTagExists(env.VERSION,
                                                                                                       env.API_ECR_REPOSITORY_NAME,
                                                                                                       env.AWS_PROFILE)
                        }
                      }
                      stages {
                        stage('Scan image') {
                          steps {
                            script {
                              octopus.prismaCloudScanImage(env.VERSION,
                                                           env.API_ECR_REPOSITORY_NAME,
                                                           env.AWS_PROFILE)
                            }
                          } /** end: steps */
                        } /** end: stage */
                        stage('Push image') {
                          steps {
                            sh label: 'push', script: '''
                              make docker/image/push
                            '''
                          } /** end: steps */
                        } /** end: stage */
                      } /** end: stages */
                    } /** end: stage */
                    stage('Upload documentation') {
                      steps {
                        script {
                          documentation.upload(env.BRANCH_NAME, env.WORKSPACE)
                        }
                      }
                    }
                    stage('Create a release in octopus') {
                      //Check if release already exists. If it does, raise error or skip it, based on given param
                      when {
                        expression { return params.SKIP_RELEASE_CREATION.equals('no') || !octopus.releaseExists(env.API_OCTOPUS_PROJECT,env.VERSION) }
                      }
                      steps {
                        echo octopus.createRelease(env.API_OCTOPUS_PROJECT,
                                                   env.VERSION,
                                                   env.OCTOPUS_CHANNEL)
                      } /** end: steps */
                    } /** end: stage */
                    stage('Deploy release in octopus') {
                      when {
                        not { expression { return env.DEPLOY_ENV.equals('skip_deployment') } }
                      }
                      steps {
                        echo octopus.deployRelease(env.API_OCTOPUS_PROJECT,
                                                   env.DEPLOY_ENV,
                                                   env.VERSION,
                                                   env.OCTOPUS_CHANNEL)
                      } /** end: steps */
                    } /** end: stage */
                  } /** end: stages */
                } /** end: stage */
              } /** end: stages */
            } /** end: stage */
          } /** end; stages */
        } /** end; stage */
      } /** end: stages */
      post {
        always {
          sh label: 'fix permissions', script: "sudo chown \$(whoami):\$(whoami) -R ${env.WORKSPACE}"
          sh label: 'shutdown containers', script: 'make docker/clean'
          script { utility.slackNotify(currentBuild.currentResult, env.NOTIFICATIONS_CHANNEL) }
        }
        cleanup { deleteDir() }
      } /** end: post */
    } /** end: stage */
  } /** end: stages */
}


