#!groovy
@Library('infraLib') _

def getStaticPath() {
  return env.CHANGE_ID ? '/' : "https://${env.ENV_PREFIX}-static.decibel.stream/${env.BUILD_TIMESTAMP}/"
}

def getAWSProfile(branch) {
  return branch == "production" ? "gdb-mct-prod" : "gdb-mct-dev"
}

def getAuthStrategy(override) {
  return override.equals('yes')
}

def dynamicEnvironments = ['test1', 'test2', 'test3', 'test4', 'test5']
def envChoices = ['default'].plus(dynamicEnvironments)

def getOverriddenDockerImageTagFromLabels(override, dynamicEnvironments) {
  version = override
  if (env.CHANGE_ID) {
    pullRequest.labels.find{
      if (dynamicEnvironments.contains(it)) {
        version = it
      }
    }
  }
  return version
}

def getVersion(override, dynamicEnvironments) {
  version = getOverriddenDockerImageTagFromLabels(override, dynamicEnvironments)
  return version.startsWith('test') ? version : "${env.BRANCH_NAME}".replaceAll(/[^a-zA-Z0-9]/, '-').toLowerCase()
}

def getTaskDefinitionFamily(env_prefix, project_group, project_name, override) {
  if (env.CHANGE_ID && !override.equals('default')) {
    return "${env_prefix}-${project_group}-${project_name}-${override}"
  }
  return "${env_prefix}-${project_group}-${project_name}"
}

def getServiceName(env_prefix, project_group, project_name, override) {
  if (env.CHANGE_ID && !override.equals('default')) {
    return "${env_prefix}-${project_group}-${project_name}-${override}"
  }
  return "${env_prefix}-${project_group}-${project_name}"
}

def getPullRequestLabels() {
  if (!env.CHANGE_ID) return []

  return pullRequest.labels
}

def testSummary

