Files
lingxi/scripts/ci-local.mjs
T
Stev_Wang 88d9c77522 fix(ci): 修复全新检出 Lint 失败并恢复 main 自动触发
背景:run #37 在 runner 上失败于 Lint,日志报 @lingxi/* 下发类型无法解析——
workspace 包 types 指向 dist/,而 dist/ 被 gitignore,全新检出未构建导致
类型感知规则失效;另 postgres 健康检查 -U lingxi 与 POSTGRES_USER=postgres 不一致。

改动:
- ci.yml:Lint 前新增 packages 构建步骤;健康检查改为 pg_isready -U postgres;
  恢复 push main 自动触发(保留 workflow_dispatch)。
- ci-local.mjs:同步补充 packages 构建步骤,避免全新检出本地 CI 同样失败。

影响面:仅 CI 配置与本地 CI 脚本,不改业务代码;push main 后自动跑完整门禁。
回滚方式:revert 本提交;如需临时停用远端 CI,注释 on.push。
验证证据:runner 冒烟 run #38 全绿(ci-smoke.yml,71s);本提交推送后由远端 ci.yml 完整链路验证。
2026-11-04 17:52:16 +08:00

64 lines
2.5 KiB
JavaScript
Raw 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
/**
* 本地 CI:按 .gitea/workflows/ci.yml 的门禁顺序执行(推送前强制;远端 Gitea Actions 为第二道防线)。
* 用法:pnpm ci:local(推荐通过 ./.tools/pnpm ci:local 锁定 pnpm 10)
*/
import { spawnSync } from 'node:child_process';
const pnpm = process.env.npm_execpath ? [process.execPath, process.env.npm_execpath] : ['pnpm'];
/**
* 端到端冒烟走 vite preview + demo 会话,需与 .gitea/workflows/ci.yml 的 job env 对齐;
* 只加在构建与 e2e 步骤,避免影响单测里对真实登录流程的断言。
*/
const e2eEnv = {
VITE_PUBLIC_API_BASE_URL: process.env.VITE_PUBLIC_API_BASE_URL ?? 'http://127.0.0.1:3000/api/v1',
VITE_PUBLIC_DEMO_SESSION: process.env.VITE_PUBLIC_DEMO_SESSION ?? 'true',
};
/** 每一步可包含多条 pnpm 命令,任一失败立即退出;env 为该步骤追加的环境变量。 */
const steps = [
{ label: '检查本地依赖(PG / Redis)', commands: [['check:dev']] },
{
label: '构建 workspace 包(Lint 类型解析前置)',
commands: [['exec', 'turbo', 'run', 'build', '--filter=./packages/*']],
},
{ label: '格式化检查', commands: [['format:check']] },
{ label: 'Lint', commands: [['lint']] },
{ label: '类型检查', commands: [['typecheck']] },
{ label: '单元测试', commands: [['test']] },
{ label: '构建', commands: [['build']], env: e2eEnv },
{
label: '数据库迁移与种子',
commands: [['exec', 'prisma', 'migrate', 'deploy'], ['db:seed']],
},
{ label: '集成测试', commands: [['test:int']] },
{ label: 'OpenAPI 导出与契约检查', commands: [['openapi:export'], ['openapi:diff']] },
{ label: '端到端测试', commands: [['test:e2e']], env: e2eEnv },
];
function runPnpm(args, env = {}) {
const result = spawnSync(pnpm[0], [...pnpm.slice(1), ...args], {
env: { ...process.env, ...env },
stdio: 'inherit',
});
if (result.error) {
console.error(`\n执行 pnpm ${args.join(' ')} 失败:${result.error.message}`);
process.exit(1);
}
if (result.status !== 0) {
console.error(`\n门禁失败:pnpm ${args.join(' ')}(exit ${result.status ?? 1})`);
process.exit(result.status ?? 1);
}
}
const startedAt = Date.now();
for (const [index, step] of steps.entries()) {
console.log(`\n[${index + 1}/${steps.length}] ${step.label}`);
for (const args of step.commands) {
runPnpm(args, step.env);
}
}
const seconds = ((Date.now() - startedAt) / 1000).toFixed(1);
console.log(`\n本地 CI 全部门禁通过,用时 ${seconds}s。`);