发布链路加固:要求版本已提交后再发布

- 新增 assertVersionCommitted:发布前确认 5 个版本来源相对 HEAD 已提交,避免仅 bump 未提交就 release 导致本地与 Jenkins 检出版本不一致

- release-upload 在取版本、OSS 防降级前调用该守卫

- 更新 AGC 更新技术方案文档,并补发布校验回归测试
This commit is contained in:
2026-09-07 14:09:16 +08:00
parent fcc3c39dad
commit 64b9ccfb9d
4 changed files with 32 additions and 1 deletions
@@ -5,6 +5,7 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
const appRoot = fileURLToPath(new URL('..', import.meta.url));
const repoRoot = path.resolve(appRoot, '../..');
const defaultReleaseTarget = 'x86_64-pc-windows-msvc';
const releaseTarget =
process.env.AGC_BUILD_TARGET?.trim() || defaultReleaseTarget;
@@ -199,6 +200,23 @@ export function writeVersionFiles(version) {
return nextVersion;
}
export function assertVersionCommitted() {
const repoPaths = versionFileSources.map((source) =>
path.relative(repoRoot, source.file).replaceAll('\\', '/'),
);
const changed =
spawnSync(
'git',
['diff', '--quiet', 'HEAD', '--', ...repoPaths],
{ cwd: repoRoot },
).status === 1;
if (changed) {
throw new Error(
'版本文件相对 HEAD 存在未提交改动,请先提交后再发布:运行 npm --prefix apps/ai-game-creator-shell run bump-version -- --commit',
);
}
}
export function prepareReleaseVersion() {
const localVersion = readLocalVersion();
validateVersionConsistency(localVersion);
@@ -78,3 +78,12 @@ test('release upload forces overwrite for versioned artifact and latest pointer'
2,
);
});
test('release upload verifies the version is committed and not below OSS', () => {
const source = readFileSync(
new URL('./release-upload.mjs', import.meta.url),
'utf8',
);
assert.match(source, /assertVersionCommitted\(\)/u);
assert.match(source, /assertVersionNotBelowOss\(/u);
});
@@ -10,6 +10,7 @@ if (!/^[a-z0-9][a-z0-9.-]{1,62}$/u.test(bucket) || /[\r\n\0]/u.test(endpoint)) {
process.env.AGC_UPDATE_OSS_BASE_URL ||= `https://${bucket}.${endpoint}/agc`;
const {
assertVersionCommitted,
assertVersionNotBelowOss,
generateUpdateManifest,
prepareReleaseVersion,
@@ -41,6 +42,7 @@ function runOssutil(args) {
}
const releaseVersion = await prepareReleaseVersion();
assertVersionCommitted();
await assertVersionNotBelowOss(releaseVersion);
runTauriBuild([]);
const { artifact, manifestPath, manifest } = generateUpdateManifest();
@@ -67,7 +67,9 @@ npm run ai-game-creator-shell:bump-version -- --version 0.1.25 --commit
构建/发布不再改写版本文件,而是读取仓库已提交版本,并在发布前做两件事:
1. 校验五个版本来源一致,不一致会中止,防止漂移。
2. 通过 `assertVersionNotBelowOss` 读取 OSS `latest.json`:若仓库版本**低于**线上版本会中止,
2. 校验版本相对 `HEAD` 已提交(`assertVersionCommitted`:若版本文件存在未提交改动会中止,
确保本地发布与 Jenkins 检出的是同一个版本。
3. 通过 `assertVersionNotBelowOss` 读取 OSS `latest.json`:若仓库版本**低于**线上版本会中止,
并提示先运行 `bump-version`,避免回退线上版本;OSS 读取失败或清单格式错误同样会中止。
仓库版本等于或高于线上版本才放行。