@zjex/git-workflow 0.2.24 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/.github/workflows/deploy-docs.yml +68 -0
  2. package/.github/workflows/test.yml +24 -4
  3. package/.husky/pre-commit +17 -0
  4. package/README.md +72 -1066
  5. package/ROADMAP.md +275 -0
  6. package/dist/index.js +450 -99
  7. package/docs/.vitepress/cache/deps/_metadata.json +52 -0
  8. package/docs/.vitepress/cache/deps/chunk-2CLQ7TTZ.js +9719 -0
  9. package/docs/.vitepress/cache/deps/chunk-2CLQ7TTZ.js.map +7 -0
  10. package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js +12824 -0
  11. package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js.map +7 -0
  12. package/docs/.vitepress/cache/deps/package.json +3 -0
  13. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
  14. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  15. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +583 -0
  16. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  17. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1352 -0
  18. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  19. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1665 -0
  20. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  21. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1813 -0
  22. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  23. package/docs/.vitepress/cache/deps/vue.js +347 -0
  24. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  25. package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-2CLQ7TTZ.js +9719 -0
  26. package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-2CLQ7TTZ.js.map +7 -0
  27. package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-LE5NDSFD.js +12824 -0
  28. package/docs/.vitepress/cache/deps_temp_44e2fb0f/chunk-LE5NDSFD.js.map +7 -0
  29. package/docs/.vitepress/cache/deps_temp_44e2fb0f/package.json +3 -0
  30. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vue_devtools-api.js +4505 -0
  31. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vue_devtools-api.js.map +7 -0
  32. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_core.js +583 -0
  33. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_core.js.map +7 -0
  34. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_integrations_useFocusTrap.js +1352 -0
  35. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  36. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___mark__js_src_vanilla__js.js +1665 -0
  37. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  38. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___minisearch.js +1813 -0
  39. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vitepress___minisearch.js.map +7 -0
  40. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vue.js +347 -0
  41. package/docs/.vitepress/cache/deps_temp_44e2fb0f/vue.js.map +7 -0
  42. package/docs/.vitepress/config.ts +167 -0
  43. package/docs/.vitepress/theme/custom.css +39 -0
  44. package/docs/.vitepress/theme/index.ts +4 -0
  45. package/docs/README.md +82 -0
  46. package/docs/commands/branch.md +468 -0
  47. package/docs/commands/commit.md +554 -0
  48. package/docs/commands/config.md +346 -0
  49. package/docs/commands/index.md +312 -0
  50. package/docs/commands/interactive.md +384 -0
  51. package/docs/commands/release.md +300 -0
  52. package/docs/commands/stash.md +309 -0
  53. package/docs/commands/tag.md +278 -0
  54. package/docs/commands/update.md +347 -0
  55. package/docs/config/ai-config.md +160 -0
  56. package/docs/config/branch-config.md +133 -0
  57. package/docs/config/commit-config.md +185 -0
  58. package/docs/config/config-file.md +776 -0
  59. package/docs/config/examples.md +279 -0
  60. package/docs/config/index.md +478 -0
  61. package/docs/features/git-wrapped.md +199 -0
  62. package/docs/guide/ai-commit.md +576 -0
  63. package/docs/guide/basic-usage.md +522 -0
  64. package/docs/guide/best-practices.md +426 -0
  65. package/docs/guide/branch-management.md +712 -0
  66. package/docs/guide/getting-started.md +294 -0
  67. package/docs/guide/index.md +168 -0
  68. package/docs/guide/installation.md +449 -0
  69. package/docs/guide/release-management.md +744 -0
  70. package/docs/guide/stash-management.md +608 -0
  71. package/docs/guide/tag-management.md +614 -0
  72. package/docs/index.md +205 -0
  73. package/docs/public/favicon.svg +21 -0
  74. package/docs/public/hero-logo.svg +43 -0
  75. package/docs/public/logo.svg +20 -0
  76. package/package.json +12 -2
  77. package/scripts/publish.js +55 -8
  78. package/scripts/publish.sh +20 -2
  79. package/scripts/release.sh +81 -3
  80. package/scripts/update-test-count.js +55 -0
  81. package/src/ai-service.ts +107 -15
  82. package/src/commands/commit.ts +4 -0
  83. package/src/commands/init.ts +18 -0
  84. package/src/commands/log.ts +503 -0
  85. package/src/config.ts +1 -0
  86. package/src/index.ts +37 -13
  87. package/src/utils.ts +10 -0
  88. package/tests/ai-service.test.ts +237 -2
  89. package/tests/init.test.ts +582 -0
  90. package/tests/log.test.ts +106 -0
  91. package/tests/release.test.ts +333 -0
  92. package/tests/setup.ts +21 -0
  93. package/tests/stash.test.ts +376 -0
  94. package/tests/update.test.ts +402 -0
  95. package/vitest.config.ts +3 -0
  96. package/zjex-logo.svg +22 -0
  97. package/zjex-optimized.svg +34 -0
  98. package/zjex.svg +1 -0
  99. package/src/commands/help.ts +0 -76
