Files
Genarrative/apps/ai-game-creator-shell/scripts/agc-global-version.test.mjs
T
suzmii 8cffbf6112 回退合并时被钩子误格式化的无关文件
过程中发现并修复:本地 pre-commit 钩子在提交合并时pipeline里prettier会重排无关文件,导致本PR携带与客户端无关的上下文
本提交把20个纯格式化文件恢复为主线内容,PR只保留macOS构建管线和发布链路相关改动
后续提交不再把这些文件纳入范围
2026-09-21 00:47:05 +08:00

207 lines
6.0 KiB
JavaScript

import assert from 'node:assert/strict';
import { test } from 'node:test';
import {
assertRequestedVersionNotBelowChannel,
buildOssutilArgs,
issueGlobalVersion,
maxVersion,
nextVersion,
previewNextGlobalVersion,
resolveSeedBaseline,
} from './agc-global-version.mjs';
function jsonResponse(payload, status = 200) {
return {
ok: status >= 200 && status < 300,
status,
json: async () => payload,
};
}
/** 以 URL 为键的假 OSS:只读 fetch + 记录写入。 */
function createFakeOss({ objects = {} } = {}) {
const state = { ...objects };
const writes = [];
return {
state,
writes,
fetchImpl: async (url) => {
const key = String(url).replace(/^https?:\/\/[^/]+\//u, '');
if (!(key in state)) return jsonResponse(null, 404);
return jsonResponse(state[key]);
},
writeImpl: (payload, options = {}) => {
writes.push({ payload, dryRun: Boolean(options.dryRun) });
if (!options.dryRun) state['agc/global-version.json'] = payload;
return { written: !options.dryRun, payload };
},
};
}
test('播种基线取仓库版本、各渠道清单与旧迁移指针的最大值', async () => {
const oss = createFakeOss({
objects: {
'agc/dev-win/latest.json': { version: '0.1.57' },
'agc/dev-mac/latest.json': { version: '0.1.12' },
'agc/latest.json': { version: '0.1.60' },
},
});
assert.equal(
await resolveSeedBaseline({
repoVersion: '0.1.48',
env: {},
fetchImpl: oss.fetchImpl,
}),
'0.1.60',
);
assert.equal(maxVersion('0.1.9', '0.1.10', null), '0.1.10');
});
test('无总号时按播种基线发首号,并把总号写回唯一事实源', async () => {
const oss = createFakeOss({
objects: {
'agc/dev-win/latest.json': { version: '0.1.57' },
'agc/dev-mac/latest.json': { version: '0.1.12' },
},
});
const issued = await issueGlobalVersion({
channel: 'dev-win',
commit: 'a'.repeat(40),
buildId: '319',
repoVersion: '0.1.48',
env: {},
fetchImpl: oss.fetchImpl,
writeImpl: oss.writeImpl,
now: () => '2026-09-20T00:00:00.000Z',
});
assert.equal(issued, '0.1.58');
assert.deepEqual(
oss.writes.map((entry) => entry.payload.version),
['0.1.58'],
);
assert.equal(oss.state['agc/global-version.json'].version, '0.1.58');
assert.equal(oss.state['agc/global-version.json'].channel, 'dev-win');
assert.equal(oss.state['agc/global-version.json'].buildId, '319');
});
test('已有总号时只递增,不再回看渠道清单', async () => {
const oss = createFakeOss({
objects: {
'agc/global-version.json': { version: '0.2.7' },
// 渠道清单被手工改小也不能把总号拉回去。
'agc/dev-win/latest.json': { version: '0.1.10' },
},
});
const issued = await issueGlobalVersion({
channel: 'dev-mac',
env: {},
fetchImpl: oss.fetchImpl,
writeImpl: oss.writeImpl,
});
assert.equal(issued, '0.2.8');
assert.equal(oss.state['agc/global-version.json'].version, '0.2.8');
});
test('dry-run 只预览下一位,不写回、不烧号', async () => {
const oss = createFakeOss({
objects: { 'agc/global-version.json': { version: '0.3.4' } },
});
const preview = await previewNextGlobalVersion({
env: {},
fetchImpl: oss.fetchImpl,
});
assert.equal(preview, '0.3.5');
assert.equal(oss.writes.length, 0);
const issued = await issueGlobalVersion({
channel: 'dev-win',
env: { AGC_RELEASE_DRY_RUN: '1' },
fetchImpl: oss.fetchImpl,
writeImpl: oss.writeImpl,
});
assert.equal(issued, '0.3.5');
assert.deepEqual(
oss.writes.map((entry) => entry.dryRun),
[true],
);
assert.equal(oss.state['agc/global-version.json'].version, '0.3.4');
});
test('传入低于本渠道清单的号时失败关闭', () => {
assert.equal(
assertRequestedVersionNotBelowChannel({
requested: '0.1.60',
channelVersion: '0.1.60',
channel: 'dev-win',
}),
'0.1.60',
);
assert.throws(
() =>
assertRequestedVersionNotBelowChannel({
requested: '0.1.59',
channelVersion: '0.1.60',
channel: 'dev-win',
}),
/低于 dev-win 渠道当前清单版本/u,
);
assert.equal(
assertRequestedVersionNotBelowChannel({
requested: '0.1.1',
channelVersion: null,
channel: 'dev-mac',
}),
'0.1.1',
);
});
test('写后回读不一致(并发发号)时失败关闭', async () => {
const oss = createFakeOss({
objects: { 'agc/global-version.json': { version: '0.5.1' } },
});
await assert.rejects(
issueGlobalVersion({
channel: 'dev-win',
env: {},
// 模拟另一个发号进程在写入后覆盖了总号。
writeImpl: (payload, options) => {
const result = oss.writeImpl(payload, options);
// 另一个发号进程紧随其后覆盖总号。
oss.state['agc/global-version.json'] = { version: '0.5.9' };
return result;
},
fetchImpl: oss.fetchImpl,
}),
/写后回读不一致/u,
);
});
test('nextVersion 只在 patch 位递增', () => {
assert.equal(nextVersion('0.1.9'), '0.1.10');
assert.equal(nextVersion('1.0.0'), '1.0.1');
assert.throws(() => nextVersion('0.1'), /不是有效的三段版本号/u);
});
test('ossutil 参数默认使用 v1 签名,并可按需带 region 与 v4', () => {
const base = {
args: ['cp', '--force', '/tmp/a.json', 'oss://agc-dev/agc/global-version.json'],
endpoint: 'oss-rg-china-mainland.aliyuncs.com',
accessKeyId: 'id',
accessKeySecret: 'secret',
env: {},
};
const v1 = buildOssutilArgs(base);
assert.equal(v1[v1.indexOf('--sign-version') + 1], 'v1');
assert.ok(!v1.includes('--region'));
assert.equal(v1[v1.indexOf('--access-key-id') + 1], 'id');
assert.equal(v1[v1.indexOf('--access-key-secret') + 1], 'secret');
const v4 = buildOssutilArgs({
...base,
env: { AGC_OSS_SIGN_VERSION: 'v4', AGC_OSS_REGION: 'cn-beijing' },
});
assert.equal(v4[v4.indexOf('--region') + 1], 'cn-beijing');
assert.equal(v4[v4.indexOf('--sign-version') + 1], 'v4');
});