import inquirer from 'inquirer' import { execSync } from 'child_process' import fs from 'fs' // 运行命令 const run = (cmd) => execSync(cmd, { stdio: 'inherit' }) // Git 工作区是否干净 const isGitClean = () => { const status = execSync('git status --porcelain').toString().trim() return status === '' } // 获取最新 tag const getLatestTag = () => { try { return execSync('git describe --tags --abbrev=0').toString().trim() } catch { return '' } } // 获取最新 tag 到现在的提交记录 const getCommitsSinceTag = (tag) => { try { const range = tag ? `${tag}..HEAD` : 'HEAD' return execSync(`git log ${range} --pretty=format:%s`).toString().trim() } catch { return '' } } // 检查是否有符合 Angular 规范的提交 const hasConventionalCommits = (log) => { return /^(feat|fix|docs|style|refactor|perf|test|chore)(\(.+\))?:/m.test(log) } // 1. 检查 git 工作区 if (!isGitClean()) { console.error('❌ Git 工作区有未提交的改动,请先提交后再发版!') process.exit(1) } // 2. 检查提交记录 const latestTag = getLatestTag() const commitLog = getCommitsSinceTag(latestTag) if (!hasConventionalCommits(commitLog)) { console.error('⚠️ 没有检测到符合 Angular 提交规范的提交,跳过 changelog 生成!') process.exit(1) } // 3. 选择发布模式 const { mode } = await inquirer.prompt([ { type: 'list', name: 'mode', message: '请选择发布模式:', choices: [ { name: '正式发版(更新版本号 + 生成 tag + 推送)', value: 'release' }, { name: '自测模式(仅生成 changelog,不推送)', value: 'test' }, ], }, ]) // 4. 选择 changelog 生成方式 const { changelogMode } = await inquirer.prompt([ { type: 'list', name: 'changelogMode', message: '请选择 changelog 生成方式:', choices: [ { name: '增量追加日志(推荐)', value: 'incremental' }, { name: '全量生成日志(会覆盖原文件)', value: 'all' }, ], }, ]) // 5. 生成 changelog if (changelogMode === 'all') { run('npx conventional-changelog -p angular -i CHANGELOG.md -s -r 0') } else { run('npx conventional-changelog -p angular -i CHANGELOG.md -s') } // 6. 检查 changelog 是否更新 const changelogContent = fs.readFileSync('CHANGELOG.md', 'utf8') if (!changelogContent.includes(new Date().getFullYear().toString())) { console.error('⚠️ changelog 没有生成新的内容,请检查提交记录!') process.exit(1) } // 7. 如果是正式模式,选择版本号递增类型 if (mode === 'release') { const { versionType } = await inquirer.prompt([ { type: 'list', name: 'versionType', message: '请选择版本号递增类型:', choices: [ { name: '补丁版本(patch)', value: 'patch' }, { name: '小版本(minor)', value: 'minor' }, { name: '大版本(major)', value: 'major' }, ], }, ]) // 更新版本号 & 提交 tag run(`npm version ${versionType} -m "release: v%s"`) // 推送代码 & tag run('git push && git push --tags') console.log('✅ 正式发版完成!') } else { console.log('✅ 自测模式完成(未生成 tag / 未推送)') }