pipeline { agent { label "${env.JOB_BASE_NAME?.endsWith('-prod') ? 'java-builder' : 'java-test'}" } options { timestamps() disableConcurrentBuilds() } stages { stage('检查测试发布参数') { when { expression { !env.JOB_BASE_NAME?.endsWith('-prod') } } steps { script { if (env.JOB_BASE_NAME?.endsWith('-dev')) { error('此流水线仅支持 test 和本轮授权的 prod 灰度') } env.IMAGE_TAG = sh(script: 'git rev-parse --short=12 HEAD', returnStdout: true).trim() } sh '''set -eu export API_UPSTREAM="${API_UPSTREAM:-http://gateway:9000}" export TEST_NETWORK="${TEST_NETWORK:-firstleg-test-network}" : "${CLIENT_WEB_URL:?CLIENT_WEB_URL 未设置}" docker network inspect "$TEST_NETWORK" >/dev/null docker compose -f docker-compose.test.yml config --quiet ''' } } stage('构建并部署测试前端') { when { expression { !env.JOB_BASE_NAME?.endsWith('-prod') } } steps { sh '''set -eu docker compose -f docker-compose.test.yml build --pull=false docker compose -f docker-compose.test.yml up -d --wait --wait-timeout 120 docker compose -f docker-compose.test.yml exec -T admin-web wget -qO- http://127.0.0.1/healthz ''' } } stage('发布临时生产灰度') { when { expression { env.JOB_BASE_NAME?.endsWith('-prod') } } steps { lock(resource: 'firstleg-production-admin-web-deploy') { withCredentials([ usernamePassword(credentialsId: 'gitea-registry-token', usernameVariable: 'BUILD_REGISTRY_USER', passwordVariable: 'BUILD_REGISTRY_PASSWORD'), usernamePassword(credentialsId: 'gitea-production-pull-token', usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASSWORD'), sshUserPrivateKey(credentialsId: 'firstleg-production-ssh', keyFileVariable: 'TARGET_SSH_KEY', usernameVariable: 'TARGET_SSH_USER'), string(credentialsId: 'firstleg-production-host', variable: 'TARGET_SSH_HOST'), file(credentialsId: 'firstleg-production-known-hosts', variable: 'TARGET_SSH_KNOWN_HOSTS') ]) { sh 'sh scripts/deploy-production.sh' } } } } } post { failure { script { if (!env.JOB_BASE_NAME?.endsWith('-prod')) { sh 'docker compose -f docker-compose.test.yml logs --tail=100 || true' } } } } }