// Initialize variables to signal that a given stage finished.
// We use them to build a graph of interconnected steps/dependencies.
// - Incoming edges use "waitUntil" and reference the given variables of dependencies.
// - Outgoing edges set the given variable to true.
def action_test_frontend_ct_build = false
def action_build_deps = false
def action_copy_external_pages = false
def action_build_dev = false
def action_test_acceptance_app_server_pro = false
def action_build_webpack = false
def action_test_acceptance_app_saas = false
def action_build_pug = false
def action_build_production = false

pipeline {
  agent {
    node {
      // Select a VM with the given tabel.
      label 'jenkins-agent-web'
      // Use the monorepo checkout in /workspace.
      customWorkspace '/workspace'
    }
  }
  options {
    // Print timestamp next to each log line.
    timestamps()
    // Abort build after hitting first failure.
    parallelsAlwaysFailFast()
    retry(3)
    timeout(time: 15, unit: 'MINUTES')
  }
  environment {
    IMAGE_NAME = 'web'
    PROJECT_NAME = 'web'
    IMAGE_REPO = 'us-east1-docker.pkg.dev/overleaf-ops/ol-docker/web'
    AR_REPO_LOCATION = 'us-east1'
    AR_URL = 'us-east1-docker.pkg.dev/overleaf-ops/ol-docker'
    DOCKER_COMPOSE_FLAGS = '-f docker-compose.ci.yml'
    BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
    JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"       // preserve original BUILD_NUMBER
    BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"  // mimic the format used for Cloud Build
    COMMIT_SHA = "${GIT_COMMIT}"
    SHORT_SHA = "${GIT_COMMIT.take(7)}"
    CDN_STAG = "gs://ol-stag-web-assets-1"
    CDN_PROD = "gs://mgcp-1117973-ol-prod-web-assets-1"
  }
  stages {
    // Retries will use the same pipeline instance. Reset the vars.
    stage('Reset vars') {
      steps {
        script {
          action_test_frontend_ct_build = false
          action_build_deps = false
          action_copy_external_pages = false
          action_build_dev = false
          action_test_acceptance_app_server_pro = false
          action_build_webpack = false
          action_test_acceptance_app_saas = false
          action_build_pug = false
          action_build_production = false
        }
      }
    }
    stage ('Build, Test and Push') {
      parallel {
        stage('Copy external pages') {
          steps {
            dir('services/web') {
              sh 'bin/copy_external_pages'
              script {
                action_copy_external_pages = true
              }
            }
          }
        }
        stage('Prefetch Tests Images') {
          steps {
            dir('services/web') {
              sh 'docker compose -f docker-compose.ci.yml pull --quiet test_frontend_ct mongo redis_test ldap saml'
            }
          }
        }
        stage('Build Deps') {
          steps {
            dir('services/web') {
              sh 'make build_deps'
            }
            script {
              action_build_deps = true
            }
          }
        }
        stage('Push Deps') {
          steps {
            script {
              waitUntil {
                return action_build_deps
              }
            }
            dir('services/web') {
              sh 'docker push ${AR_URL}/${IMAGE_NAME}:${BRANCH_NAME}-deps'
            }
          }
        }
        stage('Build Dev') {
          steps {
            script {
              waitUntil {
                return action_build_deps && action_copy_external_pages
              }
            }
            dir('services/web') {
              sh 'make build_dev'
            }
            script {
              action_build_dev = true
            }
          }
        }
        stage ('Format') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh 'make format_in_docker'
            }
          }
        }
        stage('Lint') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh 'make lint_in_docker'
            }
          }
        }
        stage('Shellcheck') {
          steps {
            dir('services/web') {
              sh 'make shellcheck'
            }
          }
        }
        stage('Acceptance SaaS') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh 'make test_acceptance_app_saas'
            }
            script {
              action_test_acceptance_app_saas = true
            }
          }
        }
        stage('Acceptance Server CE') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_acceptance_app_server_ce"
            }
          }
        }
        stage('Acceptance Server Pro') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_acceptance_app_server_pro"
            }
            script {
              action_test_acceptance_app_server_pro = true
            }
          }
        }
        stage('test_acceptance_modules_merged_saas_1') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_acceptance_modules_merged_saas_1"
            }
          }
        }
        stage('test_acceptance_modules_merged_saas_2') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_acceptance_modules_merged_saas_2"
            }
          }
        }
        stage('test_acceptance_modules_merged_saas_3') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_acceptance_modules_merged_saas_3"
            }
          }
        }
        stage('test_acceptance_modules_merged_saas_4') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_acceptance_modules_merged_saas_4"
            }
          }
        }
        stage('test_acceptance_modules_merged_server_ce') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_acceptance_modules_merged_server_ce"
            }
          }
        }
        stage('test_acceptance_modules_merged_server_pro') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_acceptance_modules_merged_server_pro"
            }
          }
        }
        stage('test_frontend') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_frontend"
            }
          }
        }
        stage('test_writefull') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_writefull"
            }
          }
        }
        stage('test_frontend_ct_build') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make build_test_frontend_ct"
            }
            script {
              action_test_frontend_ct_build = true
            }
          }
        }
        stage('test_frontend_ct_core_other') {
          environment {
            CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT = '120000'
          }
          steps {
            script {
              waitUntil {
                return action_test_frontend_ct_build
              }
            }
            dir('services/web') {
              sh "make test_frontend_ct_core_other"
            }
          }
        }
        stage('test_frontend_ct_core_features') {
          environment {
            CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT = '120000'
          }
          steps {
            script {
              waitUntil {
                return action_test_frontend_ct_build
              }
            }
            dir('services/web') {
              sh "make test_frontend_ct_core_features"
            }
          }
        }
        stage('test_frontend_ct_modules') {
          environment {
            CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT = '120000'
          }
          steps {
            script {
              waitUntil {
                return action_test_frontend_ct_build
              }
            }
            dir('services/web') {
              sh "make test_frontend_ct_modules"
            }
          }
        }
        stage('test_frontend_ct_editor_visual') {
          steps {
            script {
              waitUntil {
                return action_test_frontend_ct_build
              }
            }
            dir('services/web') {
              sh "make test_frontend_ct_editor_visual"
            }
          }
        }
        stage('test_frontend_ct_editor_other') {
          steps {
            script {
              waitUntil {
                return action_test_frontend_ct_build
              }
            }
            dir('services/web') {
              sh "make test_frontend_ct_editor_other"
            }
          }
        }
        stage('Test Unit ESM') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_unit_esm"
            }
          }
        }
        stage('Test Unit Mocha') {
          steps {
            script {
              waitUntil {
                return action_build_dev
              }
            }
            dir('services/web') {
              sh "make test_unit_mocha"
            }
          }
        }
        stage('Build Webpack') {
          steps {
            script {
              waitUntil {
                return action_build_dev && action_test_acceptance_app_server_pro
              }
            }
            dir('services/web') {
              sh 'make build_webpack'
            }
            script {
              action_build_webpack = true
            }
          }
        }
        stage('Build Pug') {
          steps {
            script {
              waitUntil {
                return action_build_dev && action_test_acceptance_app_server_pro
              }
            }
            dir('services/web') {
              sh 'make build_pug'
            }
            script {
              action_build_pug = true
            }
          }
        }
        stage('CDN Upload Image') {
          steps {
            script {
              waitUntil {
                return action_build_webpack
              }
            }
            dir('services/web') {
              sh 'make tar'
              sh 'bin/cdn_upload'
            }
          }
        }
        stage('Build Production') {
          steps {
            script {
              waitUntil {
                return action_build_webpack && action_build_pug
              }
            }
            dir('services/web') {
              sh 'make build'
            }
            script {
              action_build_production = true
            }
          }
        }
        stage('Sentry Upload') {
          steps {
            script {
              waitUntil {
                return action_build_webpack && action_build_production
              }
            }
            dir('services/web') {
              sh 'gcloud secrets versions access latest --secret=web-sentryclirc > .sentryclirc'
              sh 'make sentry_upload'
            }
          }
          post {
            cleanup {
              dir('services/web') {
                sh 'rm -f .sentryclirc'
              }
            }
          }
        }
      }
    }
    stage('Push Production') {
      steps {
        dir('services/web') {
          sh 'make publish'
        }
      }
    }
  }
  post {
    // Ensure tear down of test containers, then run general Jenkins VM cleanup.
    cleanup {
      dir('services/web') {
        sh 'make clean -j10'
      }
      sh 'make clean_jenkins'
    }
  }
}

// vim: set ft=groovy :