pipeline { agent { label 'java-builder' } options { timestamps() disableConcurrentBuilds() skipDefaultCheckout(true) timeout(time: 30, unit: 'MINUTES') } stages { stage('Checkout selected gray revision') { steps { script { if (env.JOB_BASE_NAME != 'baiyue-logistics-chat-gray' || params.ENVIRONMENT != 'gray') { error('This pipeline is restricted to the logistics chat gray job') } checkout scm env.SOURCE_COMMIT = sh(script: 'git rev-parse HEAD', returnStdout: true).trim() env.CHAT_IMAGE = "baiyue-logistics-chat-gray:${env.SOURCE_COMMIT.take(12)}-b${env.BUILD_NUMBER}" env.CERTBOT_IMAGE = "baiyue-logistics-chat-certbot:${env.SOURCE_COMMIT.take(12)}-b${env.BUILD_NUMBER}" if (!(params.PYTHON_BASE_IMAGE ==~ /[A-Za-z0-9][A-Za-z0-9._\/:@-]+/)) { error('Invalid Python base image reference') } if (!((params.ASR_PROVIDER ?: '') in ['', 'baidu'])) { error('Gray speech provider must be baidu or disabled') } if (!((params.DEBIAN_MIRROR ?: 'https://deb.debian.org') in ['https://deb.debian.org', 'https://mirrors.tuna.tsinghua.edu.cn'])) { error('Select a supported Debian mirror') } } sh '''set -eu for file in deploy/*.sh; do bash -n "$file"; done node --test tests/frontend/*.test.cjs ''' } } stage('Build and test image') { steps { withEnv(["PYTHON_BASE_IMAGE=${params.PYTHON_BASE_IMAGE}", "DEBIAN_MIRROR=${params.DEBIAN_MIRROR ?: 'https://deb.debian.org'}"]) { sh '''set -eu docker build --target test --build-arg PYTHON_BASE_IMAGE="$PYTHON_BASE_IMAGE" --build-arg DEBIAN_MIRROR="$DEBIAN_MIRROR" -t "$CHAT_IMAGE-test" . docker build --target production --build-arg PYTHON_BASE_IMAGE="$PYTHON_BASE_IMAGE" --build-arg DEBIAN_MIRROR="$DEBIAN_MIRROR" \ --label "org.opencontainers.image.revision=$SOURCE_COMMIT" -t "$CHAT_IMAGE" . docker build --target certbot --build-arg PYTHON_BASE_IMAGE="$PYTHON_BASE_IMAGE" --build-arg DEBIAN_MIRROR="$DEBIAN_MIRROR" \ --label "org.opencontainers.image.revision=$SOURCE_COMMIT" -t "$CERTBOT_IMAGE" . ''' } script { env.CHAT_IMAGE_ID = sh(script: 'docker image inspect --format "{{.Id}}" "$CHAT_IMAGE"', returnStdout: true).trim() env.CERTBOT_IMAGE_ID = sh(script: 'docker image inspect --format "{{.Id}}" "$CERTBOT_IMAGE"', returnStdout: true).trim() } } } stage('Deploy isolated gray service') { steps { lock(resource: 'baiyue-logistics-chat-gray-release') { withEnv([ "PUBLIC_ORIGIN=${params.PUBLIC_ORIGIN}", "HOST_PORT=${params.HOST_PORT}", "GRAY_DEPLOY_DIR=${params.GRAY_DEPLOY_DIR}", "GRAY_PROXY_CONF_DIR=${params.GRAY_PROXY_CONF_DIR}", "GRAY_TLS_CERT_FILE=${params.GRAY_TLS_CERT_FILE}", "GRAY_TLS_KEY_FILE=${params.GRAY_TLS_KEY_FILE}", "ASR_PROVIDER=${params.ASR_PROVIDER ?: ''}" ]) { withCredentials([ sshUserPrivateKey(credentialsId: params.SSH_CREDENTIAL_ID, keyFileVariable: 'TARGET_SSH_KEY', usernameVariable: 'TARGET_SSH_USER'), string(credentialsId: params.SSH_HOST_CREDENTIAL_ID, variable: 'TARGET_SSH_HOST'), file(credentialsId: params.SSH_KNOWN_HOSTS_CREDENTIAL_ID, variable: 'TARGET_SSH_KNOWN_HOSTS'), string(credentialsId: params.DEEPSEEK_CREDENTIAL_ID, variable: 'DEEPSEEK_API_KEY'), string(credentialsId: params.BAIDU_ASR_API_KEY_CREDENTIAL_ID, variable: 'BAIDU_ASR_API_KEY'), string(credentialsId: params.BAIDU_ASR_SECRET_KEY_CREDENTIAL_ID, variable: 'BAIDU_ASR_SECRET_KEY'), usernamePassword(credentialsId: params.PREVIEW_AUTH_CREDENTIAL_ID, usernameVariable: 'PREVIEW_USERNAME', passwordVariable: 'PREVIEW_PASSWORD') ]) { sh 'bash deploy/publish-gray.sh' script { if (params.IMPORT_ORDER_SAMPLES) { withCredentials([ file(credentialsId: params.ORDER_SNAPSHOT_CREDENTIAL_ID, variable: 'ORDER_SNAPSHOT_FILE'), file(credentialsId: params.TRACKING_SNAPSHOT_CREDENTIAL_ID, variable: 'TRACKING_SNAPSHOT_FILE') ]) { sh 'bash deploy/import-gray-order-samples.sh' } } } } } } } } } }