#!/usr/bin/env node import { execSync } from 'child_process' import inquirer from 'inquirer' import fs from 'fs' function run(cmd, options = {}) { execSync(cmd, { stdio: 'inherit', ...options }) } function runSilent(cmd) { return execSync(cmd, { encoding: 'utf-8' }).trim() } function getVersion() { return JSON.parse(fs.readFileSync('package.json', 'utf8')).version } function getLastTag() { try { return runSilent('git describe --tags --abbrev=0') } catch { return null // 没有 tag } } function getCommitsSince(tag) { const range = tag ? `${tag}..HEAD` : '' try { return runSilent(`git log ${range} --pretty=format:"- %s (%h)"`) } catch { return '' } } function updateChangelog(version, mode = 'incremental') { const lastTag = getLastTag() const commits = getCommitsSince(lastTag) if (!commits) { console.log('⚠️ 没有新提交,但依旧会记录版本变化。') } const date = new Date().toISOString().slice(0, 10) const newEntry = `\n## ${version} (${date})\n${commits || '- No changes'}\n` let changelog = '' if (fs.existsSync('CHANGELOG.md')) { changelog = fs.readFileSync('CHANGELOG.md', 'utf-8') } if (mode === 'full') { fs.writeFileSync('CHANGELOG.md', newEntry, 'utf-8') } else { fs.writeFileSync('CHANGELOG.md', newEntry + changelog, 'utf-8') } console.log(`✅ changelog 已更新到版本 ${version}`) } async function main() { console.log('🚀 开始发布流程...') // 选择版本类型 const { versionType } = await inquirer.prompt([ { type: 'list', name: 'versionType', message: '请选择版本类型:', default: 'patch', choices: [ { name: '补丁版本 (patch)', value: 'patch' }, { name: '小版本 (minor)', value: 'minor' }, { name: '大版本 (major)', value: 'major' }, ], }, ]) // 更新版本号(不自动打 tag) run(`npm version ${versionType} --no-git-tag-version`) const version = getVersion() // 同步远程 tag,防止增量 changelog 范围不准 console.log('🔄 正在同步远程标签...') run('git fetch --tags') console.log('✅ 远程标签已同步') // 选择 changelog 生成模式 const { changelogMode } = await inquirer.prompt([ { type: 'list', name: 'changelogMode', message: '请选择 changelog 生成模式:', default: 'incremental', choices: [ // { name: '全量生成(会覆盖整个文件)', value: 'full' }, { name: '增量生成(只追加本次更新的内容)', value: 'incremental' }, ], }, ]) // 生成 changelog updateChangelog(`v${version}`, changelogMode) // 提交变更 if (fs.existsSync('package-lock.json')) { run('git add package.json package-lock.json') } else { run('git add package.json') } run('git add CHANGELOG.md') try { run(`git diff --cached --quiet || git commit -m "chore: release v${version}"`) } catch { console.log('⚠️ 没有需要提交的文件,跳过 commit') } // 打 tag & 推送 run(`git tag v${version}`) run('git push && git push --tags') console.log('\x1b[36m=========================\x1b[0m') console.log('\x1b[32m🎉 发布成功!\x1b[0m') console.log(`\x1b[33m📦 版本号:v${version}\x1b[0m`) console.log('\x1b[35m⚙️ 同步代码:\x1b[0m') console.log('\x1b[34m * 同步dev分支代码到prod分支:bash scripts/merge_dev_to_pro.sh\x1b[0m') console.log('\x1b[36m=========================\x1b[0m') } main()