import { execFileSync } from 'node:child_process'; import path from 'node:path'; import process from 'node:process'; import { fileURLToPath } from 'node:url'; /** * 生成命令可以覆盖旧文件,但覆盖不等于契约已同步提交;这里仅检查指定生成物, * 避免用户其他工作区改动干扰契约门禁。 */ export function assertGeneratedContractsUnchanged(repositoryRoot, contractFiles) { for (const contractFile of contractFiles) { try { execFileSync('git', ['ls-files', '--error-unmatch', '--', contractFile], { cwd: repositoryRoot, encoding: 'utf8', stdio: ['ignore', 'ignore', 'pipe'], }); } catch { throw new Error(`生成契约未纳入 Git 跟踪:${contractFile}`); } } try { execFileSync('git', ['diff', '--exit-code', '--', ...contractFiles], { cwd: repositoryRoot, encoding: 'utf8', stdio: ['ignore', 'ignore', 'pipe'], }); } catch { throw new Error(`生成契约与 Git 提交版本不一致:${contractFiles.join('、')}`); } } const currentFile = fileURLToPath(import.meta.url); if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(currentFile)) { assertGeneratedContractsUnchanged(process.cwd(), [ 'server/openapi/openapi.json', 'web/src/api/generated/schema.ts', ]); process.stdout.write('生成契约与 Git 提交版本一致\n'); }