package/docs/index.md ADDED
@@ -0,0 +1,205 @@
1
+ ---
2
+ layout: home
3
+
4
+ hero:
5
+ name: "Git Workflow"
6
+ text: "极简的 Git 工作流 CLI 工具"
7
+ tagline: "让分支管理和版本发布变得轻松愉快"
8
+ image:
9
+ src: /hero-logo.svg
10
+ alt: Git Workflow Logo
11
+ actions:
12
+ - theme: brand
13
+ text: 快速开始
14
+ link: /guide/getting-started
15
+ - theme: alt
16
+ text: 查看 GitHub
17
+ link: https://github.com/iamzjt-front-end/git-workflow
18
+
19
+ features:
20
+ - icon: 🤖
21
+ title: AI 智能提交
22
+ details: 使用 AI 自动分析代码变更生成 commit message,支持 GitHub Models、OpenAI 等多种提供商
23
+ - icon: 🎯
24
+ title: 规范命名
25
+ details: 自动生成带日期的规范分支名,如 feature/20260109-PROJ-123-add-login
26
+ - icon: 🏷️
27
+ title: 智能版本
28
+ details: 自动识别当前版本,交互式选择下一版本,支持 semver + 预发布版本
29
+ - icon: 📝
30
+ title: 规范提交
31
+ details: 遵循 Conventional Commits + Gitmoji,提交信息更清晰规范
32
+ - icon: 🗑️
33
+ title: 批量清理
34
+ details: 一键删除本地+远程分支,按最近使用排序,智能检测远程分支状态
35
+ - icon: 💾
36
+ title: Stash 管理
37
+ details: 可视化管理 stash,支持预览、应用、创建分支等操作
38
+ - icon: ⚙️
39
+ title: 灵活配置
40
+ details: 支持项目级和全局配置,不同项目可使用不同规范
41
+ - icon: 🔔
42
+ title: 版本提醒
43
+ details: 自动检测新版本,一键更新,保持工具始终最新
44
+ ---
45
+
46
+ ## 🎯 为什么选择 Git Workflow?
47
+
48
+ 在日常开发中,你是否经常遇到这些问题:
49
+
50
+ - 🤔 每次创建分支都要手动输入一长串命名规范?
51
+ - 😫 发布版本时总是忘记当前版本号是多少?
52
+ - 📝 提交信息格式不统一,难以生成 CHANGELOG?
53
+ - 🔄 删除分支时需要分别处理本地和远程?
54
+ - 📋 团队成员的分支命名风格五花八门?
55
+ - 💬 写 commit message 总是词穷,不知道怎么描述?
56
+
57
+ **Git Workflow** 就是为解决这些痛点而生的。它提供了一套简洁的命令,让你专注于编码,而不是 Git 操作。
58
+
59
+ ## ⚡️ 快速开始
60
+
61
+ ### 安装
62
+
63
+ ::: code-group
64
+
65
+ ```bash [npm]
66
+ npm install -g @zjex/git-workflow
67
+ ```
68
+
69
+ ```bash [pnpm]
70
+ pnpm add -g @zjex/git-workflow
71
+ ```
72
+
73
+ ```bash [yarn]
74
+ yarn global add @zjex/git-workflow
75
+ ```
76
+
77
+ :::
78
+
79
+ ### 三步开始使用
80
+
81
+ ```bash
82
+ # 第 1 步:创建全局配置(只需一次)
83
+ gw init
84
+ # 选择 "全局配置(所有项目生效)"
85
+ # 配置 AI commit、分支规范等
86
+
87
+ # 第 2 步:在任意项目中使用
88
+ cd your-project
89
+ gw c # AI 自动生成 commit message
90
+ gw f # 创建规范的 feature 分支
91
+ gw t # 创建语义化版本 tag
92
+
93
+ # 第 3 步:享受高效的 Git 工作流 🎉
94
+ ```
95
+
96
+ ## 🌟 核心特性
97
+
98
+ ### 🤖 AI 智能提交
99
+
100
+ 使用 AI 自动分析代码变更生成 commit message,2-3 秒完成,支持多种 AI 提供商:
101
+
102
+ ```bash
103
+ gw c
104
+ # 已暂存的文件:
105
+ # src/auth.ts
106
+ # src/login.ts
107
+ # ────────────────────────────────────────
108
+ # ? 选择 commit 方式:
109
+ # ❯ 🤖 AI 自动生成 commit message
110
+ # ✍️ 手动编写 commit message
111
+ #
112
+ # ✔ AI 生成完成
113
+ #
114
+ # AI 生成的 commit message:
115
+ # ✨ feat(auth): 添加用户登录功能
116
+ ```
117
+
118
+ ### 🎯 规范分支命名
119
+
120
+ 自动生成带日期的规范分支名,支持自定义前缀和 ID 标签:
121
+
122
+ ```bash
123
+ gw f
124
+ # ? 请输入 Story ID (可跳过): PROJ-123
125
+ # ? 请输入描述: add-user-login
126
+ # ✔ 分支创建成功: feature/20260109-PROJ-123-add-user-login
127
+ ```
128
+
129
+ ### 🏷️ 智能版本管理
130
+
131
+ 自动检测现有 tag 前缀,智能递增版本号:
132
+
133
+ ```bash
134
+ gw t
135
+ # ? 选择 tag 前缀: v (最新: v1.2.0)
136
+ # ? 选择版本类型:
137
+ # ❯ patch → v1.2.1
138
+ # minor → v1.3.0
139
+ # major → v2.0.0
140
+ # alpha → v1.2.1-alpha.1
141
+ ```
142
+
143
+ ### 💾 可视化 Stash 管理
144
+
145
+ 原生 `git stash list` 输出难以阅读,Git Workflow 提供清晰的交互式界面:
146
+
147
+ ```bash
148
+ gw s
149
+ # 共 3 个 stash:
150
+ #
151
+ # ? 选择 stash:
152
+ # [0] main fix login bug (3 文件) 2 hours ago
153
+ # [1] develop add new feature (5 文件) 1 day ago
154
+ # [2] main WIP (1 文件) 3 days ago
155
+ # + 创建新 stash
156
+ # 取消
157
+ ```
158
+
159
+ ## 📊 与其他工具对比
160
+
161
+ | 特性 | Git Workflow | git-flow | 手动操作 |
162
+ | ---------------- | ------------- | ----------- | --------- |
163
+ | 学习成本 | ⭐ 极低 | ⭐⭐⭐ 较高 | ⭐⭐ 中等 |
164
+ | 分支命名规范 | ✅ 自动生成 | ❌ 需手动 | ❌ 需手动 |
165
+ | 版本号管理 | ✅ 智能递增 | ❌ 需手动 | ❌ 需手动 |
166
+ | AI Commit | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
167
+ | Stash 可视化管理 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
168
+ | 交互式操作 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
169
+ | 配置灵活性 | ✅ 项目级配置 | ⚠️ 有限 | - |
170
+
171
+ ## 🎨 优雅的用户界面
172
+
173
+ Git Workflow 提供优雅的命令行界面,支持键盘快捷操作:
174
+
175
+ ```
176
+ ███████╗ ██╗███████╗██╗ ██╗
177
+ ╚══███╔╝ ██║██╔════╝╚██╗██╔╝
178
+ ███╔╝ ██║█████╗ ╚███╔╝
179
+ ███╔╝ ██ ██║██╔══╝ ██╔██╗
180
+ ███████╗╚█████╔╝███████╗██╔╝ ██╗
181
+ ╚══════╝ ╚════╝ ╚══════╝╚═╝ ╚═╝
182
+
183
+ git-workflow v0.2.24
184
+
185
+ ? 选择操作:
186
+ [1] ✨ 创建 feature 分支 gw f
187
+ [2] 🐛 创建 hotfix 分支 gw h
188
+ [3] 🗑️ 删除分支 gw d
189
+ [4] 📝 提交代码 gw c
190
+ [5] 🏷️ 创建 tag gw t
191
+ ...
192
+ ```
193
+
194
+ ## 🤝 社区与支持
195
+
196
+ - 📖 [完整文档](/guide/)
197
+ - 🐛 [问题反馈](https://github.com/iamzjt-front-end/git-workflow/issues)
198
+ - 💡 [功能建议](https://github.com/iamzjt-front-end/git-workflow/discussions)
199
+ - 📦 [npm 包](https://www.npmjs.com/package/@zjex/git-workflow)
200
+
201
+ ---
202
+
203
+ <div style="text-align: center; margin-top: 2rem;">
204
+ <strong>如果这个工具对你有帮助,请给个 ⭐️ 支持一下!</strong>
205
+ </div>
@@ -0,0 +1,21 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <rect width="64" height="64" rx="8" fill="#ffffff"/>
3
+ <!-- 基于 zjex.svg 的交叉图案,放大版本用作 favicon -->
4
+ <g transform="translate(6, 6) scale(0.52)">
5
+ <!-- 蓝色条纹 -->
6
+ <path d="M69.3 59.41l-9.89 9.89L51 77.73 30.46 98.26A6 6 0 0 1 22 89.83L42.56 69.3 51 60.88l9.9-9.9z" fill="#0059cc"/>
7
+ <path d="M102 24.28a6 6 0 0 1-1.75 4.21L77.72 51l-8.42-8.44 22.5-22.5a6 6 0 0 1 10.2 4.22z" fill="#0059cc"/>
8
+
9
+ <!-- 青色条纹 -->
10
+ <path d="M83.64 6a5.94 5.94 0 0 1-1.74 4.21L41.08 51l-8.42-8.42 9.9-9.89L51 24.24 73.48 1.75A6 6 0 0 1 83.64 6z" fill="#00dac7"/>
11
+ <path d="M32.66 59.41L12.13 79.93a6 6 0 0 1-8.42-8.42L24.24 51z" fill="#00dac7"/>
12
+
13
+ <!-- 浅蓝色条纹 -->
14
+ <path d="M51 24.24l-8.42 8.43-22.5-22.5A6 6 0 0 1 24.28 0a5.89 5.89 0 0 1 4.2 1.75z" fill="#00baec"/>
15
+ <path d="M98.25 79.93a5.94 5.94 0 0 1-8.42 0L51 41.09l8.42-8.42 9.9 9.89 8.4 8.44 20.53 20.51a6 6 0 0 1 0 8.42z" fill="#00baec"/>
16
+
17
+ <!-- 深蓝色条纹 -->
18
+ <path d="M51 60.88l-8.44 8.42L1.74 28.49a6 6 0 0 1 8.43-8.43l22.49 22.5L41.08 51z" fill="#00abd8"/>
19
+ <path d="M79.93 98.26a6 6 0 0 1-8.42 0L51 77.73l8.42-8.43 20.51 20.53a6 6 0 0 1 0 8.43z" fill="#00abd8"/>
20
+ </g>
21
+ </svg>
@@ -0,0 +1,43 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1800 1800" width="320" height="320">
2
+ <!-- 简洁版本 - 无背景渐变 -->
3
+
4
+ <defs>
5
+ <!-- 原有的logo渐变 -->
6
+ <linearGradient id="blueGrad" x1="0%" y1="0%" x2="100%" y2="100%">
7
+ <stop offset="0%" style="stop-color:#00baec;stop-opacity:1" />
8
+ <stop offset="100%" style="stop-color:#0059cc;stop-opacity:1" />
9
+ </linearGradient>
10
+ <linearGradient id="cyanGrad" x1="0%" y1="0%" x2="100%" y2="100%">
11
+ <stop offset="0%" style="stop-color:#00dac7;stop-opacity:1" />
12
+ <stop offset="100%" style="stop-color:#00baec;stop-opacity:1" />
13
+ </linearGradient>
14
+
15
+ <!-- 发光效果 -->
16
+ <filter id="glow">
17
+ <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
18
+ <feMerge>
19
+ <feMergeNode in="coloredBlur"/>
20
+ <feMergeNode in="SourceGraphic"/>
21
+ </feMerge>
22
+ </filter>
23
+ </defs>
24
+
25
+ <!-- 交叉图案 - 保持原有颜色和效果 -->
26
+ <g transform="translate(900, 900) scale(16.2) translate(-51, -50)" filter="url(#glow)">
27
+ <!-- 蓝色条纹 - 使用渐变 -->
28
+ <path d="M69.3 59.41l-9.89 9.89L51 77.73 30.46 98.26A6 6 0 0 1 22 89.83L42.56 69.3 51 60.88l9.9-9.9z" fill="url(#blueGrad)"/>
29
+ <path d="M102 24.28a6 6 0 0 1-1.75 4.21L77.72 51l-8.42-8.44 22.5-22.5a6 6 0 0 1 10.2 4.22z" fill="url(#blueGrad)"/>
30
+
31
+ <!-- 青色条纹 - 使用渐变 -->
32
+ <path d="M83.64 6a5.94 5.94 0 0 1-1.74 4.21L41.08 51l-8.42-8.42 9.9-9.89L51 24.24 73.48 1.75A6 6 0 0 1 83.64 6z" fill="url(#cyanGrad)"/>
33
+ <path d="M32.66 59.41L12.13 79.93a6 6 0 0 1-8.42-8.42L24.24 51z" fill="url(#cyanGrad)"/>
34
+
35
+ <!-- 浅蓝色条纹 -->
36
+ <path d="M51 24.24l-8.42 8.43-22.5-22.5A6 6 0 0 1 24.28 0a5.89 5.89 0 0 1 4.2 1.75z" fill="#00baec"/>
37
+ <path d="M98.25 79.93a5.94 5.94 0 0 1-8.42 0L51 41.09l8.42-8.42 9.9 9.89 8.4 8.44 20.53 20.51a6 6 0 0 1 0 8.42z" fill="#00baec"/>
38
+
39
+ <!-- 深蓝色条纹 -->
40
+ <path d="M51 60.88l-8.44 8.42L1.74 28.49a6 6 0 0 1 8.43-8.43l22.49 22.5L41.08 51z" fill="#00abd8"/>
41
+ <path d="M79.93 98.26a6 6 0 0 1-8.42 0L51 77.73l8.42-8.43 20.51 20.53a6 6 0 0 1 0 8.43z" fill="#00abd8"/>
42
+ </g>
43
+ </svg>
@@ -0,0 +1,20 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 100" width="96" height="96">
2
+ <!-- 简洁版本 - 用于导航栏 -->
3
+ <g transform="translate(60, 50) scale(0.9) translate(-51, -50)">
4
+ <!-- 蓝色条纹 -->
5
+ <path d="M69.3 59.41l-9.89 9.89L51 77.73 30.46 98.26A6 6 0 0 1 22 89.83L42.56 69.3 51 60.88l9.9-9.9z" fill="#0059cc"/>
6
+ <path d="M102 24.28a6 6 0 0 1-1.75 4.21L77.72 51l-8.42-8.44 22.5-22.5a6 6 0 0 1 10.2 4.22z" fill="#0059cc"/>
7
+
8
+ <!-- 青色条纹 -->
9
+ <path d="M83.64 6a5.94 5.94 0 0 1-1.74 4.21L41.08 51l-8.42-8.42 9.9-9.89L51 24.24 73.48 1.75A6 6 0 0 1 83.64 6z" fill="#00dac7"/>
10
+ <path d="M32.66 59.41L12.13 79.93a6 6 0 0 1-8.42-8.42L24.24 51z" fill="#00dac7"/>
11
+
12
+ <!-- 浅蓝色条纹 -->
13
+ <path d="M51 24.24l-8.42 8.43-22.5-22.5A6 6 0 0 1 24.28 0a5.89 5.89 0 0 1 4.2 1.75z" fill="#00baec"/>
14
+ <path d="M98.25 79.93a5.94 5.94 0 0 1-8.42 0L51 41.09l8.42-8.42 9.9 9.89 8.4 8.44 20.53 20.51a6 6 0 0 1 0 8.42z" fill="#00baec"/>
15
+
16
+ <!-- 深蓝色条纹 -->
17
+ <path d="M51 60.88l-8.44 8.42L1.74 28.49a6 6 0 0 1 8.43-8.43l22.49 22.5L41.08 51z" fill="#00abd8"/>
18
+ <path d="M79.93 98.26a6 6 0 0 1-8.42 0L51 77.73l8.42-8.43 20.51 20.53a6 6 0 0 1 0 8.43z" fill="#00abd8"/>
19
+ </g>
20
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zjex/git-workflow",
3
- "version": "0.2.24",
3
+ "version": "0.3.2",
4
4
  "description": "🚀 极简的 Git 工作流 CLI 工具,让分支管理和版本发布变得轻松愉快",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,13 +17,17 @@
17
17
  "test:watch": "vitest",
18
18
  "test:ui": "vitest --ui",
19
19
  "test:coverage": "vitest --coverage",
20
+ "test:update-readme": "node scripts/update-test-count.js",
20
21
  "changelog": "changelogen -o CHANGELOG.md",
21
22
  "version": "node scripts/version.js",
22
23
  "release": "./scripts/release.sh",
23
24
  "release:dry": "./scripts/release.sh --dry-run",
24
25
  "publish:npm": "NODE_NO_WARNINGS=1 node scripts/publish.js",
25
26
  "prepublishOnly": "npm run build",
26
- "prepare": "husky"
27
+ "prepare": "husky",
28
+ "docs:dev": "vitepress dev docs",
29
+ "docs:build": "vitepress build docs",
30
+ "docs:preview": "npm run docs:build && vitepress preview docs"
27
31
  },
28
32
  "keywords": [
29
33
  "git",
@@ -34,6 +38,10 @@
34
38
  ],
35
39
  "author": "zjex",
36
40
  "license": "MIT",
41
+ "engines": {
42
+ "node": ">=18.0.0",
43
+ "npm": ">=9.0.0"
44
+ },
37
45
  "repository": {
38
46
  "type": "git",
39
47
  "url": "git+https://github.com/iamzjt-front-end/git-workflow.git"
@@ -46,6 +54,7 @@
46
54
  "@inquirer/prompts": "^7.0.0",
47
55
  "boxen": "^8.0.1",
48
56
  "cac": "^6.7.14",
57
+ "node-pager": "^0.3.6",
49
58
  "ora": "^9.0.0",
50
59
  "semver": "^7.7.3"
51
60
  },
@@ -59,6 +68,7 @@
59
68
  "tsup": "^8.5.1",
60
69
  "tsx": "^4.21.0",
61
70
  "typescript": "^5.9.3",
71
+ "vitepress": "^1.6.4",
62
72
  "vitest": "^4.0.16"
63
73
  }
64
74
  }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { execSync } from "child_process";
