升级 SpacetimeDB 工具链到 2.8.3 (#200)
Project CI / Repository checks (push) Successful in 2m52s
Project CI / Backend tests (push) Successful in 6m26s
Project CI / Frontend tests (push) Successful in 10m40s
Project CI / Native shell tests (push) Successful in 18m17s

将 spacetimedb、SDK、lib 精确升级到 2.8.3 并更新 Cargo.lock。

用 2.8.3 CLI 重新生成 spacetime-client Rust bindings。

同步本地 dev、生产 provision、容器镜像和事务 smoke 的版本与 commit 门禁。

更新后端契约、开发运维、项目记忆和 SpacetimeDB skills 的 2.8.3 口径。

---------

Co-authored-by: 段舒康 <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/200
Co-authored-by: suzmii <suzmii@qq.com>
Co-committed-by: suzmii <suzmii@qq.com>
This commit was merged in pull request #200.
This commit is contained in:
2026-08-27 17:10:17 +08:00
committed by 段舒康
parent d24321d657
commit 94521af890
195 changed files with 1651 additions and 1770 deletions
+36 -1
View File
@@ -20,7 +20,7 @@ const repoRoot = path.resolve(
'..',
);
const database = 'admin-account-smoke';
const expectedSpacetimeVersion = '2.7.0';
const expectedSpacetimeVersion = '2.8.3';
const commandTimeoutMs = 5 * 60 * 1000;
function assert(condition, message) {
@@ -144,6 +144,10 @@ async function stopStandalone(child) {
if (child.exitCode !== null) {
return;
}
if (process.platform === 'win32') {
await stopWindowsProcessTree(child);
return;
}
child.kill('SIGTERM');
const exited = await Promise.race([
once(child, 'exit').then(() => true),
@@ -155,6 +159,37 @@ async function stopStandalone(child) {
}
}
async function stopWindowsProcessTree(child) {
if (typeof child.pid === 'number') {
await runTaskKill(child.pid);
}
const exited = await Promise.race([
once(child, 'exit').then(() => true),
delay(5_000).then(() => false),
]);
if (!exited && child.exitCode === null) {
child.kill('SIGKILL');
await once(child, 'exit');
}
}
function runTaskKill(pid) {
return new Promise((resolve, reject) => {
const taskKill = spawn('taskkill', ['/PID', String(pid), '/T', '/F'], {
stdio: 'ignore',
shell: false,
});
taskKill.once('error', reject);
taskKill.once('exit', (code, signal) => {
if (code === 0 || code === 128 || code === 1) {
resolve();
return;
}
reject(new Error(`taskkill exited with ${signal ?? code}`));
});
});
}
async function callProcedure(serverUrl, token, procedureName, input) {
const response = await fetch(
`${serverUrl}/v1/database/${database}/call/${procedureName}`,
@@ -899,6 +899,46 @@ const checks = [
reason:
'Server-Provision Job 必须允许 dev/release 为 files-history 选择各自的 baseline state 目录。',
},
{
file: 'jenkins/Jenkinsfile.production-server-provision',
includes:
"string(name: 'SPACETIME_DOWNLOAD_ROOT', defaultValue: 'https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.8.3'",
reason:
'Server-Provision Job 的 SpacetimeDB 下载根必须与 workspace 锁定的 2.8.3 版本一致。',
},
{
file: 'jenkins/Jenkinsfile.production-server-provision',
includes:
"string(name: 'SPACETIME_EXPECTED_COMMIT', defaultValue: '8e410d2842147bd8e5a32a9589cc00c19f7478e2'",
reason:
'Server-Provision Job 必须锁定 SpacetimeDB 2.8.3 的 CLI commit,拒绝同版本号但构建来源不一致的二进制。',
},
{
file: 'jenkins/Jenkinsfile.production-server-provision',
includes:
'SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.8.3}"',
reason:
'Server-Provision 执行阶段的 SpacetimeDB 下载根默认值必须与 Job 参数默认值一致。',
},
{
file: 'jenkins/Jenkinsfile.production-server-provision',
includes:
'SPACETIME_EXPECTED_COMMIT="${SPACETIME_EXPECTED_COMMIT:-8e410d2842147bd8e5a32a9589cc00c19f7478e2}"',
reason:
'Server-Provision 执行阶段的 SpacetimeDB commit 默认值必须与 Job 参数默认值一致。',
},
{
file: 'jenkins/Jenkinsfile.production-server-provision',
excludes: 'v2.7.0-hotfix3',
reason:
'Server-Provision 不得保留已退役的 SpacetimeDB 2.7.0 hotfix 资产标签。',
},
{
file: 'jenkins/Jenkinsfile.production-server-provision',
excludes: 'd220349adb7af7eefa810eb08a185609356b83f6',
reason:
'Server-Provision 不得保留 SpacetimeDB 2.7.0 的旧 CLI commit 门禁。',
},
{
file: 'jenkins/Jenkinsfile.production-server-provision',
excludes:
+9 -9
View File
@@ -39,13 +39,13 @@ cat >"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-cli" <<'EOF'
#!/usr/bin/env bash
cat <<'VERSION'
spacetime Path: /tmp/spacetimedb-cli
Commit: d220349adb7af7eefa810eb08a185609356b83f6
spacetimedb tool version 2.7.0; spacetimedb-lib version 2.7.0;
Commit: 8e410d2842147bd8e5a32a9589cc00c19f7478e2
spacetimedb tool version 2.8.3; spacetimedb-lib version 2.8.3;
VERSION
EOF
cat >"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-standalone" <<'EOF'
#!/usr/bin/env bash
echo "spacetimedb-standalone 2.7.0"
echo "spacetimedb-standalone 2.8.3"
EOF
chmod +x \
"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-cli" \
@@ -94,13 +94,13 @@ cat >"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-cli" <<'EOF'
#!/usr/bin/env bash
cat <<'VERSION'
spacetime Path: /tmp/spacetimedb-cli
Commit: a08663c7b94688a2542577532d472f751e641f5b
spacetimedb tool version 2.7.0; spacetimedb-lib version 2.7.0;
Commit: 0000000000000000000000000000000000000000
spacetimedb tool version 2.8.3; spacetimedb-lib version 2.8.3;
VERSION
EOF
cat >"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-standalone" <<'EOF'
#!/usr/bin/env bash
echo "spacetimedb-standalone 2.7.0"
echo "spacetimedb-standalone 2.8.3"
EOF
chmod +x \
"${BARE_TAG_ROOT_DIR}/bin/current/spacetimedb-cli" \
@@ -119,14 +119,14 @@ if (
"${REPO_ROOT}/scripts/prepare-server-provision-tools.sh" \
>"${BARE_TAG_LOG}" 2>&1
); then
echo "[check-server-provision-tools] 裸 v2.7.0 tag 不应通过 hotfix3 复用门禁。" >&2
echo "[check-server-provision-tools] commit 不匹配的 v2.8.3 不应通过复用门禁。" >&2
cat "${BARE_TAG_LOG}" >&2
exit 1
fi
grep -q "SpacetimeDB commit 不匹配" "${BARE_TAG_LOG}"
if grep -q "复用目标机已有 SpacetimeDB 安装" "${BARE_TAG_LOG}"; then
echo "[check-server-provision-tools] 裸 v2.7.0 tag 被错误复用。" >&2
echo "[check-server-provision-tools] commit 不匹配的 v2.8.3 被错误复用。" >&2
cat "${BARE_TAG_LOG}" >&2
exit 1
fi
@@ -157,7 +157,7 @@ if (
"${REPO_ROOT}/scripts/prepare-server-provision-tools.sh" \
>"${BARE_ARCHIVE_LOG}" 2>&1
); then
echo "[check-server-provision-tools] 裸 v2.7.0 archive 不应通过 hotfix3 安装结果门禁。" >&2
echo "[check-server-provision-tools] commit 不匹配的 v2.8.3 archive 不应通过安装结果门禁。" >&2
cat "${BARE_ARCHIVE_LOG}" >&2
exit 1
fi
+1 -1
View File
@@ -759,7 +759,7 @@ function composeEnv() {
}
function localSpacetimeImageName() {
return `${projectName}-spacetimedb:2.7.0`;
return `${projectName}-spacetimedb:2.8.3`;
}
function spacetimeServerUrl(state) {
+4 -4
View File
@@ -614,8 +614,8 @@ function parseSpacetimeToolCommit(output) {
}
function expectedSpacetimeToolCommit(workspaceVersion) {
if (workspaceVersion === '2.7.0') {
return 'd220349adb7af7eefa810eb08a185609356b83f6';
if (workspaceVersion === '2.8.3') {
return '8e410d2842147bd8e5a32a9589cc00c19f7478e2';
}
return '';
}
@@ -623,7 +623,7 @@ function expectedSpacetimeToolCommit(workspaceVersion) {
function buildSpacetimeUpgradeInstruction(workspaceVersion) {
const expectedCommit = expectedSpacetimeToolCommit(workspaceVersion);
if (expectedCommit) {
return `请安装官方 v${workspaceVersion}-hotfix3 发行包并确认 spacetime --version 的 Commit 为 ${expectedCommit},然后重新运行本命令。`;
return `请安装官方 v${workspaceVersion} 发行包并确认 spacetime --version 的 Commit 为 ${expectedCommit},然后重新运行本命令。`;
}
return `请先直接升级并切换到锁定版本: spacetime version install ${workspaceVersion} && spacetime version use ${workspaceVersion},然后重新运行本命令。`;
}
@@ -667,7 +667,7 @@ function assertSpacetimeToolVersionMatchesWorkspace({
throw new Error(
[
`本机 spacetime CLI/standalone 虽报告 ${toolVersion},但构建 commit ${toolCommit || 'unknown'} 不是项目锁定的 ${expectedCommit}。`,
'同版本号的裸 tag 缺少后续 hotfix,不能用于本地 SpacetimeDB。',
'同版本号但 commit 不匹配的构建存在发布资产差异风险,不能用于本地 SpacetimeDB。',
buildSpacetimeUpgradeInstruction(workspaceVersion),
].join(''),
);
+17 -17
View File
@@ -773,7 +773,7 @@ describe('dev scheduler spacetime reuse guard', () => {
writeFileSync(join(tempDir, 'spacetime.pid'), `${process.pid}\n`, 'utf8');
writeFileSync(
join(tempDir, 'dev-spacetime-tool-version'),
`${workspaceSpacetimeVersionForTest()}\nd220349adb7af7eefa810eb08a185609356b83f6\n`,
`${workspaceSpacetimeVersionForTest()}\n8e410d2842147bd8e5a32a9589cc00c19f7478e2\n`,
'utf8',
);
globalThis.fetch = vi.fn(async () => ({
@@ -802,7 +802,7 @@ describe('dev scheduler spacetime reuse guard', () => {
writeFileSync(join(tempDir, 'spacetime.pid'), `${process.pid}\n`, 'utf8');
writeFileSync(
join(tempDir, 'dev-spacetime-tool-version'),
`${workspaceSpacetimeVersionForTest()}\nd220349adb7af7eefa810eb08a185609356b83f6\n`,
`${workspaceSpacetimeVersionForTest()}\n8e410d2842147bd8e5a32a9589cc00c19f7478e2\n`,
'utf8',
);
globalThis.fetch = vi.fn(async () => ({
@@ -915,30 +915,30 @@ describe('dev scheduler spacetime refresh', () => {
test('解析 spacetime --version 输出里的 tool version', () => {
const output = `
A new version of SpacetimeDB is available: v2.6.1 (current: v2.5.0)
Commit: d220349adb7af7eefa810eb08a185609356b83f6
spacetimedb tool version 2.7.0; spacetimedb-lib version 2.7.0;
Commit: 8e410d2842147bd8e5a32a9589cc00c19f7478e2
spacetimedb tool version 2.8.3; spacetimedb-lib version 2.8.3;
`;
expect(parseSpacetimeToolVersion(output)).toBe('2.7.0');
expect(parseSpacetimeToolVersion(output)).toBe('2.8.3');
expect(parseSpacetimeToolCommit(output)).toBe(
'd220349adb7af7eefa810eb08a185609356b83f6',
'8e410d2842147bd8e5a32a9589cc00c19f7478e2',
);
});
test('同为 2.7.0 时拒绝裸 tag 并接受 hotfix3 commit', () => {
test('同为 2.8.3 时拒绝 commit 不匹配并接受锁定 commit', () => {
expect(() =>
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: '2.7.0',
toolCommit: 'a08663c7b94688a2542577532d472f751e641f5b',
workspaceVersion: '2.7.0',
toolVersion: '2.8.3',
toolCommit: '0000000000000000000000000000000000000000',
workspaceVersion: '2.8.3',
}),
).toThrow('裸 tag');
).toThrow('构建 commit');
expect(() =>
assertSpacetimeToolVersionMatchesWorkspace({
toolVersion: '2.7.0',
toolCommit: 'd220349adb7af7eefa810eb08a185609356b83f6',
workspaceVersion: '2.7.0',
toolVersion: '2.8.3',
toolCommit: '8e410d2842147bd8e5a32a9589cc00c19f7478e2',
workspaceVersion: '2.8.3',
}),
).not.toThrow();
});
@@ -974,14 +974,14 @@ spacetimedb tool version 2.7.0; spacetimedb-lib version 2.7.0;
}
});
test('复用本地 SpacetimeDB standalone 时拒绝同版本裸 tag 记录', () => {
test('复用本地 SpacetimeDB standalone 时拒绝同版本但 commit 不匹配的记录', () => {
const tempDir = mkdtempSync(
join(tmpdir(), 'genarrative-spacetime-commit-'),
);
try {
writeFileSync(
join(tempDir, 'dev-spacetime-tool-version'),
'2.7.0\na08663c7b94688a2542577532d472f751e641f5b\n',
'2.8.3\n0000000000000000000000000000000000000000\n',
'utf8',
);
@@ -990,7 +990,7 @@ spacetimedb tool version 2.7.0; spacetimedb-lib version 2.7.0;
dataDir: tempDir,
serverUrl: 'http://127.0.0.1:3101',
}),
).toThrow('裸 tag');
).toThrow('构建 commit');
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
+2 -2
View File
@@ -9,11 +9,11 @@ OTELCOL_DOWNLOAD_ROOT="${OTELCOL_DOWNLOAD_ROOT:-https://github.com/open-telemetr
OTELCOL_ARCHIVE_PATH="${OTELCOL_ARCHIVE_PATH:-}"
OTELCOL_TARGET_BIN="${OTELCOL_TARGET_BIN:-/usr/local/bin/otelcol-contrib}"
SPACETIME_INSTALLER_URL="${SPACETIME_INSTALLER_URL:-https://install.spacetimedb.com}"
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.7.0-hotfix3}"
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.8.3}"
SPACETIME_TARGET_HOST="${SPACETIME_TARGET_HOST:-x86_64-unknown-linux-gnu}"
SPACETIME_ROOT="${SPACETIME_ROOT:-/stdb}"
SPACETIME_EXPECTED_VERSION="${SPACETIME_EXPECTED_VERSION:-}"
SPACETIME_EXPECTED_COMMIT="${SPACETIME_EXPECTED_COMMIT:-d220349adb7af7eefa810eb08a185609356b83f6}"
SPACETIME_EXPECTED_COMMIT="${SPACETIME_EXPECTED_COMMIT:-8e410d2842147bd8e5a32a9589cc00c19f7478e2}"
SPACETIME_ARCHIVE_PATH="${SPACETIME_ARCHIVE_PATH:-}"
SPACETIME_INSTALLER_PATH="${SPACETIME_INSTALLER_PATH:-}"
SPACETIME_UPDATE_INSTALLER_PATH="${SPACETIME_UPDATE_INSTALLER_PATH:-}"
+37 -2
View File
@@ -16,8 +16,8 @@ const repoRoot = path.resolve(
'..',
);
const database = 'editor-idempotency-smoke';
const expectedSpacetimeVersion = '2.7.0';
const expectedSpacetimeCommit = 'd220349adb7af7eefa810eb08a185609356b83f6';
const expectedSpacetimeVersion = '2.8.3';
const expectedSpacetimeCommit = '8e410d2842147bd8e5a32a9589cc00c19f7478e2';
const commandTimeoutMs = 5 * 60 * 1000;
function assert(condition, message) {
@@ -228,6 +228,10 @@ export async function stopStandalone(child) {
if (child.exitCode !== null) {
return;
}
if (process.platform === 'win32') {
await stopWindowsProcessTree(child);
return;
}
child.kill('SIGTERM');
const exited = await Promise.race([
once(child, 'exit').then(() => true),
@@ -239,6 +243,37 @@ export async function stopStandalone(child) {
}
}
async function stopWindowsProcessTree(child) {
if (typeof child.pid === 'number') {
await runTaskKill(child.pid);
}
const exited = await Promise.race([
once(child, 'exit').then(() => true),
delay(5_000).then(() => false),
]);
if (!exited && child.exitCode === null) {
child.kill('SIGKILL');
await once(child, 'exit');
}
}
function runTaskKill(pid) {
return new Promise((resolve, reject) => {
const taskKill = spawn('taskkill', ['/PID', String(pid), '/T', '/F'], {
stdio: 'ignore',
shell: false,
});
taskKill.once('error', reject);
taskKill.once('exit', (code, signal) => {
if (code === 0 || code === 128 || code === 1) {
resolve();
return;
}
reject(new Error(`taskkill exited with ${signal ?? code}`));
});
});
}
function cliPrefix(configPath) {
return ['--config-path', configPath];
}