#!/usr/bin/env groovy

pipeline {
  // Some steps hang forever. Rather than take an agent, we are good Jenkins denizens and explicitly say when we want
  // a jenkins worker
  agent none
  options {
    // Add timestamps before stdout/stderr in jenkins logs
    timestamps()
    // Let the jenkins logs show console command colors
    ansiColor('xterm')
    // Don't bother running builds if the pushes happen one right after the other
    quietPeriod(30)
  }
  parameters {
    // We can manually trigger these builds with DEBUG=true and output a bunch of debug logs to the build
    booleanParam(name: 'DEBUG', defaultValue: false, description: 'Debug the build with way too much verbose output.')
  }
  stages {
    // Each stage becomes a green box on the jenkins UI
    stage("Verify code") {
      // We have to explicitly declare when we want an agent. Agents do things like give us a jenkins-worker node
      // that can run things or access jenkins information.  These are a reserved and limited resource, so we should
      // only take one when we need it.
      agent any
      environment {
        // Put the ops user inside our AWS credentials for the entire pipeline.
        // This must be in every step since *any* step could need to download the builder which requires credentials
        AWS_SHARED_CREDENTIALS_FILE = credentials('twitch-user-preferences-prod')
      }
      stages {
        // Print some quick debug information at the stop so we can debug this build if things go wrong
        stage("Print debug info") {
          steps {
            script {
              // Put the short git SHA in the build name so we can find a build by SHA on the UI
              currentBuild.displayName = env.GIT_COMMIT[0..6] + " #" + env.BUILD_NUMBER
            }
            sh 'git clean -ffdx'
            sh 'cd builder && rm -rf twirpserviceslohook sandstorm terraform-provider-grafana'
            sh 'env'
            sh 'docker --version'
          }
        }
        stage("Create builder") {
          options {
            // Not worth creating the builder twice at the same time.
            lock(resource: 'jackup3_builder_creation')
          }
          steps {
            // We clone internal libraries when we create the builder.  Setup an SSH agent to allow internal `git`
            // commands against git-aws
            sshagent(['git-aws-read-key']) {
              sh './make.sh builder push_if_needed'
            }
          }
        }
        stage("Test") {
          steps {
            // Note how we run *everything* inside the builder so we can isolate from changes to the jenkins environment
            sh './make.sh builder run go test'
            // Note: Don't run upload_code_coverage in a docker container because the codecov script depends upon many
            //       Jenkins env variables
            sh './make.sh extra upload_code_coverage'
          }
        }
        stage("Lint") {
          steps {
            sh './make.sh go lint'
            sh './make.sh go dep_check'
            sh './make.sh docker lint cmd/jackup3/Dockerfile cmd/jackup3/Dockerfile_integration_test builder/Dockerfile'
          }
        }
        stage("build docker image") {
          steps {
            sh './make.sh docker build'
          }
        }
        stage("push docker images to staging/production") {
          when {
            branch 'master';
          }
          steps {
            sh './make.sh infra docker_push staging'
            sh './make.sh infra docker_push production'
          }
        }
        stage("build integration docker image") {
          steps {
            sh './make.sh docker build_integration'
          }
        }
        stage("push integration image") {
          steps {
            sh './make.sh infra docker_integration_push staging'
          }
        }
        stage("Integration test run") {
          steps {
            sh './make.sh infra integration_test_ecs_run staging'
          }
        }
      }
    }
    stage("Staging deploy") {
      agent any
      environment {
        AWS_SHARED_CREDENTIALS_FILE = credentials('twitch-user-preferences-prod')
      }
      when {
        branch 'master';
      }
      options {
        // Do not allow two staging deploys at once
        // inversePrecedence will let the most recent staging deploy access the lock first
        lock(resource: 'jackup3_staging_deploy', inversePrecedence: true)
      }
      steps {
        // milestone means that if one build does a staging push, it will cancel older builds from also trying
        // to push to staging.
        milestone(100)
        sh './make.sh infra deploy staging'
      }
    }
    stage("Wait for canary confirmation") {
      // Note: Do input inside `agent none` so we don't claim a jenkins worker while waiting for input
      agent none
      when {
        branch 'master';
      }
      steps {
        // Input stops the build and waits for a user to click OK
        input message: "Proceed?"
      }
    }
    stage("Canary deploy") {
      agent any
      environment {
        AWS_SHARED_CREDENTIALS_FILE = credentials('twitch-user-preferences-prod')
      }
      when {
        branch 'master';
      }
      options {
        lock(resource: 'jackup3_canary_deploy', inversePrecedence: true)
      }
      steps {
        milestone(200)
        sh './make.sh infra deploy canary'
      }
    }
    stage("Wait for production confirmation") {
      agent none
      when {
        branch 'master';
      }
      steps {
        input message: "Proceed?"
      }
    }
    stage("Production deploy") {
      agent any
      environment {
        AWS_SHARED_CREDENTIALS_FILE = credentials('twitch-user-preferences-prod')
      }
      when {
        branch 'master';
      }
      options {
        lock(resource: 'jackup3_production_deploy', inversePrecedence: true)
      }
      steps {
        milestone(300)
        sh './make.sh infra deploy production'
      }
    }
  }
  // TODO: Add post step to clean workspace
}