3
+ import { execSync, spawn } from "child_process";
4
4
  import { readFileSync } from "fs";
5
5
  import ora from "ora";
6
6
  import boxen from "boxen";
@@ -96,14 +96,61 @@ async function main() {
96
96
  const npmUser = exec("npm whoami", true);
97
97
  if (!npmUser) {
98
98
  spinner3.fail(`${colors.blue("[3/11]")} 检查 npm 登录状态`);
99
- console.log(colors.red(" 未登录 npm,请先执行: npm login"));
100
- process.exit(1);
99
+ console.log(colors.yellow("⚠️ 未登录 npm,需要先登录"));
100
+ console.log(colors.dim("正在为你打开 npm 登录..."));
101
+ console.log("");
102
+
103
+ try {
104
+ // 使用 spawn 而不是 exec,以便用户可以交互
105
+ const loginProcess = spawn("npm", ["login"], {
106
+ stdio: "inherit", // 继承父进程的 stdio,允许用户交互
107
+ shell: true
108
+ });
109
+
110
+ // 等待登录完成
111
+ await new Promise((resolve, reject) => {
112
+ loginProcess.on("close", (code) => {
113
+ if (code === 0) {
114
+ resolve();
115
+ } else {
116
+ reject(new Error(`npm login 失败,退出码: ${code}`));
117
+ }
118
+ });
119
+
120
+ loginProcess.on("error", (error) => {
121
+ reject(error);
122
+ });
123
+ });
124
+
125
+ console.log("");
126
+ console.log(colors.green("✅ npm 登录成功!"));
127
+ console.log(colors.dim("继续发布流程..."));
128
+ console.log("");
129
+
130
+ // 重新检查登录状态
131
+ const newNpmUser = exec("npm whoami", true);
132
+ if (!newNpmUser) {
133
+ console.log(colors.red("✖ 登录验证失败,请手动执行: npm login"));
134
+ process.exit(1);
135
+ }
136
+
137
+ spinner3.succeed(
138
+ `${colors.blue("[3/11]")} 检查 npm 登录状态 ${colors.dim(
139
+ `(${newNpmUser.trim()})`
140
+ )}`
141
+ );
142
+ } catch (error) {
143
+ console.log(colors.red("✖ npm 登录失败:"), error.message);
144
+ console.log(colors.dim("请手动执行: npm login"));
145
+ process.exit(1);
146
+ }
147
+ } else {
148
+ spinner3.succeed(
149
+ `${colors.blue("[3/11]")} 检查 npm 登录状态 ${colors.dim(
150
+ `(${npmUser.trim()})`
151
+ )}`
152
+ );
101
153
  }
102
- spinner3.succeed(
103
- `${colors.blue("[3/11]")} 检查 npm 登录状态 ${colors.dim(
104
- `(${npmUser.trim()})`
105
- )}`
106
- );
107
154
 
108
155
  // 获取当前分支
109
156
  const currentBranch = exec("git branch --show-current", true).trim();
@@ -123,8 +123,26 @@ fi
123
123
  echo -ne "${BLUE}[3/${TOTAL_STEPS}]${NC} 检查 npm 登录状态... "
124
124
  if ! npm whoami &> /dev/null; then
125
125
  echo -e "${RED}❌${NC}"
126
- print_error "未登录 npm,请先执行: npm login"
127
- exit 1
126
+ echo -e "${YELLOW}⚠️ 未登录 npm,需要先登录${NC}"
127
+ echo -e "${DIM}正在为你打开 npm 登录...${NC}"
128
+ echo ""
129
+
130
+ # 执行 npm login
131
+ if npm login; then
132
+ echo ""
133
+ echo -e "${GREEN}✅ npm 登录成功!${NC}"
134
+ echo -e "${DIM}继续发布流程...${NC}"
135
+ echo ""
136
+
137
+ # 重新检查登录状态
138
+ if ! npm whoami &> /dev/null; then
139
+ print_error "登录验证失败,请手动执行: npm login"
140
+ exit 1
141
+ fi
142
+ else
143
+ print_error "npm 登录失败,请手动执行: npm login"
144
+ exit 1
145
+ fi
128
146
  fi
129
147
  NPM_USER=$(npm whoami)
130
148
  echo -e "${GREEN}✅${NC} ${DIM}(${NPM_USER})${NC}"
@@ -111,8 +111,26 @@ fi
111
111
  # 检查 npm 登录状态
112
112
  print_step "检查 npm 登录状态..."
113
113
  if ! npm whoami &> /dev/null; then
114
- print_error "未登录 npm,请先执行: npm login"
115
- exit 1
114
+ echo -e "${YELLOW}⚠️ 未登录 npm,需要先登录${NC}"
115
+ echo -e "${DIM}正在为你打开 npm 登录...${NC}"
116
+ echo ""
117
+
118
+ # 执行 npm login
119
+ if npm login; then
120
+ echo ""
121
+ echo -e "${GREEN}✅ npm 登录成功!${NC}"
122
+ echo -e "${DIM}继续发布流程...${NC}"
123
+ echo ""
124
+
125
+ # 重新检查登录状态
126
+ if ! npm whoami &> /dev/null; then
127
+ print_error "登录验证失败,请手动执行: npm login"
128
+ exit 1
129
+ fi
130
+ else
131
+ print_error "npm 登录失败,请手动执行: npm login"
132
+ exit 1
133
+ fi
116
134
  fi
117
135
  NPM_USER=$(npm whoami)
118
136
  print_success "已登录 npm (用户: ${NPM_USER})"
@@ -120,7 +138,67 @@ print_success "已登录 npm (用户: ${NPM_USER})"
120
138
  # 拉取最新代码
121
139
  print_step "拉取最新代码..."
122
140
  if [[ "$DRY_RUN" == false ]]; then
123
- git pull origin "$CURRENT_BRANCH"
141
+ # 检查是否有远程更新
142
+ git fetch origin "$CURRENT_BRANCH"
143
+
144
+ # 检查本地和远程是否有分歧
145
+ LOCAL_COMMIT=$(git rev-parse HEAD)
146
+ REMOTE_COMMIT=$(git rev-parse "origin/$CURRENT_BRANCH")
147
+
148
+ if [[ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]]; then
149
+ print_warning "检测到本地和远程分支有分歧"
150
+
151
+ # 检查是否可以快进
152
+ if git merge-base --is-ancestor HEAD "origin/$CURRENT_BRANCH"; then
153
+ print_info "远程有新提交,正在快进合并..."
154
+ git pull origin "$CURRENT_BRANCH" --ff-only
155
+ elif git merge-base --is-ancestor "origin/$CURRENT_BRANCH" HEAD; then
156
+ print_info "本地有新提交,需要推送到远程"
157
+ print_warning "建议先推送本地提交再发布"
158
+ read -p "是否继续发布? (y/N) " -n 1 -r
159
+ echo
160
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
161
+ print_info "已取消,请先推送本地提交: git push origin $CURRENT_BRANCH"
162
+ exit 0
163
+ fi
164
+ else
165
+ print_warning "本地和远程分支有冲突,需要解决分歧"
166
+ echo ""
167
+ echo "建议的解决方案:"
168
+ echo "1. 使用 rebase: git pull origin $CURRENT_BRANCH --rebase"
169
+ echo "2. 使用 merge: git pull origin $CURRENT_BRANCH --no-rebase"
170
+ echo ""
171
+ read -p "选择解决方案 (1=rebase, 2=merge, q=退出): " -n 1 -r
172
+ echo
173
+
174
+ case $REPLY in
175
+ 1)
176
+ print_info "使用 rebase 策略合并..."
177
+ if git pull origin "$CURRENT_BRANCH" --rebase; then
178
+ print_success "Rebase 成功"
179
+ else
180
+ print_error "Rebase 失败,请手动解决冲突后重新运行发布脚本"
181
+ exit 1
182
+ fi
183
+ ;;
184
+ 2)
185
+ print_info "使用 merge 策略合并..."
186
+ if git pull origin "$CURRENT_BRANCH" --no-rebase; then
187
+ print_success "Merge 成功"
188
+ else
189
+ print_error "Merge 失败,请手动解决冲突后重新运行发布脚本"
190
+ exit 1
191
+ fi
192
+ ;;
193
+ *)
194
+ print_info "已取消,请手动解决分支分歧后重新运行"
195
+ exit 0
196
+ ;;
197
+ esac
198
+ fi
199
+ else
200
+ print_info "本地和远程分支已同步"
201
+ fi
124
202
  fi
