// ============================================================ // pre-build-check.mjs — 构建前校验 // // 用法: // node build/scripts/pre-build-check.mjs // // 检查项: // 1. Git 工作区是否干净(有未提交变更时警告,非阻断) // 2. CHANGELOG.md 是否包含当前版本条目 // 3. package.json 版本号与传入版本号一致 // 4. 渠道版本号格式校验(beta/alpha 必须含预发布后缀) // ============================================================ import { readFileSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { execSync } from 'node:child_process'; const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT = join(__dirname, '..', '..'); const platform = process.argv[2]; const version = process.argv[3]; const channel = process.argv[4] || 'stable'; if (!platform || !version) { console.error('用法: node build/scripts/pre-build-check.mjs [channel]'); process.exit(1); } let hasError = false; // ---------- 1. Git 工作区检查 ---------- console.log('▸ 检查 Git 工作区状态...'); try { const status = execSync('git status --porcelain', { cwd: ROOT, encoding: 'utf-8' }).trim(); if (status) { console.warn('⚠️ 警告: Git 工作区有未提交的变更:'); const lines = status.split('\n').slice(0, 10); lines.forEach((l) => console.warn(` ${l}`)); if (status.split('\n').length > 10) { console.warn(` ... 还有 ${status.split('\n').length - 10} 个文件`); } console.warn(' (不阻断构建,但建议先提交)\n'); } else { console.log(' ✅ Git 工作区干净\n'); } } catch { console.warn(' ⚠️ 非 Git 环境,跳过工作区检查\n'); } // ---------- 2. CHANGELOG 版本条目检查 ---------- console.log('▸ 检查 CHANGELOG.md 版本条目...'); const changelogPath = join(ROOT, 'CHANGELOG.md'); try { const changelogContent = readFileSync(changelogPath, 'utf-8'); const versionPattern = new RegExp( `^##\\s+${version.replace(/\./g, '\\.')}\\b`, 'm', ); if (versionPattern.test(changelogContent)) { console.log(` ✅ CHANGELOG.md 已包含 v${version} 条目\n`); } else { console.error(` ❌ CHANGELOG.md 中未找到 v${version} 的更新日志条目`); console.error(` 请在 CHANGELOG.md 顶部添加: ## ${version}(日期)\n`); hasError = true; } } catch { console.warn(' ⚠️ CHANGELOG.md 不存在,跳过版本条目检查\n'); } // ---------- 3. package.json 版本号一致性 ---------- console.log('▸ 检查 package.json 版本一致性...'); const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8')); if (pkg.version === version) { console.log(` ✅ package.json 版本号一致: ${version}\n`); } else { console.error(` ❌ 版本号不一致: 传入 ${version},package.json 为 ${pkg.version}`); console.error(' 请先执行: node build/scripts/bump-version.mjs \n'); hasError = true; } // ---------- 4. 渠道版本号格式校验 ---------- console.log('▸ 检查渠道版本号格式...'); if (channel === 'stable') { // stable 版本号必须是纯 semver(如 0.0.28) if (/^\d+\.\d+\.\d+$/.test(version)) { console.log(' ✅ Stable 渠道版本号格式正确\n'); } else { console.error(` ❌ Stable 渠道版本号必须为纯 semver 格式 (x.y.z),当前: ${version}\n`); hasError = true; } } else { // beta/alpha 版本号必须含预发布后缀(如 0.0.29-beta.1) if (/-/.test(version)) { console.log(` ✅ ${channel} 渠道版本号含预发布后缀\n`); } else { console.warn(` ⚠️ ${channel} 渠道建议使用预发布版本号(如 ${version}-${channel}.1)`); console.warn(' 当前版本号不含预发布后缀,可能覆盖 stable 版本的 OSS 文件\n'); } } // ---------- 5. 环境变量检查(仅 upload/publish 时有效,此处仅提示) ---------- console.log('▸ 环境变量就绪检查...'); const uploadVars = ['OSS_ENDPOINT', 'OSS_BUCKET', 'OSS_ACCESS_KEY_ID', 'OSS_ACCESS_KEY_SECRET']; const missingUpload = uploadVars.filter((v) => !process.env[v]); if (missingUpload.length > 0) { console.warn(` ⚠️ OSS 相关环境变量未设置: ${missingUpload.join(', ')}`); console.warn(' 如需上传 OSS,请配置这些环境变量(或在 .env.local 中设置)'); } else { console.log(' ✅ OSS 环境变量已配置'); } if (!process.env.UPDATE_API_KEY) { console.warn(' ⚠️ UPDATE_API_KEY 未设置,发布到 API 可能失败'); } else { console.log(' ✅ UPDATE_API_KEY 已配置'); } console.log(''); // ---------- 结果 ---------- if (hasError) { console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); console.error('❌ 构建前校验未通过,请修复以上问题后重试'); console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); process.exit(1); } console.log('✅ 构建前校验全部通过');