Files
overleaf-cep/services/web/Jenkinsfile
Jakob Ackermann 49667a605b [web] tweak Jenkins pipeline following move to faster CI VMs (#29188)
* [web] tweak Jenkins pipeline following move to faster CI VMs

The webpack build time has been reduced by about 30%. Adjust the sleep
statement for delaying the webpack build accordingly.

Push the production docker image layers from the parallel steps already.
Use a shared "scratch" tag to avoid generating cruft per branch/build.

* [web] avoid sharing the cypress/downloads folder in CI

GitOrigin-RevId: 52fdf420ec04fd26e3823ff9fca8c52f7a7764d7
2025-10-30 09:07:43 +00:00

366 lines
10 KiB
Groovy

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()
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
CDN_STAG = "gs://ol-stag-web-assets-1"
CDN_PROD = "gs://mgcp-1117973-ol-prod-web-assets-1"
}
stages {
stage('Set Build Variables') {
steps {
script {
def relevantCommitHash
if (env.CHANGE_BRANCH) {
echo "PR build detected. Jenkins checked out a merge commit: ${GIT_COMMIT}"
relevantCommitHash = sh(script: 'git rev-parse HEAD^1', returnStdout: true).trim()
echo "Found actual branch commit: ${relevantCommitHash}"
} else {
echo "Branch build detected. Using commit: ${GIT_COMMIT}"
relevantCommitHash = "${GIT_COMMIT}"
}
env.COMMIT_SHA = relevantCommitHash
env.SHORT_SHA = relevantCommitHash.take(7)
env.BUILD_NUMBER = "${env.SHORT_SHA}_${env.JENKINS_BUILD_NUMBER}"
}
}
}
stage('Stage 1') {
parallel {
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') {
steps {
dir('services/web') {
sh 'bin/copy_external_pages'
retry(count: 3) {
sh 'make build_deps'
}
retry(count: 3) {
sh 'make build_dev'
}
sh 'make build_test_frontend_ct'
}
}
}
}
}
stage('Stage 2') {
parallel {
stage('Push Deps') {
steps {
dir('services/web') {
sh 'make push_branch'
}
}
}
stage('Format') {
steps {
dir('services/web') {
sh 'make format_in_docker'
}
}
}
stage('Lint') {
steps {
dir('services/web') {
sh 'make lint_in_docker'
}
}
post {
always {
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'web-eslint', name: 'Web eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'services/web/data/reports/eslint.json')]
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'web-stylelint', name: 'Web stylelint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [styleLint(pattern: 'services/web/data/reports/stylelint.json')]
}
}
}
stage('Shellcheck') {
steps {
dir('services/web') {
sh 'make shellcheck'
}
}
}
stage('Acceptance SaaS') {
steps {
dir('services/web') {
retry(count: 3) {
sh 'make test_acceptance_app_saas'
}
}
}
}
stage('Acceptance Server CE') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_acceptance_app_server_ce"
}
}
}
}
stage('Acceptance Server Pro') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_acceptance_app_server_pro"
}
}
}
}
stage('test_acceptance_modules_merged_saas_1') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_acceptance_modules_merged_saas_1"
}
}
}
}
stage('test_acceptance_modules_merged_saas_2') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_acceptance_modules_merged_saas_2"
}
}
}
}
stage('test_acceptance_modules_merged_saas_3') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_acceptance_modules_merged_saas_3"
}
}
}
}
stage('test_acceptance_modules_merged_saas_4') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_acceptance_modules_merged_saas_4"
}
}
}
}
stage('test_acceptance_modules_merged_server_ce') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_acceptance_modules_merged_server_ce"
}
}
}
}
stage('test_acceptance_modules_merged_server_pro') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_acceptance_modules_merged_server_pro"
}
}
}
}
stage('test_frontend') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_frontend"
}
}
}
}
stage('test_writefull') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_writefull"
}
}
}
}
stage('test_frontend_ct_core_other') {
environment {
CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT = '120000'
}
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_frontend_ct_core_other"
}
}
}
}
stage('test_frontend_ct_core_features') {
environment {
CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT = '120000'
}
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_frontend_ct_core_features"
}
}
}
}
stage('test_frontend_ct_modules') {
environment {
CYPRESS_INTERNAL_BROWSER_CONNECT_TIMEOUT = '120000'
}
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_frontend_ct_modules"
}
}
}
}
stage('test_frontend_ct_editor_visual') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_frontend_ct_editor_visual"
}
}
}
}
stage('test_frontend_ct_editor_other') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_frontend_ct_editor_other"
}
}
}
}
stage('Test Unit ESM') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_unit_esm"
}
}
}
}
stage('Test Unit Mocha') {
steps {
dir('services/web') {
retry(count: 3) {
sh "make test_unit_mocha"
}
}
}
}
stage('Build webpack + production + cdn upload + sentry upload') {
stages {
stage('Wait a bit to give tests all the CPU capacity') {
steps {
sh 'sleep 60'
}
}
stage('Build Webpack') {
steps {
dir('services/web') {
sh 'make build_webpack'
}
}
}
stage('Build Pug') {
steps {
dir('services/web') {
sh 'make build_pug'
}
}
}
stage('CDN Upload Image') {
steps {
dir('services/web') {
sh 'make tar'
retry(count: 3) {
sh 'bin/cdn_upload'
}
}
}
}
stage('Build Production') {
steps {
dir('services/web') {
sh 'make build'
}
}
}
stage('Sentry Upload') {
steps {
dir('services/web') {
sh 'gcloud secrets versions access latest --secret=web-sentryclirc > .sentryclirc'
retry(count: 3) {
sh 'make sentry_upload'
}
}
}
post {
cleanup {
dir('services/web') {
sh 'rm -f .sentryclirc'
}
}
}
}
stage('Push Production image early') {
steps {
dir('services/web') {
sh 'make push_scratch'
}
}
}
}
}
}
}
stage('Push Production') {
steps {
dir('services/web') {
sh 'make publish'
}
}
}
}
post {
always {
junit checksName: 'Web test results', testResults: 'services/web/data/reports/junit-*.xml,services/web/data/reports/junit-*/**/*.xml'
}
// Ensure tear down of test containers, then run general Jenkins VM cleanup.
cleanup {
dir('services/web') {
sh 'make clean -j10'
}
sh 'make clean_jenkins -j10'
}
}
}
// vim: set ft=groovy :