/*
Config mandatory properties:
octopus_project
package_id

Optional properties (= default value):
slack_channel   (= "delphi-etl-cicd-alerts")
aws_profile     (= "gdb-delphi-dev")
build_timeout   (= 20)
agent_type      (= "linux-agents-xlarge")
sbt_image       (= '475275892927.dkr.ecr.us-east-1.amazonaws.com/sbt:1.3.3')
project_group   (= 'delphi')
enable_git_tags (= false)
scala_version   (= 2.11)
*/

def call(body) {
  def config = [:]
  body.resolveStrategy = Closure.DELEGATE_FIRST
  body.delegate = config
  body()
  // Set defaults
  if ( !config.containsKey("slack_channel") )   {config.slack_channel   = "delphi-etl-cicd-alerts"}
  if ( !config.containsKey("aws_profile") )     {config.aws_profile     = "gdb-delphi-dev"}
  if ( !config.containsKey("build_timeout") )   {config.build_timeout   = 20}
  if ( !config.containsKey("agent_type") )      {config.agent_type      = 'linux-agents-xlarge'}
  if ( !config.containsKey("sbt_image") )       {config.sbt_image       = '475275892927.dkr.ecr.us-east-1.amazonaws.com/sbt:1.3.3'}
  if ( !config.containsKey("project_group") )   {config.project_group   = 'delphi'}
  if ( !config.containsKey("enable_git_tags") ) {config.enable_git_tags = false}
  if ( !config.containsKey("scala_version") )   {config.scala_version  = '2.11'}
  // Check if mandatory properties are set
  if (!config.containsKey("octopus_project") || !config.containsKey("package_id")) {error "Mandatory properties haven't been set"}

  pipeline {
    agent {
      label config.agent_type
    }
    options {
      timeout(time: config.build_timeout, unit: 'MINUTES')
    }
    environment {
      AWS_PROFILE           = "${config.aws_profile}"
      PROJECT_GROUP         = "${config.project_group}"
      OCTOPUS_CLI_SERVER    = "https://octopus.delphi.zone"
      OCTOPUS_CLI_API_KEY   = sh(script: "aws secretsmanager get-secret-value --profile gdb-delphi-dev --secret-id 'infra/jenkins/octopus_api_key' --output json | jq .SecretString | tr -d '\"'", , returnStdout: true).trim()
      OCTOPUS_CHANNEL       = octopus.setOctoChannel(env.BRANCH_NAME)
      DEPLOY_ENV            = octopus.setDeploymentEnvDelphi(params.DEPLOY_ENV_CHOICE, env.PROJECT_GROUP, env.BRANCH_NAME )
      NOTIFICATIONS_CHANNEL = "${config.slack_channel}"
    }
    parameters {
      choice(
        choices: ['default', 'yes', 'no'],
        description: '''Whether to trigger creation of octopus release.
        By default it\'s only triggered for develop, release* and master branches.
        ''',
        name: 'TRIGGER_DEPLOY'
      )
      choice(
        choices: [ 'default', 'dev', 'qa', 'stage', 'skip_deployment'],
        description: 'Set environment for deployment. Skipped by default for master/release*, dev by default for all other branches',
        name: 'DEPLOY_ENV_CHOICE'
      )
      booleanParam(
        defaultValue: true,
        description: "Don't raise errors in case release already exists",
        name: 'FAIL_IF_RELEASE_EXISTS'
      )
      booleanParam(
        defaultValue: true,
        description: "Publish artifact to nexus repository",
        name: 'PUBLISH_ARTIFACT'
      )
    }
    stages {
      stage('Docker login') {
        steps {
          sh "\$(aws ecr get-login --no-include-email --profile ${config.aws_profile} --region us-east-1)"
        }
      }
      stage('Set Maven credentials') {
        steps {
          script {
            nexus.generateAuthorizedMavenConfig("./.credentials")
          }
        }
      }
      stage('Docker stage') {
        agent {
          docker {
            image config.sbt_image
            // The following args are aimed to workaround some issues with using Docker container as a Jenkins agent:
            // 1. Disable image entrypoint to let Jenkins verify container was started correctly using custom commands.
            // 2. Explicitly tell SBT locations for configs and local cache because Jenkins runs container using a
            //    custom user (with `-u 1000:1000`) and SBT cannot resolve these paths automatically.
            // 3. Set MaxMetaspaceSize to 1G due to OOM
            args '--entrypoint "" -e JAVA_OPTS="-Dsbt.color=false -Dsbt.global.base=.sbt -Dsbt.boot.directory=.sbt -Dsbt.ivy.home=.ivy2"'
            reuseNode true
          }
        }
        environment {
          BUILD_VERSION = sh(
            script: "sbt 'inspect actual version' | grep 'Setting: java.lang.String' | cut -d '=' -f2 | tr -d ' ' | tr -d '[:space:]'",
            returnStdout: true
          )
        }
        stages {
          stage('Export version') {
            steps {
              echo env.BUILD_VERSION
              script { version = env.BUILD_VERSION }
            }
          }
          stage('Scalastyle') {
            steps { sh 'sbt scalastyle test:scalastyle scalafmtCheckAll' }
          }
          stage('Test') {
            steps { sh 'sbt coverage test' }
          }
          stage("Coverage") {
            steps { sh 'sbt coverageReport' }
          }
          stage('Publish') {
            when {
              expression { params.PUBLISH_ARTIFACT }
              anyOf {
                // publish from `master`
                branch 'master'

                allOf {
                  // publish RC versions only from the `release/*`
                  branch 'release/*'
                  expression { BUILD_VERSION ==~ /.*-RC[1-9]+[0-9]*$/ }
                }

                allOf {
                  // publish SNAPSHOT versions from the `develop`
                  anyOf {
                    branch 'develop'
                  }
                  expression { BUILD_VERSION ==~ /.*-SNAPSHOT$/ }
                }
              }
            }
            steps { sh 'sbt publish' }
          }
        }

        post {
          always {
            junit '**/target/test-reports/*.xml'

            step([
              $class: 'ScoveragePublisher',
              reportDir: "target/scala-${config.scala_version}/scoverage-report",
              reportFile: 'scoverage.xml']
            )

            recordIssues(
              enabledForFailure: false,
              tool: scala()
            )

            recordIssues(
              enabledForFailure: true,
              tool: checkStyle(pattern: '**/target/scalastyle-result.xml')
            )
          }
        }
      }

      stage('Git Tag') {
        when {
          branch 'master'
          expression { !sh(returnStdout: true, script: "git tag -l v$version")?.trim() }
          expression { config.enable_git_tags}
        }
        steps {
            sshagent(['dna-ci']) {
              sh "git tag v$version"
              sh 'git push --tags'
            }
        }
      }

      stage("Octopus release") {
        steps {
          script {
            def pipelineParams = scalaPackage.setScalaPipelineParams(config.octopus_project, config.package_id, version, params.TRIGGER_DEPLOY, params.failIfReleaseExists)
            scalaPackage.scalaPipeline(pipelineParams)
          }
        }
      }
    }
    post {
      failure {
        script {
          utility.slackNotifyMainBranches(currentBuild.currentResult, env.NOTIFICATIONS_CHANNEL)
        }
      }
    }
  }
}
