/** * bump-version.js — 构建时自动递增 package.json 版本号 * * 逻辑: * 检查自上次构建以来的 git commit,若仅包含工程化变更(chore/build/ci/auto bump)或没有新 commit, * 则跳过版本号递增,保持当前版本号。 * 否则按指定类型(默认 patch)递增版本号。 * * 用法: node scripts/bump-version.js [patch|minor|major] * 默认 patch,每次 npm run build 前自动执行 */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const pkgPath = path.resolve(__dirname, '..', 'package.json'); const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')); const rootDir = path.resolve(__dirname, '..'); const lastBuildFile = path.join(rootDir, '.last_build_commit'); // ----- 判断是否有有效变更 ----- let hasMeaningfulChanges = true; try { let fromHash = ''; try { fromHash = fs.readFileSync(lastBuildFile, 'utf-8').trim(); } catch { fromHash = ''; } if (fromHash) { const range = `${fromHash}..HEAD`; const log = execSync( `git log --no-merges --pretty=format:"%s" ${range}`, { cwd: rootDir, encoding: 'utf-8' } ).trim(); const commits = log ? log.split('\n').filter(Boolean) : []; if (commits.length === 0) { hasMeaningfulChanges = false; console.log('[bump-version] 没有新 commit,跳过版本号递增'); } else { const allChore = commits.every(msg => { const s = msg.toLowerCase().trim(); return ( s.startsWith('chore:') || s.startsWith('chore(') || s.startsWith('build:') || s.startsWith('build(') || s.startsWith('ci:') || s.startsWith('ci(') || /auto ?bump/i.test(s) || /工程化/.test(s) || /skip ?ci/i.test(s) ); }); if (allChore) { hasMeaningfulChanges = false; console.log(`[bump-version] 仅有工程化变更(${commits.length} 条),跳过版本号递增`); } else { console.log(`[bump-version] 检测到 ${commits.length} 条提交,其中 ${commits.filter(msg => { const s = msg.toLowerCase().trim(); return !(s.startsWith('chore:') || s.startsWith('chore(') || s.startsWith('build:') || s.startsWith('build(') || s.startsWith('ci:') || s.startsWith('ci(') || /auto ?bump/i.test(s) || /工程化/.test(s) || /skip ?ci/i.test(s)); }).length} 条有效变更`); } } } else { console.log('[bump-version] 首次构建,正常递增版本号'); } } catch (e) { console.warn(`[bump-version] 检查变更失败(${e.message}),回退到默认递增`); hasMeaningfulChanges = true; } // ----- 版本号递增 ----- if (!hasMeaningfulChanges) { console.log(`[bump-version] 保持版本号 ${pkg.version}`); process.exit(0); } const current = pkg.version; const parts = current.split('.').map(Number); if (parts.length !== 3 || parts.some(isNaN)) { console.error(`[bump-version] 无效版本号: ${current}`); process.exit(1); } const type = process.argv[2] || 'patch'; switch (type) { case 'major': parts[0] += 1; parts[1] = 0; parts[2] = 0; break; case 'minor': parts[1] += 1; parts[2] = 0; break; case 'patch': default: parts[2] += 1; break; } const next = parts.join('.'); pkg.version = next; fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8'); console.log(`[bump-version] ${current} → ${next}`);