version-script.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #!/usr/bin/env node
  2. import fs from 'fs'
  3. import path from 'path'
  4. import { fileURLToPath } from 'url'
  5. import { execSync } from 'child_process'
  6. import readline from 'readline'
  7. // 获取当前脚本所在目录
  8. const __filename = fileURLToPath(import.meta.url)
  9. const __dirname = path.dirname(__filename)
  10. // 读取package.json
  11. const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'))
  12. const currentVersion = packageJson.version
  13. // 获取当前分支名
  14. function getCurrentBranch() {
  15. try {
  16. return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim()
  17. } catch (error) {
  18. console.error('❌❌❌ getCurrentBranch Failed:', error.message)
  19. return 'unknown-branch'
  20. }
  21. }
  22. // 获取当前时间戳
  23. function getTimestamp() {
  24. const now = new Date()
  25. // 精确到秒 + 3位随机数(1/1000概率),确保同一秒内多次构建也能生成唯一的tag
  26. return (
  27. now.getFullYear() +
  28. String(now.getMonth() + 1).padStart(2, '0') +
  29. String(now.getDate()).padStart(2, '0') +
  30. String(now.getHours()).padStart(2, '0') +
  31. String(now.getMinutes()).padStart(2, '0') +
  32. String(now.getSeconds()).padStart(2, '0') +
  33. Math.floor(Math.random() * 1000)
  34. .toString()
  35. .padStart(3, '0')
  36. )
  37. }
  38. // 验证版本号格式
  39. function isValidVersion(version) {
  40. const versionRegex = /^(\d+)(\.(\d+))?(\.(\d+))?$/
  41. return versionRegex.test(version)
  42. }
  43. // 比较版本号
  44. function compareVersions(version1, version2) {
  45. const v1 = version1.split('.').map(Number)
  46. const v2 = version2.split('.').map(Number)
  47. for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
  48. const num1 = v1[i] || 0
  49. const num2 = v2[i] || 0
  50. if (num1 > num2) return 1
  51. if (num1 < num2) return -1
  52. }
  53. return 0
  54. }
  55. // 格式化日期为YYYY-MM-DD HH:mm:ss
  56. function formatDateTime(date) {
  57. const year = date.getFullYear()
  58. const month = String(date.getMonth() + 1).padStart(2, '0')
  59. const day = String(date.getDate()).padStart(2, '0')
  60. const hours = String(date.getHours()).padStart(2, '0')
  61. const minutes = String(date.getMinutes()).padStart(2, '0')
  62. const seconds = String(date.getSeconds()).padStart(2, '0')
  63. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
  64. }
  65. // 创建版本信息文件
  66. function createVersionInfoFile(version, type, branch, tag) {
  67. const versionInfo = {
  68. version: version,
  69. branch: branch,
  70. tag: tag,
  71. buildType: type,
  72. buildTime: formatDateTime(new Date()),
  73. }
  74. const distDir = path.join(__dirname, 'dist')
  75. // 确保dist目录存在
  76. if (!fs.existsSync(distDir)) {
  77. fs.mkdirSync(distDir, { recursive: true })
  78. }
  79. // 写入version.json文件
  80. fs.writeFileSync(path.join(distDir, 'version.json'), JSON.stringify(versionInfo, null, 2))
  81. console.log(`✅✅✅ version.json has been generated: ${path.join(distDir, 'version.json')}`)
  82. }
  83. // 处理测试构建
  84. function handleTestBuild() {
  85. const branch = getCurrentBranch()
  86. const timestamp = getTimestamp()
  87. const tag = `test-${timestamp}`
  88. console.log(
  89. `🚀🚀🚀 A test version is being created... branchName:${branch},productionVersion:${currentVersion}`
  90. )
  91. try {
  92. // 执行构建命令
  93. execSync('vite build', { stdio: 'inherit' })
  94. // 创建tag
  95. execSync(`git tag ${tag}`, { stdio: 'inherit' })
  96. console.log(`✅✅✅ Test Version Build Success! Test Version: ${tag}`)
  97. // 生成版本信息文件
  98. createVersionInfoFile(currentVersion, 'test', branch, tag)
  99. } catch (error) {
  100. console.error('❌❌❌ Test Version Build Failed:', error.message)
  101. process.exit(1)
  102. }
  103. }
  104. // 处理发布构建
  105. function handlePublishBuild() {
  106. const rl = readline.createInterface({
  107. input: process.stdin,
  108. output: process.stdout,
  109. })
  110. rl.question(`请输入需要发布的新版本号(当前生产版本号: ${currentVersion}): `, (newVersion) => {
  111. newVersion = newVersion.trim()
  112. if (!isValidVersion(newVersion)) {
  113. console.error('无效的发布版本号格式,请使用x.x.x格式')
  114. rl.close()
  115. process.exit(1)
  116. }
  117. if (compareVersions(newVersion, currentVersion) <= 0) {
  118. console.error(`发布版本号必须大于当前版本(${currentVersion})`)
  119. rl.close()
  120. process.exit(1)
  121. }
  122. const branch = getCurrentBranch()
  123. const tag = `publish-v${newVersion}`
  124. console.log(
  125. `🚀🚀🚀 A publish version is being created... branchName:${branch}、productionVersion: ${newVersion}`
  126. )
  127. try {
  128. // 更新package.json中的版本
  129. packageJson.version = newVersion
  130. fs.writeFileSync(path.join(__dirname, 'package.json'), JSON.stringify(packageJson, null, 2))
  131. // 执行构建命令
  132. execSync('vite build', { stdio: 'inherit' })
  133. // 创建tag
  134. execSync(`git tag ${tag}`, { stdio: 'inherit' })
  135. console.log(`✅✅✅ Publish version ${tag} build success! Version number: ${newVersion}`)
  136. // 生成版本信息文件
  137. createVersionInfoFile(newVersion, 'publish', branch, tag)
  138. } catch (error) {
  139. console.error('❌❌❌ Publish version build failed:', error.message)
  140. process.exit(1)
  141. } finally {
  142. rl.close()
  143. }
  144. })
  145. }
  146. // 基于特定tag构建
  147. function handleBuildByTag() {
  148. const rl = readline.createInterface({
  149. input: process.stdin,
  150. output: process.stdout,
  151. })
  152. // 保存原始分支
  153. const originalBranch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim()
  154. rl.question('请输入要构建的tag名称(test-xxxx 或 publish-xxxx):', (tag) => {
  155. tag = tag.trim()
  156. try {
  157. // 检查tag是否存在
  158. execSync(`git rev-parse ${tag}`, { stdio: 'ignore' })
  159. console.log(`🚀🚀🚀 正在基于tag ${tag} 构建...`)
  160. // 切换到该tag
  161. execSync(`git checkout ${tag}`, { stdio: 'inherit' })
  162. // 读取当前分支名
  163. const branch = getCurrentBranch()
  164. // 读取package.json中的版本号
  165. const pkgJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'))
  166. const version = pkgJson.version
  167. // 执行构建命令
  168. execSync('vite build', { stdio: 'inherit' })
  169. // 生成版本信息文件
  170. const buildType = tag.startsWith('test-') ? 'test' : 'publish'
  171. createVersionInfoFile(version, buildType, branch, tag)
  172. console.log(`✅✅✅ 基于tag ${tag} 构建成功!`)
  173. // 切换回原分支
  174. execSync(`git checkout ${originalBranch}`, { stdio: 'inherit' })
  175. console.log(`✅✅✅ 已切换回原分支: ${originalBranch}`)
  176. } catch (error) {
  177. console.error(`❌❌❌ 基于tag ${tag} 构建失败: ${error.message}`)
  178. // 即使构建失败也尝试切换回原分支
  179. try {
  180. execSync(`git checkout ${originalBranch}`, { stdio: 'inherit' })
  181. console.log(`✅✅✅ 已切换回原分支: ${originalBranch}`)
  182. } catch (checkoutError) {
  183. console.error(`❌❌❌ 切换回原分支失败,请手动处理: ${checkoutError.message}`)
  184. }
  185. process.exit(1)
  186. } finally {
  187. rl.close()
  188. }
  189. })
  190. }
  191. // 主函数
  192. function main() {
  193. const command = process.argv[2]
  194. switch (command) {
  195. case 'test':
  196. handleTestBuild()
  197. break
  198. case 'publish':
  199. handlePublishBuild()
  200. break
  201. case 'build-by-tag':
  202. handleBuildByTag()
  203. break
  204. default:
  205. console.log('用法: node version-script.js [test|publish|build-by-tag]')
  206. process.exit(1)
  207. }
  208. }
  209. main()