pipeline {
  agent {
    label 'linux-agents-2xlarge-2exec-1'
  }

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

  parameters {
    booleanParam defaultValue: false,
                 description: 'Skip unit tests',
                 name: 'SKIP_UNIT_TEST'
    booleanParam defaultValue: false,
                 description: 'Skip UI tests',
                 name: 'SKIP_UI_TEST'
    separator(name: 'separator-decibel-api-checks', sectionHeader: 'Dynamic environments')
    choice choices: envChoices,
           description: 'Override docker image tag',
           name: 'OVERRIDDEN_DOCKER_IMAGE_TAG'
    booleanParam defaultValue: false,
             description: 'Skip unit tests',
             name: 'REMOVE_LABEL'
    choice choices: ['default', 'yes', 'no'],
           description: 'Use old auth',
           name: 'USE_OLD_AUTH'
  }


  environment {
    ENV_PREFIX     = "${mctFrontendHelpers.getEnvPrefixByBranch(env.BRANCH_NAME)}"
    PROJECT_GROUP  = "marketing"
    PROJECT        = "ui"
    AWS_REGION     = "us-east-1"
    AWS_PROFILE    = "gdb-mct-dev"
    AWS_ACCOUNT_ID = "925412343888"
    TAG            = getVersion(params.OVERRIDDEN_DOCKER_IMAGE_TAG, dynamicEnvironments)
    CLUSTER_PREFIX = "${mctFrontendHelpers.getClusterPrefixByBranch(env.BRANCH_NAME)}"
    CLUSTER        = "${env.CLUSTER_PREFIX}-${env.PROJECT_GROUP}-clu"
    SERVICE        = "${getServiceName(env.ENV_PREFIX, env.PROJECT_GROUP, env.PROJECT, env.TAG)}"
    TASK_DEF       = "${getTaskDefinitionFamily(env.ENV_PREFIX, env.PROJECT_GROUP, env.PROJECT, env.TAG)}"

    AUTH0_DOMAIN       = mctFrontendHelpers.getAuth0DomainByEnv(env.ENV_PREFIX)
    AUTH0_CLIENT_ID    = mctFrontendHelpers.getAuth0ClientIdByEnv(env.ENV_PREFIX)
    AUTH0_API_AUDIENCE = mctFrontendHelpers.getAuth0ApiAudienceByEnv(env.ENV_PREFIX)
    AMPLITUDE_KEY      = mctFrontendHelpers.getAmplitudeKeyByEnv(env.ENV_PREFIX)
    APPOLO_BASE_URL    = mctFrontendHelpers.getApolloLinkByEnv(env.ENV_PREFIX)
    LOGROCKET_KEY      = mctFrontendHelpers.getLogRocketKeyByEnv(env.ENV_PREFIX)
    SENTRY_DSN         = utility.getSecretValueById('infra/jenkins/decibel/fe/SENTRY_DSN', 'gdb-infra-dev')
    AG_GRID_KEY        = utility.getSecretValueByIdAndJsonPath('infra/jenkins/decibel/fe/AG_GRID_KEY', 'gdb-infra-dev', ".${env.ENV_PREFIX}")
    BUILD_TIMESTAMP    = sh returnStdout: true, script: "date +%s | tr -d '\n'"
    INTERCOM_ID        = mctFrontendHelpers.getIntercomIdByEnv(env.ENV_PREFIX)
    ATLAS_AUTH_URL     = mctFrontendHelpers.getAtlasAuthUrlByEnv(env.ENV_PREFIX)
    USE_OLD_AUTH       = getAuthStrategy(params.USE_OLD_AUTH)
    SPLIT_KEY          = utility.getSecretValueByIdAndJsonPath('infra/jenkins/decibel/fe/SPLIT_KEY', 'gdb-infra-dev', ".${env.ENV_PREFIX}")

    NOTIFICATIONS_CHANNEL = '#mct-deployments'
  }

  triggers {
    issueCommentTrigger('.*build me.*')
  }

  stages {
    stage('Add Label') {
      when {
        allOf {
          changeRequest()
          not { expression { return params.OVERRIDDEN_DOCKER_IMAGE_TAG.equals('default') } }
          not { expression { return params.REMOVE_LABEL } }
        } /** end: allOf */
      } /** end: when */
      steps {
        script {
          pullRequest.addLabel("${params.OVERRIDDEN_DOCKER_IMAGE_TAG}")
          pullRequest.addLabel(env.BRANCH_NAME)
        } /** end: script */
      } /** end: steps */
    } /** end: stage */
    stage('Remove Label') {
      when {
        allOf {
          changeRequest()
          not { expression { return params.OVERRIDDEN_DOCKER_IMAGE_TAG.equals('default') } }
          expression { return params.REMOVE_LABEL }
        } /** end: allOf */
      } /** end: when */
      steps {
        script {
          pullRequest.removeLabel("${params.OVERRIDDEN_DOCKER_IMAGE_TAG}")
          pullRequest.removeLabel(env.BRANCH_NAME)
        } /** end: script */
      } /** end: steps */
    } /** end: stage */
    stage('Test') {
      when {
        allOf {
          not { expression { params.SKIP_UNIT_TEST } }
          not { expression { return params.REMOVE_LABEL } }
        }
      }
      options {
        retry(2)
      }
      environment {
        JEST_JUNIT_OUTPUT_DIR = 'output'
        JEST_JUNIT_OUTPUT_NAME = 'junit.xml'
      }
      steps {
        echo "PG - ${env.PROJECT_GROUP} | ENV - ${env.ENV_PREFIX} | Project - ${env.PROJECT} | Tag - ${env.TAG}"
        sh "make docker/login/base"
        sh "make docker/test"
      }
      post {
        always {
          sh "sudo chown -R \$(whoami):\$(whoami) ${env.JEST_JUNIT_OUTPUT_DIR}"
          junit allowEmptyResults: false, testResults: "${env.JEST_JUNIT_OUTPUT_DIR}/${env.JEST_JUNIT_OUTPUT_NAME}"
          script { testSummary = utility.getTestSummary() }
          cobertura autoUpdateHealth: false,
            autoUpdateStability: false,
            coberturaReportFile: '**/output/coverage/jest/clover.xml',
            conditionalCoverageTargets: '70, 0, 0',
            failUnhealthy: false,
            failUnstable: false,
            lineCoverageTargets: '80, 0, 0',
            maxNumberOfBuilds: 0,
            methodCoverageTargets: '80, 0, 0',
            onlyStable: false,
            zoomCoverageChart: false
        }
      } /** end: post */
    } /** end: stage */

    stage('Build') {
      when {
        not { expression { return params.REMOVE_LABEL } }
      }
      environment {
        STATIC_FILES_PATH = getStaticPath()
      }
      steps {
        echo "STATIC_FILES_PATH - ${STATIC_FILES_PATH} | AWS_ACCOUNT_ID - ${AWS_ACCOUNT_ID} "
        sh "make docker/login/base"
        sh "make docker/image/build"
      }
    } /** 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=decibel.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('Deploy Static Files') {
      when {
        anyOf {
          expression { return env.BRANCH_NAME =~ /release*/ }
          expression { return mctFrontendHelpers.getBranchesToDeploy().contains(env.BRANCH_NAME) }
          allOf {
            expression { return env.TAG.startsWith('test') }
            expression { return getPullRequestLabels().contains(env.BRANCH_NAME) }
            not { expression { return params.REMOVE_LABEL } }
          }
        }
      }
      environment {
        CONTAINER_ID = sh returnStdout: true, script: "docker create ${env.AWS_ACCOUNT_ID}.dkr.ecr.${env.AWS_REGION}.amazonaws.com/${env.PROJECT_GROUP}/${env.PROJECT}:${env.TAG} | tr -d '\n'"
        BUCKET = "${mctFrontendHelpers.getBucketNamePrefixByBranch(env.BRANCH_NAME)}-${env.PROJECT_GROUP}-frontend-static"
        AWS_PROFILE = getAWSProfile(env.BRANCH_NAME)
      } /** end: environment */
      steps {
        script { utility.slackNotify("DEPLOY_STARTED", env.NOTIFICATIONS_CHANNEL, "deploy started for ${env.ENV_PREFIX}.decibel.stream") }
        sh "rm -rf ./s3_upload; mkdir -p ./s3_upload"
        sh "docker cp ${env.CONTAINER_ID}:/usr/share/nginx/html ./s3_upload/"
        sh "aws s3 sync --metadata-directive REPLACE --cache-control 'max-age=604800' --exclude index.html --size-only s3_upload/html s3://${env.BUCKET}/${env.BUILD_TIMESTAMP}/"
      } /** end: steps */
      post {
        always {
          sh "docker rm -v ${env.CONTAINER_ID}"
        }
      } /** end: post */
    } /** end: stage */

    /*
    stage('UI Smoke Test') {
      when {
        not { expression { params.SKIP_UI_TEST } }
      }
      environment {
        BASE_URL      = "http://ui"
        API_URL       = "http://api:8000"
        API_IMAGE_TAG = "develop"
        UI_IMAGE_TAG  = "${env.TAG}"
        TIMEOUT_MS    = 30000

        AUTH0_MANAGEMENT_CLIENT_ID     = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/AUTH0_MANAGEMENT_CLIENT_ID", "gdb-infra-dev")
        AUTH0_MANAGEMENT_CLIENT_SECRET = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/AUTH0_MANAGEMENT_CLIENT_SECRET", "gdb-infra-dev")
        AUTH_URL = "https://sme-dna.auth0.com/oauth/token"
        DELPHI_API_CLIENT_ID     = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/DELPHI_API_CLIENT_ID", "gdb-infra-dev")
        DELPHI_API_CLIENT_SECRET = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/DELPHI_API_CLIENT_SECRET", "gdb-infra-dev")
        USER1_PASS = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/USER1_PASS", "gdb-infra-dev")
        USER2_PASS = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/USER2_PASS", "gdb-infra-dev")
        USER3_PASS = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/USER3_PASS", "gdb-infra-dev")
        USER4_PASS = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/USER4_PASS", "gdb-infra-dev")
        USER11_PASS = utility.getSecretValueById("infra/jenkins/decibel/dev/uitest/USER11_PASS", "gdb-infra-dev")

        BROWSER_NAME       = "chrome"
        BROWSER_LATEST_TAG = sh(returnStdout: true, script: "curl -s https://registry.hub.docker.com/v1/repositories/selenoid/vnc/tags | jq -r .[].name | grep ${env.BROWSER_NAME} | tail -n1").trim()
        BROWSER_LATEST_VER = sh(returnStdout: true, script: "echo ${env.BROWSER_LATEST_TAG} | cut -f 2 -d_").trim()

        WORK_DIR = "${env.WORKSPACE}/automation"

        COMPOSE_PROJECT_NAME = "ui-test-${env.BUILD_NUMBER}"
      }
      stages {
        stage("Pull data") {
          environment {
            AWS_PROFILE = "gdb-infra-dev"
          }
          steps {
            catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
              sh label: "download pg backup", script: """
                cd ${env.WORK_DIR} && aws s3 sync \
                  s3://dev-infra-decibel-test-data/postgres/ \
                  ./docker/postgres/docker-entrypoint-initdb.d/
              """
              sh label: "download es snapshot", script: """
                cd ${env.WORK_DIR} && aws s3 sync \
                  s3://dev-infra-decibel-test-data/elasticsearch/ \
                  ./docker/elasticsearch/es-repo/
              """
              sh label: "pull video recorder", script: """
                docker pull selenoid/video-recorder:latest-release
              """
              sh label: "pull browser", script: """
                docker pull selenoid/vnc:${env.BROWSER_LATEST_TAG}
              """
              sh label: "generate browser config", script: """
                envsubst < ${env.WORK_DIR}/docker/selenoid/conf/browsers.json.template > ${env.WORK_DIR}/docker/selenoid/conf/browsers.json
              """
            }
          }
        }
        stage("Prep Data") {
          environment {
            AWS_PROFILE = "gdb-mct-dev"
          }
          steps {
            catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
              sh label: "docker login", script: """
                aws ecr get-login --no-include-email | awk '{print \$6}' | docker login -u AWS --password-stdin https://925412343888.dkr.ecr.us-east-1.amazonaws.com
              """
              sh label: "docker network", script: "docker network create selenoid || exit 0"
              sh label: "populate data", script: """
                cd ${env.WORK_DIR} && docker-compose up -d postgres redis elasticsearch selenoid
                sleep 30
                cd ${env.WORK_DIR} && docker-compose logs --tail 50 postgres
                cd ${env.WORK_DIR} && docker-compose up db_migrations
                cd ${env.WORK_DIR} && docker-compose up elasticsearch_restore
              """
            }
          }
        }
        stage("Launch API and UI") {
          steps {
            catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
              sh label: "launch API", script: """
                cd ${env.WORK_DIR} && docker-compose up -d api && docker-compose logs --tail 50 api
              """
              sh label: "launch UI", script: """
                cd ${env.WORK_DIR} && docker-compose up -d ui && docker-compose logs --tail 50 ui
              """
            }
          }
        }
        stage("Test") {
          steps {
            catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
              sh label: "test", script: """
                cd ${env.WORK_DIR} && docker-compose up tests
              """
            }
          }
          post {
            success {
              githubNotify description: "Smoke passed", status: 'SUCCESS', context: 'continuous-integration/jenkins/smoke-tests'
            }
            failure {
              githubNotify description: "Smoke failed", status: 'FAILURE', context: 'continuous-integration/jenkins/smoke-tests'
            }
            always {
              catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                sh "sudo chown -R \$(whoami):\$(whoami) ${env.WORK_DIR}/"
                allure(results: [[path: 'automation/allure-results']])
              }
            }
          }
        }
      }
      post {
        always {
          sh label: "terminate test env", script: """
            cd ${env.WORK_DIR} && docker-compose down \
            && docker volume prune -f
          """
        }
      }
    }
    */


    stage('Publish') {
      when {
        anyOf {
          expression { return env.BRANCH_NAME =~ /release*/ }
          expression { return mctFrontendHelpers.getBranchesToDeploy().contains(env.BRANCH_NAME) }
          allOf {
            expression { return env.TAG.startsWith('test') }
            expression { return getPullRequestLabels().contains(env.BRANCH_NAME) }
            not { expression { return params.REMOVE_LABEL } }
          }
        }
      }
      steps {
        sh "make docker/image/push"
      }
    } /** end: stage */

    stage('Update ECS service') {
      when {
        anyOf {
          expression { return env.BRANCH_NAME =~ /release*/ }
          expression { return mctFrontendHelpers.getBranchesToDeploy().contains(env.BRANCH_NAME) }
          allOf {
            expression { return env.TAG.startsWith('test') }
            expression { return getPullRequestLabels().contains(env.BRANCH_NAME) }
            not { expression { return params.REMOVE_LABEL } }
          }
        }
      }
      environment {
        AWS_PROFILE = getAWSProfile(env.BRANCH_NAME)
      }
      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 --cluster ${env.CLUSTER} --service ${env.SERVICE}"
      } /** end: steps */
      post {
        success {
          script { utility.slackNotify('DEPLOY_FINISHED', env.NOTIFICATIONS_CHANNEL) }
        }
        unsuccessful {
          script { utility.slackNotify('DEPLOY_FAILED', env.NOTIFICATIONS_CHANNEL) }
        }
      } /** end: post */
    } /** end: stage */
  } /** end: stages */
  post {
    always {
      script { utility.slackNotify(currentBuild.result, env.NOTIFICATIONS_CHANNEL, "build ${currentBuild.result} \n${testSummary}") }
    }
  } /** end: post */
} /** end: pipeline */
