#!groovy

@Library('infraLib') _

List<String> softwareCatalogFiles = [
  "software-catalog.yaml",
  "software-catalog-celery_beat.yaml",
  "software-catalog-celery_flower.yaml",
  "software-catalog-celery_worker.yaml",
]

pipeline {
  agent {
    label 'linux-agents'
  }
  options {
    ansiColor('xterm')
    disableConcurrentBuilds()
    disableResume()
    timeout(60)
    timestamps()
    buildDiscarder logRotator(artifactDaysToKeepStr: '',
      artifactNumToKeepStr: '',
      daysToKeepStr: '',
      numToKeepStr: '15')
  }
  environment {
    AWS_PROFILE         = 'gdb-core-dev'
    PROJECT_GROUP       = 'core'
    ECR                 = '582412345909.dkr.ecr.us-east-1.amazonaws.com'
    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.setDeploymentEnv(params.DEPLOY_ENV_CHOICE, env.PROJECT_GROUP, env.BRANCH_NAME)

    PROJECT_NAME      = "atlas-um"
    WORK_DIR          = "${env.WORKSPACE}"
    ECR_REPOSITORY    = "${env.PROJECT_GROUP}/${env.PROJECT_NAME}"
    REGISTRY          = "${env.ECR}/${env.ECR_REPOSITORY}"
    VERSION           = octopus.getVersion(env.BRANCH_NAME,env.WORK_DIR)

    NOTIFICATIONS_CHANNEL = "#core-deployments"

    PYPI_INDEX_URL = "https://artifacts.apollo.stream/repository/pypi-all/simple"
  }
  parameters {
    choice(
      choices: [
        'default',
        'dev',
        'qa',
        'prod',
        'skip_deployment'
      ],
      description: 'Set environment for deployment. Development by default',
      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 - ovewrite 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'
    )
    booleanParam(
      defaultValue: true,
      description: 'Run feature tests stage',
      name: 'RUN_FEATURE_TESTS'
    )
    booleanParam(
      defaultValue: true,
      description: 'Run security check stage',
      name: 'RUN_SECURITY_CHECK'
    )
  }
  stages {
    stage('Validate Software Catalog Definition') {
      steps {
        library "jenkins-global-libraries@master"
        script {
          softwareCatalogFiles.each {file ->
            datadogSoftwareCatalogValidate(
              serviceDefinitionFilePath: file,
            )
          }
        }
      }
    }
    stage('Build') {
      stages {
        stage('Sqitch') {
          steps {
            sh "cd ${env.WORK_DIR} && make docker/login"
            sh "cd ${env.WORK_DIR} && make docker/sqitch/build"
          } /** end: steps */
        } /** end: stage */
        stage('Atlas UM') {
          steps {
            sh "cd ${env.WORK_DIR} && make docker/login"
            sh "cd ${env.WORK_DIR} && make docker/image/build"
          } /** end: steps */
        } /** end: stage */
      } /** end: stages */
    } /** end: stage */
    stage('Test') {
      stages {
        stage('Unit tests') {
          steps {
            sh "cd ${env.WORK_DIR} && make docker/test/unit"
          }
        }
        stage('Feature tests') {
          when {
            expression { return params.RUN_FEATURE_TESTS }
          }
          steps {
            sh "cd ${env.WORK_DIR} && make docker/test/feat"
          }
        }
      }
    }
    stage('Style check') {
      stages {
        stage('Linter') {
          steps {
            sh "cd ${env.WORK_DIR} && make docker/lint"
          }
        }
      }
    }
    stage('Security check') {
      when {
        expression { return params.RUN_SECURITY_CHECK }
      }
      stages {
        stage('Dependencies Check') {
          steps {
            sh "cd ${env.WORK_DIR} && make docker/dependencies-check"
          }
        }
        stage('Bandit') {
          steps {
            sh "cd ${env.WORK_DIR} && make docker/bandit"
          }
        }
      }
    }
    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=atlas.um \
  -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 {
        expression { return pythonPackage.checkBranchConditions(params.TRIGGER_DEPLOY)}
      }
      stages {
        stage('Sqitch') {
          environment {
            OCTOPUS_PROJECT = "${env.PROJECT_GROUP}.atlas-um-sqitch"
          }
          stages {
            stage('Check version') {
              when { expression { return params.IMAGE_UPLOAD_MODE == 'error' && octopus.ecrImageTagExists(env.VERSION,env.ECR_REPOSITORY,env.AWS_PROFILE) }}
              steps { error "Image with ${env.VERSION} version tag already exists. To ignore this error set IMAGE_UPLOAD_MODE parameter to overwrite or skip_build"}
            }
            stage('Push to ECR') {
              when {
                expression { return params.IMAGE_UPLOAD_MODE == 'overwrite' || !octopus.ecrImageTagExists(env.VERSION,env.ECR_REPOSITORY,env.AWS_PROFILE) }
              }
              steps {
                sh "cd ${env.WORK_DIR} && make docker/login"
                sh "cd ${env.WORK_DIR} && make docker/sqitch/push"
              }
            }
            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 == 'no' || !octopus.releaseExists(env.OCTOPUS_PROJECT,env.VERSION) }
              }
              steps {
                echo octopus.createRelease(env.OCTOPUS_PROJECT,env.VERSION,env.OCTOPUS_CHANNEL)
              }
            }
            stage('Deploy release in octopus') {
              when {
                expression { return env.DEPLOY_ENV != 'skip_deployment' }
              }
              steps {
                echo octopus.deployRelease(env.OCTOPUS_PROJECT,env.DEPLOY_ENV,env.VERSION,env.OCTOPUS_CHANNEL)
              }
            }
          }
        }
        stage('Atlas UM') {
          environment {
            OCTOPUS_PROJECT = "${env.PROJECT_GROUP}.${env.PROJECT_NAME}"
          }
          stages {
            stage('Check version') {
              when { expression { return params.IMAGE_UPLOAD_MODE == 'error' && octopus.ecrImageTagExists(env.VERSION,env.ECR_REPOSITORY,env.AWS_PROFILE) }}
              steps { error "Image with ${env.VERSION} version tag already exists. To ignore this error set IMAGE_UPLOAD_MODE parameter to overwrite or skip_build"}
            }
            stage('Scan image') {
              steps {
                script {
                  octopus.prismaCloudScanImage(env.VERSION,
                                               env.ECR_REPOSITORY,
                                               env.AWS_PROFILE)
                }
              } /** end: steps */
            } /** end: stage */
            stage('Push to ECR') {
              when {
                expression { return params.IMAGE_UPLOAD_MODE == 'overwrite' || !octopus.ecrImageTagExists(env.VERSION,env.ECR_REPOSITORY,env.AWS_PROFILE) }
              }
              steps {
                sh "cd ${env.WORK_DIR} && make docker/login"
                sh "cd ${env.WORK_DIR} && make docker/image/push"
              }
            }
            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 == 'no' || !octopus.releaseExists(env.OCTOPUS_PROJECT,env.VERSION) }
              }
              steps {
                echo octopus.createRelease(env.OCTOPUS_PROJECT,env.VERSION,env.OCTOPUS_CHANNEL)
              }
            }
            stage('Deploy release in octopus') {
              when {
                expression { return env.DEPLOY_ENV != 'skip_deployment' }
              }
              steps {
                echo octopus.deployRelease(env.OCTOPUS_PROJECT,env.DEPLOY_ENV,env.VERSION,env.OCTOPUS_CHANNEL)
              }
            }
            stage('Publish Software Catalog Definition') {
              when {
                branch 'master'
              }
              steps{
                script {
                  softwareCatalogFiles.each {file ->
                    datadogSoftwareCatalogPublish(
                      serviceDefinitionFilePath: file,
                      fetchAdditionalMetadata: false,
                    )
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  post {
    always {
      sh 'make docker/clean'
      sh "sudo chown \$(whoami):\$(whoami) -R ${env.WORKSPACE}"
      script {
        utility.slackNotify(currentBuild.currentResult, env.NOTIFICATIONS_CHANNEL)
      }
    }
    cleanup {
        deleteDir()
    }
  }
}
