@zjex/git-workflow 0.4.4 → 0.4.6
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.
- package/CHANGELOG.md +29 -0
- package/README.md +1 -1
- package/dist/index.js +87 -15
- package/docs/commands/amend-date.md +75 -13
- package/docs/guide/command-quotes-handling.md +279 -0
- package/docs/guide/debug-mode.md +384 -0
- package/package.json +1 -1
- package/src/commands/amend-date.ts +25 -5
- package/src/commands/amend.ts +0 -1
- package/src/index.ts +11 -3
- package/src/utils.ts +91 -10
- package/tests/amend-date.test.ts +59 -4
- package/tests/command-with-quotes.test.ts +378 -0
- package/tests/debug-mode.test.ts +503 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
# Debug 模式
|
|
2
|
+
|
|
3
|
+
Debug 模式可以帮助你诊断命令执行失败的原因,显示详细的命令、输出和错误信息。
|
|
4
|
+
|
|
5
|
+
## 启用 Debug 模式
|
|
6
|
+
|
|
7
|
+
在任何命令后添加 `--debug` 或 `-d` 参数:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 基本用法
|
|
11
|
+
gw tag --debug
|
|
12
|
+
gw tag -d
|
|
13
|
+
|
|
14
|
+
# 其他命令
|
|
15
|
+
gw f --debug
|
|
16
|
+
gw b --debug
|
|
17
|
+
gw c --debug
|
|
18
|
+
gw s --debug
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Debug 输出内容
|
|
22
|
+
|
|
23
|
+
启用 debug 模式后,你会看到:
|
|
24
|
+
|
|
25
|
+
### 1. 模式提示
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
🐛 Debug 模式已启用
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. 执行的命令
|
|
32
|
+
|
|
33
|
+
每次执行 Git 命令时,会显示完整的命令字符串:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
[DEBUG] 执行命令: git tag -a "v1.5.3" -m "Release v1.5.3"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 3. 退出码
|
|
40
|
+
|
|
41
|
+
命令执行完成后显示退出码:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
[DEBUG] 退出码: 0
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- `0` 表示成功
|
|
48
|
+
- 非 `0` 表示失败
|
|
49
|
+
|
|
50
|
+
### 4. 标准输出
|
|
51
|
+
|
|
52
|
+
如果命令有标准输出,会显示:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
[DEBUG] 标准输出:
|
|
56
|
+
Counting objects: 3, done.
|
|
57
|
+
Writing objects: 100% (3/3), 256 bytes | 256.00 KiB/s, done.
|
|
58
|
+
Total 3 (delta 0), reused 0 (delta 0)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 5. 错误输出
|
|
62
|
+
|
|
63
|
+
如果命令失败,会显示详细的错误信息:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
[DEBUG] 错误输出:
|
|
67
|
+
fatal: Failed to resolve 'HEAD' as a valid ref.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 6. 故障排查信息
|
|
71
|
+
|
|
72
|
+
命令失败时,还会显示额外的排查信息:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
[DEBUG] 故障排查信息:
|
|
76
|
+
命令: git tag -a "v1.5.3" -m "Release v1.5.3"
|
|
77
|
+
工作目录: /Users/username/project
|
|
78
|
+
Shell: /bin/zsh
|
|
79
|
+
建议: 尝试在终端中直接运行上述命令以获取更多信息
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 使用场景
|
|
83
|
+
|
|
84
|
+
### 场景 1:Tag 创建失败
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
$ gw tag --debug
|
|
88
|
+
|
|
89
|
+
🐛 Debug 模式已启用
|
|
90
|
+
|
|
91
|
+
✔ 选择 tag 前缀: v (最新: v1.5.2)
|
|
92
|
+
当前最新 tag: v1.5.2
|
|
93
|
+
|
|
94
|
+
────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
✔ 选择版本类型: patch → v1.5.3
|
|
97
|
+
|
|
98
|
+
────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
[DEBUG] 执行命令: git tag -a "v1.5.3" -m "Release v1.5.3"
|
|
101
|
+
[DEBUG] 退出码: 128
|
|
102
|
+
[DEBUG] 错误输出:
|
|
103
|
+
fatal: Failed to resolve 'HEAD' as a valid ref.
|
|
104
|
+
|
|
105
|
+
✗ tag 创建失败
|
|
106
|
+
fatal: Failed to resolve 'HEAD' as a valid ref.
|
|
107
|
+
|
|
108
|
+
[DEBUG] 故障排查信息:
|
|
109
|
+
命令: git tag -a "v1.5.3" -m "Release v1.5.3"
|
|
110
|
+
工作目录: /Users/username/cmk-vue
|
|
111
|
+
Shell: /bin/zsh
|
|
112
|
+
建议: 尝试在终端中直接运行上述命令以获取更多信息
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
从这个输出可以看出:
|
|
116
|
+
|
|
117
|
+
- 命令本身是正确的(引号处理正常)
|
|
118
|
+
- 退出码 128 表示 Git 错误
|
|
119
|
+
- 错误原因:`HEAD` 无法解析(仓库没有提交)
|
|
120
|
+
|
|
121
|
+
### 场景 2:分支推送失败
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
$ gw f --debug
|
|
125
|
+
|
|
126
|
+
🐛 Debug 模式已启用
|
|
127
|
+
|
|
128
|
+
✔ 请输入需求ID: 123
|
|
129
|
+
✔ 请输入描述: add-feature
|
|
130
|
+
|
|
131
|
+
────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
[DEBUG] 执行命令: git fetch origin main
|
|
134
|
+
[DEBUG] 退出码: 0
|
|
135
|
+
|
|
136
|
+
[DEBUG] 执行命令: git checkout -b "feature/20240120-123-add-feature" origin/main
|
|
137
|
+
[DEBUG] 退出码: 0
|
|
138
|
+
[DEBUG] 标准输出:
|
|
139
|
+
Switched to a new branch 'feature/20240120-123-add-feature'
|
|
140
|
+
|
|
141
|
+
✔ 分支创建成功: feature/20240120-123-add-feature
|
|
142
|
+
|
|
143
|
+
────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
(自动推送已启用)
|
|
146
|
+
|
|
147
|
+
[DEBUG] 执行命令: git push -u origin "feature/20240120-123-add-feature"
|
|
148
|
+
[DEBUG] 退出码: 128
|
|
149
|
+
[DEBUG] 错误输出:
|
|
150
|
+
fatal: unable to access 'https://github.com/user/repo.git/': Could not resolve host: github.com
|
|
151
|
+
|
|
152
|
+
✗ 远程推送失败
|
|
153
|
+
fatal: unable to access 'https://github.com/user/repo.git/': Could not resolve host: github.com
|
|
154
|
+
|
|
155
|
+
[DEBUG] 故障排查信息:
|
|
156
|
+
命令: git push -u origin "feature/20240120-123-add-feature"
|
|
157
|
+
工作目录: /Users/username/project
|
|
158
|
+
Shell: /bin/zsh
|
|
159
|
+
建议: 尝试在终端中直接运行上述命令以获取更多信息
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
从这个输出可以看出:
|
|
163
|
+
|
|
164
|
+
- 分支创建成功
|
|
165
|
+
- 推送失败是因为网络问题(无法解析 github.com)
|
|
166
|
+
|
|
167
|
+
### 场景 3:Stash 创建失败
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
$ gw s --debug
|
|
171
|
+
|
|
172
|
+
🐛 Debug 模式已启用
|
|
173
|
+
|
|
174
|
+
没有 stash 记录
|
|
175
|
+
✔ 检测到未提交的变更,是否创建 stash? 是
|
|
176
|
+
✔ Stash 消息 (可选): 临时保存:修复bug
|
|
177
|
+
|
|
178
|
+
[DEBUG] 执行命令: git stash push -m "临时保存:修复bug"
|
|
179
|
+
[DEBUG] 退出码: 0
|
|
180
|
+
[DEBUG] 标准输出:
|
|
181
|
+
Saved working directory and index state On master: 临时保存:修复bug
|
|
182
|
+
|
|
183
|
+
✔ Stash 创建成功
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 对比:普通模式 vs Debug 模式
|
|
187
|
+
|
|
188
|
+
### 普通模式
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
$ gw tag
|
|
192
|
+
|
|
193
|
+
✔ 选择 tag 前缀: v (最新: v1.5.2)
|
|
194
|
+
当前最新 tag: v1.5.2
|
|
195
|
+
|
|
196
|
+
────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
✔ 选择版本类型: patch → v1.5.3
|
|
199
|
+
|
|
200
|
+
────────────────────────────────────────
|
|
201
|
+
|
|
202
|
+
✗ tag 创建失败
|
|
203
|
+
fatal: Failed to resolve 'HEAD' as a valid ref.
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Debug 模式
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
$ gw tag --debug
|
|
210
|
+
|
|
211
|
+
🐛 Debug 模式已启用
|
|
212
|
+
|
|
213
|
+
✔ 选择 tag 前缀: v (最新: v1.5.2)
|
|
214
|
+
当前最新 tag: v1.5.2
|
|
215
|
+
|
|
216
|
+
────────────────────────────────────────
|
|
217
|
+
|
|
218
|
+
✔ 选择版本类型: patch → v1.5.3
|
|
219
|
+
|
|
220
|
+
────────────────────────────────────────
|
|
221
|
+
|
|
222
|
+
[DEBUG] 执行命令: git tag -a "v1.5.3" -m "Release v1.5.3"
|
|
223
|
+
[DEBUG] 退出码: 128
|
|
224
|
+
[DEBUG] 错误输出:
|
|
225
|
+
fatal: Failed to resolve 'HEAD' as a valid ref.
|
|
226
|
+
|
|
227
|
+
✗ tag 创建失败
|
|
228
|
+
fatal: Failed to resolve 'HEAD' as a valid ref.
|
|
229
|
+
|
|
230
|
+
[DEBUG] 故障排查信息:
|
|
231
|
+
命令: git tag -a "v1.5.3" -m "Release v1.5.3"
|
|
232
|
+
工作目录: /Users/username/cmk-vue
|
|
233
|
+
Shell: /bin/zsh
|
|
234
|
+
建议: 尝试在终端中直接运行上述命令以获取更多信息
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## 常见问题排查
|
|
238
|
+
|
|
239
|
+
### 问题 1:Failed to resolve 'HEAD'
|
|
240
|
+
|
|
241
|
+
**错误信息:**
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
fatal: Failed to resolve 'HEAD' as a valid ref.
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**原因:** 仓库没有任何提交
|
|
248
|
+
|
|
249
|
+
**解决方法:**
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
git add .
|
|
253
|
+
git commit -m "Initial commit"
|
|
254
|
+
gw tag
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 问题 2:Tag already exists
|
|
258
|
+
|
|
259
|
+
**错误信息:**
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
fatal: tag 'v1.5.3' already exists
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**原因:** Tag 已经存在
|
|
266
|
+
|
|
267
|
+
**解决方法:**
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# 删除旧 tag
|
|
271
|
+
git tag -d v1.5.3
|
|
272
|
+
git push origin --delete v1.5.3
|
|
273
|
+
|
|
274
|
+
# 重新创建
|
|
275
|
+
gw tag
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### 问题 3:Network error
|
|
279
|
+
|
|
280
|
+
**错误信息:**
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
fatal: unable to access 'https://github.com/...': Could not resolve host
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**原因:** 网络连接问题
|
|
287
|
+
|
|
288
|
+
**解决方法:**
|
|
289
|
+
|
|
290
|
+
- 检查网络连接
|
|
291
|
+
- 检查代理设置
|
|
292
|
+
- 稍后重试
|
|
293
|
+
|
|
294
|
+
### 问题 4:Permission denied
|
|
295
|
+
|
|
296
|
+
**错误信息:**
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
fatal: could not read Username for 'https://github.com': terminal prompts disabled
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**原因:** 没有配置 Git 凭据
|
|
303
|
+
|
|
304
|
+
**解决方法:**
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# 配置 SSH
|
|
308
|
+
ssh-keygen -t ed25519 -C "your_email@example.com"
|
|
309
|
+
# 添加 SSH key 到 GitHub
|
|
310
|
+
|
|
311
|
+
# 或使用 HTTPS + token
|
|
312
|
+
git config --global credential.helper store
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## 提交 Bug 报告
|
|
316
|
+
|
|
317
|
+
如果你遇到问题需要提交 bug 报告,请:
|
|
318
|
+
|
|
319
|
+
1. **使用 debug 模式重现问题**
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
gw <command> --debug > debug.log 2>&1
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
2. **包含以下信息**
|
|
326
|
+
- 完整的 debug 输出
|
|
327
|
+
- 操作系统和 Shell 版本
|
|
328
|
+
- Git 版本:`git --version`
|
|
329
|
+
- gw 版本:`gw --version`
|
|
330
|
+
- 仓库状态:`git status`
|
|
331
|
+
|
|
332
|
+
3. **提交到 GitHub Issues**
|
|
333
|
+
- 附上 `debug.log` 文件
|
|
334
|
+
- 描述期望的行为
|
|
335
|
+
- 描述实际的行为
|
|
336
|
+
|
|
337
|
+
## 性能影响
|
|
338
|
+
|
|
339
|
+
Debug 模式会:
|
|
340
|
+
|
|
341
|
+
- ✅ 捕获额外的输出信息
|
|
342
|
+
- ✅ 显示更多日志
|
|
343
|
+
- ⚠️ 轻微增加执行时间(通常 < 100ms)
|
|
344
|
+
- ✅ 不影响命令的实际功能
|
|
345
|
+
|
|
346
|
+
建议:
|
|
347
|
+
|
|
348
|
+
- 日常使用:不启用 debug 模式
|
|
349
|
+
- 遇到问题:启用 debug 模式排查
|
|
350
|
+
- 提交 bug:必须提供 debug 输出
|
|
351
|
+
|
|
352
|
+
## 相关命令
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
# 查看版本
|
|
356
|
+
gw --version
|
|
357
|
+
gw -v
|
|
358
|
+
|
|
359
|
+
# 查看帮助
|
|
360
|
+
gw --help
|
|
361
|
+
gw -h
|
|
362
|
+
|
|
363
|
+
# 启用 debug
|
|
364
|
+
gw <command> --debug
|
|
365
|
+
gw <command> -d
|
|
366
|
+
|
|
367
|
+
# 组合使用(不支持)
|
|
368
|
+
# ❌ gw --version --debug # 不会显示 debug 信息
|
|
369
|
+
# ✅ gw tag --debug # 正确用法
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## 实现细节
|
|
373
|
+
|
|
374
|
+
Debug 模式通过以下方式实现:
|
|
375
|
+
|
|
376
|
+
1. **全局标志**:在主入口设置全局 `DEBUG_MODE` 标志
|
|
377
|
+
2. **命令拦截**:在 `execAsync` 中检查 debug 模式
|
|
378
|
+
3. **输出捕获**:捕获 stdout 和 stderr
|
|
379
|
+
4. **格式化输出**:使用颜色和前缀标识 debug 信息
|
|
380
|
+
|
|
381
|
+
相关文件:
|
|
382
|
+
|
|
383
|
+
- `src/index.ts` - 解析 `--debug` 参数
|
|
384
|
+
- `src/utils.ts` - 实现 debug 输出逻辑
|
package/package.json
CHANGED
|
@@ -19,14 +19,33 @@ function formatGitDate(date: Date): string {
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* 解析用户输入的日期
|
|
22
|
-
* 支持格式:
|
|
22
|
+
* 支持格式:
|
|
23
|
+
* - YYYY-MM-DD (默认 00:00:00)
|
|
24
|
+
* - YYYY-MM-DD HH:mm:ss
|
|
23
25
|
* @param input 用户输入
|
|
24
26
|
* @returns Date 对象或 null
|
|
25
27
|
*/
|
|
26
28
|
function parseDate(input: string): Date | null {
|
|
27
29
|
const trimmed = input.trim();
|
|
28
|
-
const dateMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
29
30
|
|
|
31
|
+
// 尝试匹配完整格式: YYYY-MM-DD HH:mm:ss
|
|
32
|
+
const fullMatch = trimmed.match(
|
|
33
|
+
/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/,
|
|
34
|
+
);
|
|
35
|
+
if (fullMatch) {
|
|
36
|
+
const [, year, month, day, hours, minutes, seconds] = fullMatch;
|
|
37
|
+
return new Date(
|
|
38
|
+
parseInt(year),
|
|
39
|
+
parseInt(month) - 1,
|
|
40
|
+
parseInt(day),
|
|
41
|
+
parseInt(hours),
|
|
42
|
+
parseInt(minutes),
|
|
43
|
+
parseInt(seconds),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 尝试匹配简化格式: YYYY-MM-DD (默认 00:00:00)
|
|
48
|
+
const dateMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
30
49
|
if (dateMatch) {
|
|
31
50
|
const [, year, month, day] = dateMatch;
|
|
32
51
|
return new Date(
|
|
@@ -120,7 +139,6 @@ export async function amendDate(commitHash?: string): Promise<void> {
|
|
|
120
139
|
value: c,
|
|
121
140
|
description: c.date,
|
|
122
141
|
})),
|
|
123
|
-
pageSize: 15,
|
|
124
142
|
theme,
|
|
125
143
|
});
|
|
126
144
|
}
|
|
@@ -133,7 +151,9 @@ export async function amendDate(commitHash?: string): Promise<void> {
|
|
|
133
151
|
divider();
|
|
134
152
|
|
|
135
153
|
// ========== 步骤 2: 输入新日期 ==========
|
|
136
|
-
console.log(colors.dim("
|
|
154
|
+
console.log(colors.dim("支持格式:"));
|
|
155
|
+
console.log(colors.dim(" YYYY-MM-DD (如: 2026-01-19,默认 00:00:00)"));
|
|
156
|
+
console.log(colors.dim(" YYYY-MM-DD HH:mm:ss (如: 2026-01-19 14:30:00)"));
|
|
137
157
|
console.log("");
|
|
138
158
|
|
|
139
159
|
const dateInput = await input({
|
|
@@ -141,7 +161,7 @@ export async function amendDate(commitHash?: string): Promise<void> {
|
|
|
141
161
|
validate: (value) => {
|
|
142
162
|
const parsed = parseDate(value);
|
|
143
163
|
if (!parsed) {
|
|
144
|
-
return "日期格式不正确,请使用 YYYY-MM-DD 格式";
|
|
164
|
+
return "日期格式不正确,请使用 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss 格式";
|
|
145
165
|
}
|
|
146
166
|
return true;
|
|
147
167
|
},
|
package/src/commands/amend.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { cac } from "cac";
|
|
14
14
|
import { select } from "@inquirer/prompts";
|
|
15
15
|
import { ExitPromptError } from "@inquirer/core";
|
|
16
|
-
import { checkGitRepo, theme, colors } from "./utils.js";
|
|
16
|
+
import { checkGitRepo, theme, colors, setDebugMode } from "./utils.js";
|
|
17
17
|
import { createBranch, deleteBranch } from "./commands/branch.js";
|
|
18
18
|
import {
|
|
19
19
|
listTags,
|
|
@@ -488,12 +488,20 @@ cli
|
|
|
488
488
|
console.log("");
|
|
489
489
|
});
|
|
490
490
|
|
|
491
|
-
// 不使用 cac 的 version,手动处理 --version 和 --
|
|
491
|
+
// 不使用 cac 的 version,手动处理 --version、--help 和 --debug
|
|
492
492
|
cli.option("-v, --version", "显示版本号");
|
|
493
493
|
cli.option("-h, --help", "显示帮助信息");
|
|
494
|
+
cli.option("-d, --debug", "启用调试模式,显示详细的命令和错误信息");
|
|
494
495
|
|
|
495
|
-
// 在 parse 之前检查 --version 和 --
|
|
496
|
+
// 在 parse 之前检查 --version、--help 和 --debug
|
|
496
497
|
const processArgs = process.argv.slice(2);
|
|
498
|
+
|
|
499
|
+
// 检查是否启用 debug 模式
|
|
500
|
+
if (processArgs.includes("-d") || processArgs.includes("--debug")) {
|
|
501
|
+
setDebugMode(true);
|
|
502
|
+
console.log(colors.yellow("🐛 Debug 模式已启用\n"));
|
|
503
|
+
}
|
|
504
|
+
|
|
497
505
|
if (processArgs.includes("-v") || processArgs.includes("--version")) {
|
|
498
506
|
console.log(colors.yellow(`v${version}`));
|
|
499
507
|
process.exit(0);
|
package/src/utils.ts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { execSync, spawn, type ExecSyncOptions } from "child_process";
|
|
2
2
|
import type { Ora } from "ora";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 全局 debug 模式标志
|
|
6
|
+
*/
|
|
7
|
+
let debugMode = false;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 设置 debug 模式(由主入口调用)
|
|
11
|
+
*/
|
|
12
|
+
export function setDebugMode(enabled: boolean): void {
|
|
13
|
+
debugMode = enabled;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 获取当前 debug 模式状态
|
|
18
|
+
*/
|
|
19
|
+
export function isDebugMode(): boolean {
|
|
20
|
+
return debugMode;
|
|
21
|
+
}
|
|
22
|
+
|
|
4
23
|
export interface Colors {
|
|
5
24
|
red: (s: string) => string;
|
|
6
25
|
green: (s: string) => string;
|
|
@@ -104,22 +123,68 @@ export function divider(): void {
|
|
|
104
123
|
* 使用 spawn 异步执行命令,避免阻塞 spinner
|
|
105
124
|
* @param command 命令字符串
|
|
106
125
|
* @param spinner 可选的 ora spinner 实例
|
|
107
|
-
* @returns Promise<boolean
|
|
126
|
+
* @returns Promise<{success: boolean, error?: string}> 返回执行结果和错误信息
|
|
108
127
|
*/
|
|
109
|
-
export function execAsync(
|
|
128
|
+
export function execAsync(
|
|
129
|
+
command: string,
|
|
130
|
+
spinner?: Ora,
|
|
131
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
110
132
|
return new Promise((resolve) => {
|
|
111
|
-
|
|
133
|
+
// Debug 模式:显示执行的命令
|
|
134
|
+
if (debugMode) {
|
|
135
|
+
console.log(colors.dim(`\n[DEBUG] 执行命令: ${colors.cyan(command)}`));
|
|
136
|
+
}
|
|
112
137
|
|
|
113
|
-
|
|
138
|
+
// 使用 shell 模式执行命令,这样可以正确处理引号
|
|
139
|
+
const process = spawn(command, {
|
|
114
140
|
stdio: spinner ? "pipe" : "inherit",
|
|
141
|
+
shell: true,
|
|
115
142
|
});
|
|
116
143
|
|
|
144
|
+
let errorOutput = "";
|
|
145
|
+
let stdoutOutput = "";
|
|
146
|
+
|
|
147
|
+
// 捕获标准输出(debug 模式)
|
|
148
|
+
if (debugMode && process.stdout) {
|
|
149
|
+
process.stdout.on("data", (data) => {
|
|
150
|
+
stdoutOutput += data.toString();
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 捕获错误输出
|
|
155
|
+
if (process.stderr) {
|
|
156
|
+
process.stderr.on("data", (data) => {
|
|
157
|
+
errorOutput += data.toString();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
117
161
|
process.on("close", (code) => {
|
|
118
|
-
|
|
162
|
+
// Debug 模式:显示退出码和输出
|
|
163
|
+
if (debugMode) {
|
|
164
|
+
console.log(colors.dim(`[DEBUG] 退出码: ${code}`));
|
|
165
|
+
if (stdoutOutput) {
|
|
166
|
+
console.log(colors.dim(`[DEBUG] 标准输出:\n${stdoutOutput}`));
|
|
167
|
+
}
|
|
168
|
+
if (errorOutput) {
|
|
169
|
+
console.log(colors.dim(`[DEBUG] 错误输出:\n${errorOutput}`));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (code === 0) {
|
|
174
|
+
resolve({ success: true });
|
|
175
|
+
} else {
|
|
176
|
+
resolve({ success: false, error: errorOutput.trim() });
|
|
177
|
+
}
|
|
119
178
|
});
|
|
120
179
|
|
|
121
|
-
process.on("error", () => {
|
|
122
|
-
|
|
180
|
+
process.on("error", (err) => {
|
|
181
|
+
// Debug 模式:显示进程错误
|
|
182
|
+
if (debugMode) {
|
|
183
|
+
console.log(colors.dim(`[DEBUG] 进程错误: ${err.message}`));
|
|
184
|
+
console.log(colors.dim(`[DEBUG] 错误堆栈:\n${err.stack}`));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
resolve({ success: false, error: err.message });
|
|
123
188
|
});
|
|
124
189
|
});
|
|
125
190
|
}
|
|
@@ -138,9 +203,9 @@ export async function execWithSpinner(
|
|
|
138
203
|
successMessage?: string,
|
|
139
204
|
errorMessage?: string,
|
|
140
205
|
): Promise<boolean> {
|
|
141
|
-
const
|
|
206
|
+
const result = await execAsync(command, spinner);
|
|
142
207
|
|
|
143
|
-
if (success) {
|
|
208
|
+
if (result.success) {
|
|
144
209
|
if (successMessage) {
|
|
145
210
|
spinner.succeed(successMessage);
|
|
146
211
|
} else {
|
|
@@ -152,7 +217,23 @@ export async function execWithSpinner(
|
|
|
152
217
|
} else {
|
|
153
218
|
spinner.fail();
|
|
154
219
|
}
|
|
220
|
+
|
|
221
|
+
// 显示具体的错误信息
|
|
222
|
+
if (result.error) {
|
|
223
|
+
console.log(colors.dim(` ${result.error}`));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Debug 模式:显示完整的命令和建议
|
|
227
|
+
if (debugMode) {
|
|
228
|
+
console.log(colors.yellow("\n[DEBUG] 故障排查信息:"));
|
|
229
|
+
console.log(colors.dim(` 命令: ${command}`));
|
|
230
|
+
console.log(colors.dim(` 工作目录: ${process.cwd()}`));
|
|
231
|
+
console.log(colors.dim(` Shell: ${process.env.SHELL || "unknown"}`));
|
|
232
|
+
console.log(
|
|
233
|
+
colors.dim(` 建议: 尝试在终端中直接运行上述命令以获取更多信息\n`),
|
|
234
|
+
);
|
|
235
|
+
}
|
|
155
236
|
}
|
|
156
237
|
|
|
157
|
-
return success;
|
|
238
|
+
return result.success;
|
|
158
239
|
}
|