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 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 { 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 'docker push ${AR_URL}/${IMAGE_NAME}:${BRANCH_NAME}-deps' } } } 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 90' } } 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') { 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' } } } // vim: set ft=groovy :