Files
Genarrative/scripts/spacetime-export-migration-json.mjs
kdletters 1ccb8a710d
Some checks failed
CI / verify (push) Has been cancelled
Add migration token parameters to Jenkins deploy flows
2026-04-30 10:48:58 +08:00

136 lines
3.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
import { writeFile } from 'node:fs/promises';
import path from 'node:path';
import {
callSpacetimeProcedure,
callSpacetimeProcedureViaCli,
createSpacetimeWebIdentity,
ensureParentDir,
ensureProcedureOk,
parseArgs,
} from './spacetime-migration-common.mjs';
try {
const options = parseArgs(process.argv.slice(2));
if (!options.out) {
throw new Error('必须传入 --out。');
}
const input = {
include_tables: options.includeTables,
};
const webOptions = await prepareWebExportOptions(options);
let result;
try {
result = await callSpacetimeProcedure(webOptions, 'export_database_migration_to_file', input);
} finally {
await revokeTemporaryWebIdentity(webOptions);
}
ensureProcedureOk(result);
if (typeof result.migration_json !== 'string' || result.migration_json.trim() === '') {
throw new Error('导出 procedure 没有返回 migration_json。');
}
const outPath = path.resolve(options.out);
await ensureParentDir(outPath);
await writeFile(outPath, result.migration_json, 'utf8');
console.log(`[spacetime:migration:export] 已写入 ${outPath}`);
printTableStats(result.table_stats);
printMigrationWarnings(result.warnings);
} catch (error) {
console.error(
`[spacetime:migration:export] ${error instanceof Error ? error.message : String(error)}`,
);
process.exit(1);
}
async function prepareWebExportOptions(options) {
if (options.token) {
return { ...options, useHttp: true };
}
const identity = await createSpacetimeWebIdentity(options);
console.log(
`[spacetime:migration:export] 已通过 Web API 创建临时 identity: ${identity.identity}`,
);
try {
const authorizeResult = await callSpacetimeProcedureViaCli(
options,
'authorize_database_migration_operator',
{
bootstrap_secret: options.bootstrapSecret || '',
operator_identity_hex: identity.identity,
note: options.note || 'temporary web api migration export',
},
);
ensureProcedureOk(authorizeResult);
} catch (error) {
throw new Error(
`授权临时 Web API identity 失败。当前 spacetime CLI identity 必须已经是迁移操作员如果旧库迁移操作员表不为空bootstrap secret 不会越权授权新的操作员。可先用已有迁移操作员授权当前部署机 identity或为导出脚本提供已有迁移操作员的 --token。原始错误: ${
error instanceof Error ? error.message : String(error)
}`,
);
}
console.log(`[spacetime:migration:export] 已授权临时 Web API identity`);
return {
...options,
token: identity.token,
temporaryWebIdentity: identity.identity,
useHttp: true,
};
}
async function revokeTemporaryWebIdentity(options) {
if (!options.temporaryWebIdentity) {
return;
}
try {
const revokeResult = await callSpacetimeProcedure(
options,
'revoke_database_migration_operator',
{ operator_identity_hex: options.temporaryWebIdentity },
);
ensureProcedureOk(revokeResult);
console.log(`[spacetime:migration:export] 已撤销临时 Web API identity`);
} catch (error) {
console.warn(
`[spacetime:migration:export] 撤销临时 Web API identity 失败: ${
error instanceof Error ? error.message : String(error)
}`,
);
}
}
function printTableStats(tableStats) {
if (!Array.isArray(tableStats) || tableStats.length === 0) {
return;
}
const rows = tableStats.map((stat) => ({
table: stat.table_name,
exported: stat.exported_row_count,
}));
console.table(rows);
}
function printMigrationWarnings(warnings) {
if (!Array.isArray(warnings) || warnings.length === 0) {
return;
}
console.warn('[spacetime:migration:export] 迁移告警:');
console.table(
warnings.map((warning) => ({
table: warning.table_name,
kind: warning.warning_kind,
message: warning.message,
})),
);
}