perf(ci): run selected tests once before service builds

This commit is contained in:
2026-08-24 13:43:38 +08:00
parent 9dd2fcb7e5
commit b012d64b54
4 changed files with 58 additions and 6 deletions
Vendored
+32 -1
View File
@@ -108,6 +108,9 @@ pipeline {
}
env.RESOLVED_JOB_PREFIX = jobPrefix
env.DATABASE_CHANGE_DETECTED = 'false'
if (env.RESOLVED_ENVIRONMENT == 'production' && params.SKIP_TESTS) {
error('生产环境禁止跳过测试')
}
List selected = []
if (params.BUILD_MODE == 'ALL') {
@@ -177,6 +180,33 @@ pipeline {
}
}
stage('统一 Maven 测试门禁') {
when {
expression { env.NO_SERVICE_CHANGE != 'true' && !params.SKIP_TESTS }
}
agent { label 'java-builder' }
tools { maven 'maven-3.8.8' }
steps {
script {
String selectedModules = env.SELECTED_SERVICES.split(',')
.collect { it.trim() }
.findAll { it }
.join(',')
echo "统一测试本次选中的服务及其公共依赖: ${selectedModules}"
sh """
test \"\$(git rev-parse HEAD)\" = \"${env.SOURCE_COMMIT}\"
mvn --settings deploy/maven/settings-ci.xml --batch-mode --errors -pl ${selectedModules} -am test
"""
echo "统一测试门禁通过: ${env.SOURCE_COMMIT};下游单服务任务不再重复执行测试"
}
}
post {
always {
junit allowEmptyResults: true, testResults: '**/target/surefire-reports/TEST-*.xml'
}
}
}
stage('并行调度独立服务 Job') {
when { expression { env.NO_SERVICE_CHANGE != 'true' } }
steps {
@@ -196,7 +226,8 @@ pipeline {
string(name: 'IMAGE_TAG', value: env.IMAGE_TAG),
string(name: 'ENVIRONMENT', value: env.RESOLVED_ENVIRONMENT),
booleanParam(name: 'DEPLOY', value: params.DEPLOY),
booleanParam(name: 'SKIP_TESTS', value: params.SKIP_TESTS),
// 总控已完成统一测试,或用户已明确选择跳过;下游仅负责编译、打包和部署。
booleanParam(name: 'SKIP_TESTS', value: true),
string(name: 'IMAGE_REPOSITORY', value: env.RESOLVED_IMAGE_REPOSITORY),
string(name: 'DOCKER_BASE_IMAGE', value: params.DOCKER_BASE_IMAGE),
string(name: 'EVENT_BRIDGE_REGION', value: params.EVENT_BRIDGE_REGION)
+6 -3
View File
@@ -114,12 +114,15 @@ pipeline {
stage('Maven 测试与打包') {
steps {
script {
if (params.ENVIRONMENT == 'production' && params.SKIP_TESTS) {
error('生产环境禁止跳过测试')
boolean coordinatorPinnedCommit = params.SOURCE_COMMIT?.trim() as boolean
if (params.ENVIRONMENT == 'production' && params.SKIP_TESTS && !coordinatorPinnedCommit) {
error('生产环境手工构建禁止跳过测试;总控流水线可在统一测试通过后执行快速打包')
}
boolean skipTestExecution = params.ENVIRONMENT == 'test' || params.SKIP_TESTS
String testOption = skipTestExecution ? '-DskipTests' : ''
if (params.ENVIRONMENT == 'test') {
if (params.SKIP_TESTS && coordinatorPinnedCommit) {
echo "总控已处理提交 ${env.RESOLVED_SOURCE_COMMIT} 的测试门禁,本单服务仅编译测试源码并打包"
} else if (params.ENVIRONMENT == 'test') {
echo '测试环境快速部署:编译主代码和测试代码,但不重复执行单元测试;完整测试由提交门禁和预发布执行'
}
sh "mvn --settings ${env.MAVEN_SETTINGS} --batch-mode --errors -pl ${env.RESOLVED_SERVICE} -am clean package ${testOption}"
@@ -13,6 +13,17 @@ test('coordinator releases its builder while waiting for downstream jobs', () =>
assert.doesNotMatch(pipeline, /cleanWs\(/)
})
test('coordinator runs selected tests once before parallel service packaging', () => {
const gateIndex = pipeline.indexOf("stage('统一 Maven 测试门禁')")
const dispatchIndex = pipeline.indexOf("stage('并行调度独立服务 Job')")
assert.ok(gateIndex >= 0, 'unified test gate must exist')
assert.ok(dispatchIndex > gateIndex, 'unified tests must finish before downstream dispatch')
assert.match(pipeline, /-pl \$\{selectedModules\} -am test/)
assert.match(pipeline, /booleanParam\(name: 'SKIP_TESTS', value: true\)/)
assert.doesNotMatch(pipeline, /TESTED_COMMIT/)
})
test('AUTO detects database migrations without expanding them to all services', () => {
assert.match(pipeline, /def databaseMigrationPaths = \['deploy\/sql\/'\]/)
assert.match(pipeline, /!databaseMigration && commonPaths\.any/)
@@ -30,8 +30,9 @@ test('coordinator jobs present their own deployment environment as the default c
})
test('production deployments cannot skip tests', () => {
assert.match(pipeline, /params\.ENVIRONMENT == 'production' && params\.SKIP_TESTS/)
assert.match(pipeline, /error\('生产环境禁止跳过测试'\)/)
assert.match(coordinatorPipeline, /env\.RESOLVED_ENVIRONMENT == 'production' && params\.SKIP_TESTS/)
assert.match(coordinatorPipeline, /error\('生产环境禁止跳过测试'\)/)
assert.match(pipeline, /生产环境手工构建禁止跳过测试/)
})
test('Java builds use the shared builder pool and serialize incremental target deployments', () => {
@@ -51,6 +52,12 @@ test('Java builds use the shared builder pool and serialize incremental target d
assert.match(directDeployScript, /--pull never/)
})
test('production only accepts skipped downstream tests for a coordinator-pinned commit', () => {
assert.match(pipeline, /boolean coordinatorPinnedCommit = params\.SOURCE_COMMIT\?\.trim\(\) as boolean/)
assert.match(pipeline, /params\.ENVIRONMENT == 'production' && params\.SKIP_TESTS && !coordinatorPinnedCommit/)
assert.match(pipeline, /生产环境手工构建禁止跳过测试/)
})
test('development and test deployment locks are acquired before target executors', () => {
const directDeployStage = pipeline.slice(
pipeline.indexOf("stage('部署开发或测试环境')"),