#!groovy

@Library('infraLib') _

def BRANCHES_TO_DEPLOY = [
    "staging", "qa", "production"
]

pipeline {
  agent {
    label 'linux-agents'
  }

  options {
    ansiColor('xterm')
    disableConcurrentBuilds()
  }

  environment {
    DEPLOY_TO_TEST = "${params.DEPLOY_TO_TEST || (utility.getGithubComment() == 'deploy me')}"
    ENV_PREFIX     = "${env.DEPLOY_TO_TEST == 'true' ? 'dev' : filtrAdminHelpers.getEnvPrefixByBranch(env.BRANCH_NAME)}"
    PROJECT        = "${env.DEPLOY_TO_TEST == 'true' ? 'apolloapp-test' : 'apolloapp'}"
    PROJECT_GROUP  = "apollo"
    REPOSITORY     = "apolloapp"
    CLUSTER        = "${env.ENV_PREFIX}-${env.PROJECT_GROUP}-clu"
    SERVICE        = "${env.ENV_PREFIX}-${env.PROJECT_GROUP}-${env.PROJECT}"
    TASK_DEF       = "${env.ENV_PREFIX}-${env.PROJECT_GROUP}-${env.PROJECT}"
    TAG            = "${env.DEPLOY_TO_TEST == 'true' ? 'test' : env.BRANCH_NAME}"
    BUCKET         = "${env.DEPLOY_TO_TEST == 'true' ? 'dev-apollo-new-ui-test' : "${env.ENV_PREFIX}-${env.PROJECT_GROUP}-new-ui"}"
    STATIC_ROOT    = "${env.DEPLOY_TO_TEST == 'true' ? "https://test-static.apollo.stream/static" : "https://${env.ENV_PREFIX}-static.apollo.stream/static"}"

    SENTRY_DSN          = utility.getSecretValueById('infra/jenkins/apollo/common/apolloapp/SENTRY_DSN', 'gdb-delphi-dev')
    SENTRY_AUTH_TOKEN   = utility.getSecretValueById('infra/jenkins/apollo/common/apolloapp/SENTRY_AUTH_TOKEN', 'gdb-delphi-dev')
    SENTRY_RELEASE_NAME = "${sh returnStdout: true, script: 'git rev-parse --short HEAD'}".trim()

    AUTH0_DOMAIN        = "${filtrAdminHelpers.getAuth0DomainByBranch(env.BRANCH_NAME)}"
    AUTH0_CLIENT_ID     = "${filtrAdminHelpers.getAuth0ClientIdByBranch(env.BRANCH_NAME)}"
    AUTH0_API_AUDIENCE  = "${filtrAdminHelpers.getAuth0ApiAudienceByBranch(env.BRANCH_NAME)}"

    DUPLICATIONAPI_URI = "${filtrAdminHelpers.getDuplicationApiUriByBranch(env.BRANCH_NAME)}"

    NOTIFICATIONS_CHANNEL = '#apollo-deployments'
  }

  parameters {
    string(name: 'ECR',
           defaultValue: '475275892927.dkr.ecr.us-east-1.amazonaws.com',
           description: 'Docker images repository.')
    booleanParam(name: 'DEPLOY_TO_TEST',
                 defaultValue: false,
                 description: 'Deploy this build to test environment')
    booleanParam(name: 'SKIP_TESTS',
                 defaultValue: false,
                 description: 'Skip tests')
  }

  triggers {
    issueCommentTrigger('.*build me.*|.*deploy me.*')
  }
  stages {
    stage('Build container') {
      steps {
        echo "Using tag ${params.ECR}/${env.REPOSITORY}:${env.TAG}"
        echo "PG - ${env.PROJECT_GROUP} | ENV - ${env.ENV_PREFIX} | Project - ${env.PROJECT}"
        echo "service ${env.SERVICE} | task-definition ${env.TASK_DEF} | cluster ${env.CLUSTER}"
        echo "S3 ${env.BUCKET} | Static ${env.STATIC_ROOT}"
        echo "Auth0 | Domain: ${env.AUTH0_DOMAIN} Audience: ${env.AUTH0_API_AUDIENCE} Client ID: ${env.AUTH0_CLIENT_ID}"
        sh "make docker/build"
      } /** end: steps */
    } /** end: stage */
    stage('Test') {
      when {
        not { expression { return params.SKIP_TESTS } }
      } /** end: when */
      steps {
        sh "make test"
      } /** end: steps */
    } /** 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=apollo.web-app \
  -Dsonar.projectBaseDir=${env.SONAR_PROJECT_BASE_DIR} \
  -Dsonar.host.url=${env.SONAR_HOST_URL} \
  -Dsonar.login=${env.SONAR_TOKEN}
"""
          }
        }
      } /** end: steps */
    } /** end: stage */
    stage('Upload docker image') {
      environment {
        AWS_PROFILE = 'gdb-delphi-dev'
      } /** end: environment */
      when {
        anyOf {
          expression { return BRANCHES_TO_DEPLOY.contains(env.BRANCH_NAME) }
          expression { return env.DEPLOY_TO_TEST.toBoolean() }
        } /** end: anyOf */
      } /** end: when */
      steps {
        sh "make docker/push"
      } /** end: steps */
    } /** end: stage */
    stage('Upload static files to s3') {
      when {
        anyOf {
          expression { return BRANCHES_TO_DEPLOY.contains(env.BRANCH_NAME) }
          expression { return env.DEPLOY_TO_TEST.toBoolean() }
        } /** end: anyOf */
      } /** end: when */
      environment {
        CONTAINER_ID = sh returnStdout: true, script: "docker create ${params.ECR}/${env.REPOSITORY}:${env.TAG} | tr -d '\n'"
      } /** end: environment */
      stages {
        stage ('Nofity') {
          steps {
            slackSend channel: "${env.NOTIFICATIONS_CHANNEL}",
              color: 'warning',
              iconEmoji: ':rocket:',
              username: 'Deploy',
              message: "started deployment for ${env.JOB_NAME} <${env.BUILD_URL}|Open>"
          } /** end: steps */
        } /** end: stage */
        stage('Prepare files') {
          steps {
            sh "rm -rf ./s3_upload; mkdir -p ./s3_upload"
            sh "docker cp ${env.CONTAINER_ID}:/usr/src/static ./s3_upload/"
            sh "ls ./s3_upload/"
            sh "docker rm -v ${env.CONTAINER_ID}"
          } /** end: steps */
        } /** end: stage */
        stage('Upload') {
          parallel {
            stage('gdb-apollo-dev') {
              when {
                anyOf {
                  branch 'develop'
                  branch 'qa'
                  branch 'staging'
                  expression { return env.DEPLOY_TO_TEST.toBoolean() }
                } /** end: anyOf */
              } /** end: when */
              environment {
                AWS_PROFILE = 'gdb-apollo-dev'
                BUCKET      = "${env.DEPLOY_TO_TEST == 'true' ? 'dev-apollo-new-ui-test' : env.ENV_PREFIX.plus('-apollo-new-ui')}"
              } /* end: environment */
              steps {
                sh "aws s3 sync s3_upload/static s3://${env.BUCKET}/static --size-only --delete"
              } /** end: steps */
            } /** end: stage */
            stage('gdb-apollo-prod') {
              when {
                anyOf {
                  branch 'uat'
                  branch 'production'
                } /** end: anyOf */
              } /** end:  when */
              environment {
                AWS_PROFILE = 'gdb-apollo-prod'
                BUCKET      = "${env.ENV_PREFIX.plus('-apollo-new-ui')}"
              } /** end: environment */
              steps {
                sh "aws s3 sync s3_upload/static s3://${env.BUCKET}/static --size-only --delete"
              } /** end: steps */
            } /** end: stage */
          } /** end: parallel */
        } /** end: stage */
        stage('Invalidate cache') {
          when {
            branch 'production'
          } /** end: when */
          environment {
            AWS_PROFILE = 'gdb-apollo-prod'
          } /** end: environment */
          steps {
            sh label: 'font cache invalidation',
               script: '''
                aws cloudfront create-invalidation \
                    --distribution-id ESVCLQOMQ2DYX \
                    --paths "/static/build/fonts/*"
            '''
          } /** end: steps */
        } /** end: stage */
      } /** end: stages */
      post {
        unsuccessful {
          slackSend channel: "${env.NOTIFICATIONS_CHANNEL}",
            color: 'danger',
            iconEmoji: ':warning:',
            username: 'Deploy',
            message: "deploy failed for ${env.JOB_NAME} <${env.BUILD_URL}|Open>"
        } /** end: unsuccessful */
      } /** end: post */
    } /** end: stage */
    stage('Update ECS service') {
      when {
        anyOf {
          expression { return BRANCHES_TO_DEPLOY.contains(env.BRANCH_NAME) }
          expression { return env.DEPLOY_TO_TEST.toBoolean() }
        }
      }
      parallel {
        stage('gdb-apollo-dev') {
          when {
            anyOf {
              branch 'develop'
              branch 'qa'
              branch 'staging'
              expression { return env.DEPLOY_TO_TEST.toBoolean() }
            }
          }
          environment {
            AWS_PROFILE = 'gdb-apollo-dev'
          }
          steps {
            sh "aws ecs update-service --service ${env.SERVICE} --force-new-deployment --task-definition ${env.TASK_DEF} --cluster ${env.CLUSTER}"
            sh "aws ecs wait services-stable --service ${env.SERVICE} --cluster ${env.CLUSTER}"
          }
        }
        stage('gdb-apollo-prod') {
          when {
            anyOf {
              branch 'uat'
              branch 'production'
            }
          }
          environment {
            AWS_PROFILE = 'gdb-apollo-prod'
          }
          steps {
            sh "aws ecs update-service --service ${env.SERVICE} --force-new-deployment --task-definition ${env.TASK_DEF} --cluster ${env.CLUSTER}"
            sh "aws ecs wait services-stable --service ${env.SERVICE} --cluster ${env.CLUSTER}"
          }
        }
      }
      post {
        success {
          slackSend channel: "${env.NOTIFICATIONS_CHANNEL}",
            color: 'good',
            iconEmoji: ':tada:',
            username: 'Deploy',
            message: "successfully finished deployment for ${env.JOB_NAME} <${env.BUILD_URL}|Open>"
        }
        unsuccessful {
          slackSend channel: "${env.NOTIFICATIONS_CHANNEL}",
            color: 'danger',
            iconEmoji: ':warning:',
            username: 'Deploy',
            message: "deploy failed for ${env.JOB_NAME} <${env.BUILD_URL}|Open>"
        }
      }
    }
  }
  post {
    always {
      script {
        utility.slackNotify(currentBuild.currentResult, env.NOTIFICATIONS_CHANNEL)
      }
    }
  }
}
