feat(release): add standard and fast 103 portal release modes
Formalize fast release as --mode fast so verified changes can skip canary promotion and full Gate reruns while keeping backups and health checks. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -38,7 +38,7 @@ test('production release verifies gate report before 103 preflight and upload',
|
||||
assert.ok(gateIndex > 0, 'missing gate verifier');
|
||||
assert.ok(preflightIndex > gateIndex, '103 preflight must run after gate verification');
|
||||
assert.ok(uploadIndex > preflightIndex, 'upload must run after preflight');
|
||||
assert.match(source, /生产发布守门员禁止 --skip-tests/);
|
||||
assert.match(source, /标准发布禁止 --skip-tests/);
|
||||
assert.match(source, /禁止 ALLOW_PORTAL_RELEASE_SCOPE_BYPASS/);
|
||||
});
|
||||
|
||||
@@ -47,11 +47,11 @@ test('production stable release verifies canary promotion evidence before gate c
|
||||
path.join(ROOT, 'scripts', 'release-portal-runtime-prod.sh'),
|
||||
'utf8',
|
||||
);
|
||||
const promotionIndex = source.indexOf('verify-canary-promotion-evidence.mjs');
|
||||
const gateIndex = source.indexOf('verify-release-gate-report.mjs');
|
||||
const promotionIndex = source.indexOf('say "验证 103 灰度晋升证据"');
|
||||
const gateCallIndex = source.indexOf('say "验证与当前 main 和 runtime artifact 绑定的 Gate report"');
|
||||
const impactIndex = source.indexOf('run-release-gate-impact.mjs');
|
||||
assert.ok(promotionIndex > 0, 'missing canary promotion evidence verifier');
|
||||
assert.ok(gateIndex > promotionIndex, 'gate verification must follow promotion evidence');
|
||||
assert.ok(promotionIndex > 0, 'missing canary promotion evidence step');
|
||||
assert.ok(gateCallIndex > promotionIndex, 'gate verification must follow promotion evidence in standard flow');
|
||||
assert.ok(impactIndex > 0, 'missing risk-based impact gate fallback');
|
||||
assert.doesNotMatch(source, /在同一候选完成 103 灰度验收且晋升证据校验落地前,禁止非 dry-run/);
|
||||
assert.match(source, /read_agent_run_status_json/);
|
||||
@@ -125,10 +125,46 @@ test('production release rejects --skip-tests before repository or network prefl
|
||||
{ cwd: ROOT, encoding: 'utf8' },
|
||||
);
|
||||
assert.notEqual(result.status, 0);
|
||||
assert.match(result.stderr, /禁止 --skip-tests/);
|
||||
assert.match(result.stderr, /标准发布禁止 --skip-tests/);
|
||||
assert.doesNotMatch(`${result.stdout}\n${result.stderr}`, /103 只读预检/);
|
||||
});
|
||||
|
||||
test('fast production release allows --skip-tests but still requires check-release-ready', () => {
|
||||
const result = spawnSync(
|
||||
'bash',
|
||||
[
|
||||
path.join(ROOT, 'scripts', 'release-portal-runtime-prod.sh'),
|
||||
'--mode',
|
||||
'fast',
|
||||
'--skip-tests',
|
||||
'--skip-build',
|
||||
'--dry-run',
|
||||
],
|
||||
{ cwd: ROOT, encoding: 'utf8' },
|
||||
);
|
||||
assert.notEqual(result.status, 0);
|
||||
assert.doesNotMatch(result.stderr, /标准发布禁止 --skip-tests/);
|
||||
assert.match(`${result.stdout}\n${result.stderr}`, /快速发布:跳过额外本地测试/);
|
||||
});
|
||||
|
||||
test('fast release wrapper delegates to runtime prod script with --mode fast', async () => {
|
||||
const source = await fs.readFile(
|
||||
path.join(ROOT, 'scripts', 'release-portal-fast-prod.sh'),
|
||||
'utf8',
|
||||
);
|
||||
assert.match(source, /release-portal-runtime-prod\.sh.*--mode fast/);
|
||||
});
|
||||
|
||||
test('fast production release skips canary promotion evidence in script', async () => {
|
||||
const source = await fs.readFile(
|
||||
path.join(ROOT, 'scripts', 'release-portal-runtime-prod.sh'),
|
||||
'utf8',
|
||||
);
|
||||
assert.match(source, /快速发布:跳过 103 灰度晋升证据/);
|
||||
assert.match(source, /verify-canary-promotion-evidence\.mjs/);
|
||||
assert.match(source, /release_mode=\$\{RELEASE_MODE\}/);
|
||||
});
|
||||
|
||||
test('production canary verifies the exact Gate artifact before any 103 preflight or upload', async () => {
|
||||
const source = await fs.readFile(CANARY_RELEASE, 'utf8');
|
||||
const gateIndex = source.indexOf('verify-release-gate-report.mjs');
|
||||
|
||||
Reference in New Issue
Block a user