fix(deploy): publish unified services to temporary gray environment

This commit is contained in:
2026-10-07 11:02:47 +08:00
parent 6346e7bd95
commit ec0c06ff88
9 changed files with 211 additions and 72 deletions
+19 -30
View File
@@ -52,44 +52,33 @@ test('coordinator cannot initialize test databases', () => {
assert.doesNotMatch(pipeline, /测试数据库初始化/)
})
test('coordinator defaults event bridge deployments to both regions', () => {
assert.match(pipeline, /choice\(name: 'EVENT_BRIDGE_REGION', choices: \['BOTH', 'CN', 'OVERSEAS'\]/)
assert.match(pipeline, /\['BOTH', 'SELECT', 'CN', 'OVERSEAS'\]\.contains\(bridgeRegion\)/)
assert.match(pipeline, /兼容旧 Jenkins 参数 SELECT:本次按 BOTH/)
assert.doesNotMatch(pipeline, /事件桥 BOTH 仅支持开发或测试环境/)
assert.match(pipeline, /String downstreamImageTag = deployBothBridges[\s\S]*?\? "\$\{env\.IMAGE_TAG\}-both"/)
assert.match(pipeline, /String downstreamBridgeRegion = deployBothBridges[\s\S]*?\? 'CN'/)
assert.match(pipeline, /service == 'event-bridge-service' \? params\.EVENT_BRIDGE_REGION : 'CN'/)
assert.match(pipeline, /string\(name: 'EVENT_BRIDGE_REGION', value: downstreamBridgeRegion\)/)
test('coordinator dispatches exactly the current TEST service map without retired regional units', async () => {
const serviceMap = await readFile(new URL('../deploy/service-map.yml', import.meta.url), 'utf8')
const expected = [...serviceMap.matchAll(/^ ([a-z][a-z0-9-]+):$/gm)].map(match => match[1]).sort()
const declaration = pipeline.match(/def serviceModules = \[([\s\S]*?)\]/)?.[1] || ''
const actual = [...declaration.matchAll(/'([^']+)'/g)].map(match => match[1]).sort()
assert.equal(expected.length, 13)
assert.deepEqual(actual, expected)
assert.doesNotMatch(pipeline, /EVENT_BRIDGE_REGION|gateway-overseas|event-bridge-service/)
})
test('production deploy uses DEPLOY as the single explicit release switch', () => {
test('TEST and gray jobs use fixed independent environment mappings and explicit DEPLOY', () => {
assert.match(pipeline, /booleanParam\(name: 'DEPLOY'/)
assert.match(pipeline, /test "\$\(git rev-parse HEAD\)" = "\$\(git rev-parse origin\/main\)"/)
assert.match(pipeline, /env\.RESOLVED_ENVIRONMENT == 'production' && params\.SKIP_TESTS/)
assert.match(pipeline, /case 'backend-java':[\s\S]*?return 'test'/)
assert.match(pipeline, /case 'backend-java-prod':[\s\S]*?return 'production'/)
assert.match(pipeline, /case 'backend-java-prod':[\s\S]*?return 'baiyue-firstleg-prod-'/)
assert.doesNotMatch(pipeline, /return 'development'|backend-java-dev/)
assert.match(pipeline, /booleanParam\(name: 'DEPLOY', value: params\.DEPLOY\)/)
assert.doesNotMatch(pipeline, /input message:/)
assert.doesNotMatch(pipeline, /\u786e\u8ba4\u90e8\u7f72/)
})
test('production deploy reports one aggregated result to WeCom', () => {
const sourceCommitIndex = pipeline.indexOf("env.SOURCE_COMMIT = sh(script: 'git rev-parse HEAD'")
const productionGuardIndex = pipeline.indexOf("if (env.RESOLVED_ENVIRONMENT == 'production')")
assert.match(pipeline, /credentialsId: 'wecom-prod-webhook'/)
assert.match(pipeline, /node\('java-builder'\) \{[\s\S]*?WECOM_WEBHOOK/)
assert.match(pipeline, /env\.JOB_BASE_NAME == 'backend-java-prod' && params\.DEPLOY/)
assert.ok(sourceCommitIndex >= 0, 'source commit must be recorded for notifications')
assert.ok(sourceCommitIndex < productionGuardIndex,
'source commit must be recorded before production validation can fail')
test('TEST coordinator records downstream identity and fails the aggregate on any unsuccessful service', () => {
assert.match(pipeline, /env\.SOURCE_COMMIT = sh\(script: 'git rev-parse HEAD'/)
assert.match(pipeline, /def downstreamBuildUrls = \[:\]/)
assert.match(pipeline, /downstreamBuildUrls\[service\] = downstreamBuild\.absoluteUrl/)
assert.match(pipeline, /downstreamBuildNumbers\[service\] = downstreamBuild\.number/)
assert.match(pipeline, /unstable \{[\s\S]*?'\u26a0\ufe0f \u751f\u4ea7\u90e8\u7f72\u90e8\u5206\u5931\u8d25'/)
assert.match(pipeline, /\u7ed3\u679c\uff1a\u6210\u529f \$\{successCount\} \/ \u5931\u8d25 \$\{failedServices\.size\(\)\}/)
assert.match(pipeline, /\u5931\u8d25\u670d\u52a1\uff1a\$\{failedLinks/)
assert.match(pipeline, /failure \{[\s\S]*?'\u274c \u751f\u4ea7\u53d1\u5e03\u5931\u8d25'/)
assert.match(pipeline, /aborted \{[\s\S]*?'\u23f9 \u751f\u4ea7\u90e8\u7f72\u5df2\u53d6\u6d88'/)
assert.match(pipeline, /> \u8017\u65f6\uff1a\$\{duration\}/)
assert.match(pipeline, /\u4f01\u4e1a\u5fae\u4fe1\u901a\u77e5\u5931\u8d25\uff0c\u4e0d\u5f71\u54cd\u539f\u6784\u5efa\u7ed3\u679c/)
assert.doesNotMatch(servicePipeline, /wecom-prod-webhook|sendProductionWeComNotification/)
assert.match(pipeline, /downstreamResults\.findAll \{ service, result -> result != 'SUCCESS' \}/)
assert.match(pipeline, /if \(failed\) \{[\s\S]*?unstable\(/)
assert.doesNotMatch(pipeline + servicePipeline, /wecom-prod-webhook|sendProductionWeComNotification/)
})