release.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import inquirer from 'inquirer'
  2. import { execSync } from 'child_process'
  3. import fs from 'fs'
  4. import path from 'path'
  5. // changelog 文件路径
  6. const changelogPath = path.resolve('CHANGELOG.md')
  7. // 运行命令工具
  8. const run = (cmd) => execSync(cmd, { stdio: 'inherit' })
  9. // 检查 Git 工作区是否干净
  10. const isGitClean = () => {
  11. const status = execSync('git status --porcelain').toString().trim()
  12. return status === ''
  13. }
  14. // 检查是否有符合规范的提交(feat、fix 等)
  15. const hasConventionalCommits = () => {
  16. const lastTag = execSync('git describe --tags --abbrev=0', { stdio: 'pipe' }).toString().trim()
  17. const log = execSync(`git log ${lastTag}..HEAD --pretty=format:%s`, { stdio: 'pipe' })
  18. .toString()
  19. .trim()
  20. return /^(feat|fix|docs|style|refactor|perf|test|chore)(\(.+\))?:/m.test(log)
  21. }
  22. // 1. 确保 changelog 文件存在
  23. if (!fs.existsSync(changelogPath)) {
  24. console.log(`📄 检测到不存在 ${changelogPath},已自动创建空文件`)
  25. fs.writeFileSync(changelogPath, '', 'utf-8')
  26. }
  27. // 2. 检查 git 工作区
  28. if (!isGitClean()) {
  29. console.error('❌ Git 工作区有未提交的改动,请先提交后再发版!')
  30. process.exit(1)
  31. }
  32. // 3. 询问发布模式
  33. const { publishMode } = await inquirer.prompt([
  34. {
  35. type: 'list',
  36. name: 'publishMode',
  37. message: '请选择发布模式:',
  38. choices: [
  39. { name: '正常发版(更新版本号并推送)', value: 'normal' },
  40. { name: '自测模式(仅生成 changelog,不推送)', value: 'test' },
  41. ],
  42. default: 'normal',
  43. },
  44. ])
  45. // 4. 检查是否有符合规范的提交
  46. if (!hasConventionalCommits()) {
  47. console.error('⚠️ 没有检测到符合 Angular 提交规范的提交,跳过 changelog 生成!')
  48. process.exit(1)
  49. }
  50. // 5. 询问生成 changelog 的方式
  51. const { mode } = await inquirer.prompt([
  52. {
  53. type: 'list',
  54. name: 'mode',
  55. message: '请选择 changelog 生成方式:',
  56. choices: [
  57. { name: '只追加日志(推荐)', value: 'incremental' },
  58. { name: '全量生成日志(会覆盖原文件)', value: 'all' },
  59. ],
  60. default: 'incremental',
  61. },
  62. ])
  63. // 6. 生成 changelog
  64. if (mode === 'all') {
  65. run('npx conventional-changelog -p angular -i CHANGELOG.md -s -r 0')
  66. } else {
  67. run('npx conventional-changelog -p angular -i CHANGELOG.md -s')
  68. }
  69. // 7. 如果是自测模式,提前结束
  70. if (publishMode === 'test') {
  71. console.log('✅ 自测模式完成(未生成 tag / 未推送)')
  72. process.exit(0)
  73. }
  74. // 8. 更新版本号(补丁版本)
  75. run('npm version patch -m "new version published: v%s"')
  76. // 9. 推送代码和 tag
  77. run('git push && git push --tags')
  78. console.log('✅ 发布完成!')