125
203
  print_success "代码已更新"
126
204
 
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync, writeFileSync } from 'fs';
4
+ import { execSync } from 'child_process';
5
+
6
+ try {
7
+ // 运行测试并获取结果
8
+ console.log('🧪 运行测试...');
9
+ const testOutput = execSync('npm test', { encoding: 'utf8' });
10
+
11
+ // 从测试输出中提取测试数量
12
+ // 移除ANSI颜色代码,然后匹配测试总数
13
+ const cleanOutput = testOutput.replace(/\x1B\[[0-9;]*m/g, '');
14
+ const testMatch = cleanOutput.match(/Tests\s+(\d+)\s+passed\s+\(\d+\)/);
15
+
16
+ let testCount = 0;
17
+ if (testMatch) {
18
+ testCount = parseInt(testMatch[1]);
19
+ }
20
+
21
+ if (testCount === 0) {
22
+ console.log('❌ 无法从测试输出中提取测试数量');
23
+ console.log('测试输出:', testOutput.slice(-500)); // 显示最后500字符用于调试
24
+ process.exit(1);
25
+ }
26
+
27
+ console.log(`✅ 检测到 ${testCount} 个测试用例`);
28
+
29
+ // 读取README文件
30
+ const readmePath = 'README.md';
31
+ let readmeContent = readFileSync(readmePath, 'utf8');
32
+
33
+ // 更新测试徽章
34
+ const badgeRegex = /tests-\d+%20passed/g;
35
+ const newBadge = `tests-${testCount}%20passed`;
36
+
37
+ if (readmeContent.match(badgeRegex)) {
38
+ const oldContent = readmeContent;
39
+ readmeContent = readmeContent.replace(badgeRegex, newBadge);
40
+
41
+ if (oldContent !== readmeContent) {
42
+ writeFileSync(readmePath, readmeContent);
43
+ console.log(`✅ README中的测试数量已更新为 ${testCount}`);
44
+ } else {
45
+ console.log(`ℹ️ 测试数量无变化,保持 ${testCount}`);
46
+ }
47
+ } else {
48
+ console.log('❌ 未找到测试徽章,无法更新');
49
+ process.exit(1);
50
+ }
51
+
52
+ } catch (error) {
53
+ console.error('❌ 更新测试数量失败:', error.message);
54
+ process.exit(1);
55
+ }