@zjex/git-workflow 0.3.7 → 0.3.9

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/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
  <a href="https://github.com/iamzjt-front-end/git-workflow"><img src="https://img.shields.io/github/stars/iamzjt-front-end/git-workflow?style=flat&colorA=18181B&colorB=F59E0B" alt="github stars"></a>
13
13
  <a href="https://github.com/iamzjt-front-end/git-workflow/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@zjex/git-workflow?style=flat&colorA=18181B&colorB=10B981" alt="license"></a>
14
14
  <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D18-339933?style=flat&logo=node.js&logoColor=white&colorA=18181B" alt="node version"></a>
15
- <a href="https://github.com/iamzjt-front-end/git-workflow/actions"><img src="https://img.shields.io/badge/tests-267%20passed-success?style=flat&colorA=18181B" alt="tests"></a>
15
+ <a href="https://github.com/iamzjt-front-end/git-workflow/actions"><img src="https://img.shields.io/badge/tests-290%20passed-success?style=flat&colorA=18181B" alt="tests"></a>
16
16
  <a href="https://github.com/iamzjt-front-end/git-workflow/issues"><img src="https://img.shields.io/github/issues/iamzjt-front-end/git-workflow?style=flat&colorA=18181B&colorB=EC4899" alt="issues"></a>
17
17
  </p>
18
18
 
package/dist/index.js CHANGED
@@ -91,9 +91,9 @@ __export(update_notifier_exports, {
91
91
  clearUpdateCache: () => clearUpdateCache
92
92
  });
93
93
  import { execSync as execSync6 } from "child_process";
94
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, unlinkSync } from "fs";
94
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, existsSync as existsSync3, unlinkSync as unlinkSync2 } from "fs";
95
95
  import { homedir as homedir3 } from "os";
96
- import { join as join3 } from "path";
96
+ import { join as join4 } from "path";
97
97
  import boxen from "boxen";
98
98
  import { select as select7 } from "@inquirer/prompts";
99
99
  import ora5 from "ora";
@@ -179,11 +179,10 @@ function showSimpleNotification(current, latest) {
179
179
  )} \u2192 ${colors.green(latest)} ${colors.dim("\u8FD0\u884C")} ${colors.cyan(
180
180
  "gw update"
181
181
  )} ${colors.dim("\u66F4\u65B0")}`;
182
- console.log("");
183
182
  console.log(
184
183
  boxen(message, {
185
184
  padding: { top: 0, bottom: 0, left: 2, right: 2 },
186
- margin: { top: 0, bottom: 1, left: 0, right: 0 },
185
+ margin: { top: 0, bottom: 0, left: 0, right: 0 },
187
186
  borderStyle: "round",
188
187
  borderColor: "yellow",
189
188
  align: "center"
@@ -283,16 +282,16 @@ async function performUpdate(packageName) {
283
282
  }
284
283
  function clearUpdateCache() {
285
284
  try {
286
- const cacheFile = join3(homedir3(), CACHE_FILE);
285
+ const cacheFile = join4(homedir3(), CACHE_FILE);
287
286
  if (existsSync3(cacheFile)) {
288
- unlinkSync(cacheFile);
287
+ unlinkSync2(cacheFile);
289
288
  }
290
289
  } catch {
291
290
  }
292
291
  }
293
292
  function readCache() {
294
293
  try {
295
- const cacheFile = join3(homedir3(), CACHE_FILE);
294
+ const cacheFile = join4(homedir3(), CACHE_FILE);
296
295
  if (!existsSync3(cacheFile)) {
297
296
  return null;
298
297
  }
@@ -304,8 +303,8 @@ function readCache() {
304
303
  }
305
304
  function writeCache(cache) {
306
305
  try {
307
- const cacheFile = join3(homedir3(), CACHE_FILE);
308
- writeFileSync3(cacheFile, JSON.stringify(cache), "utf-8");
306
+ const cacheFile = join4(homedir3(), CACHE_FILE);
307
+ writeFileSync4(cacheFile, JSON.stringify(cache), "utf-8");
309
308
  } catch {
310
309
  }
311
310
  }
@@ -431,12 +430,22 @@ async function getBranchName(type) {
431
430
  console.log(colors.red(`${idLabel}\u4E0D\u80FD\u4E3A\u7A7A`));
432
431
  return null;
433
432
  }
434
- const description = await input({ message: "\u8BF7\u8F93\u5165\u63CF\u8FF0:", theme });
435
- if (!description) {
433
+ const requireDescription = type === "feature" ? config2.featureRequireDescription ?? false : config2.hotfixRequireDescription ?? false;
434
+ const descMessage = requireDescription ? "\u8BF7\u8F93\u5165\u63CF\u8FF0:" : "\u8BF7\u8F93\u5165\u63CF\u8FF0 (\u53EF\u8DF3\u8FC7):";
435
+ const description = await input({ message: descMessage, theme });
436
+ if (requireDescription && !description) {
436
437
  console.log(colors.red("\u63CF\u8FF0\u4E0D\u80FD\u4E3A\u7A7A"));
437
438
  return null;
438
439
  }
439
- return id ? `${branchPrefix}/${TODAY}-${id}-${description}` : `${branchPrefix}/${TODAY}-${description}`;
440
+ if (id && description) {
441
+ return `${branchPrefix}/${TODAY}-${id}-${description}`;
442
+ } else if (id) {
443
+ return `${branchPrefix}/${TODAY}-${id}`;
444
+ } else if (description) {
445
+ return `${branchPrefix}/${TODAY}-${description}`;
446
+ } else {
447
+ return `${branchPrefix}/${TODAY}`;
448
+ }
440
449
  }
441
450
  async function createBranch(type, baseBranchArg) {
442
451
  const config2 = getConfig();
@@ -1327,6 +1336,25 @@ async function init() {
1327
1336
  });
1328
1337
  config2.hotfixIdLabel = hotfixIdLabel;
1329
1338
  divider();
1339
+ const featureRequireDescription = await select4({
1340
+ message: "Feature \u5206\u652F\u662F\u5426\u8981\u6C42\u5FC5\u586B\u63CF\u8FF0?",
1341
+ choices: [
1342
+ { name: "\u5426", value: false },
1343
+ { name: "\u662F", value: true }
1344
+ ],
1345
+ theme
1346
+ });
1347
+ config2.featureRequireDescription = featureRequireDescription;
1348
+ const hotfixRequireDescription = await select4({
1349
+ message: "Hotfix \u5206\u652F\u662F\u5426\u8981\u6C42\u5FC5\u586B\u63CF\u8FF0?",
1350
+ choices: [
1351
+ { name: "\u5426", value: false },
1352
+ { name: "\u662F", value: true }
1353
+ ],
1354
+ theme
1355
+ });
1356
+ config2.hotfixRequireDescription = hotfixRequireDescription;
1357
+ divider();
1330
1358
  const defaultTagPrefix = await input3({
1331
1359
  message: "\u9ED8\u8BA4 Tag \u524D\u7F00 (\u7559\u7A7A\u5219\u6BCF\u6B21\u9009\u62E9):",
1332
1360
  theme
@@ -1791,6 +1819,9 @@ async function dropStash(index) {
1791
1819
  // src/commands/commit.ts
1792
1820
  init_utils();
1793
1821
  import { execSync as execSync5 } from "child_process";
1822
+ import { writeFileSync as writeFileSync3, unlinkSync } from "fs";
1823
+ import { tmpdir } from "os";
1824
+ import { join as join3 } from "path";
1794
1825
  import { select as select6, input as input5, checkbox } from "@inquirer/prompts";
1795
1826
  import ora4 from "ora";
1796
1827
 
@@ -2198,45 +2229,39 @@ function formatFileStatus(status) {
2198
2229
  }
2199
2230
  async function commit() {
2200
2231
  const config2 = getConfig();
2232
+ const autoStage = config2.autoStage ?? true;
2233
+ if (autoStage) {
2234
+ execSync5("git add -A", { stdio: "pipe" });
2235
+ }
2201
2236
  let { staged, unstaged } = parseGitStatus();
2202
- if (unstaged.length > 0) {
2203
- const autoStage = config2.autoStage ?? true;
2204
- if (autoStage) {
2205
- execSync5("git add -A", { stdio: "pipe" });
2206
- console.log(colors.green("\u2714 \u5DF2\u81EA\u52A8\u6682\u5B58\u6240\u6709\u66F4\u6539"));
2207
- divider();
2208
- const newStatus = parseGitStatus();
2209
- staged = newStatus.staged;
2210
- unstaged = newStatus.unstaged;
2211
- } else if (staged.length === 0) {
2212
- console.log(colors.yellow("\u6CA1\u6709\u6682\u5B58\u7684\u66F4\u6539"));
2213
- divider();
2214
- console.log("\u672A\u6682\u5B58\u7684\u6587\u4EF6:");
2215
- for (const { status, file } of unstaged) {
2216
- console.log(` ${formatFileStatus(status)} ${file}`);
2217
- }
2218
- divider();
2219
- const filesToStage = await checkbox({
2220
- message: "\u9009\u62E9\u8981\u6682\u5B58\u7684\u6587\u4EF6:",
2221
- choices: unstaged.map(({ status, file }) => ({
2222
- name: `${formatFileStatus(status)} ${file}`,
2223
- value: file,
2224
- checked: true
2225
- })),
2226
- theme
2227
- });
2228
- if (filesToStage.length === 0) {
2229
- console.log(colors.yellow("\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55\u6587\u4EF6\uFF0C\u5DF2\u53D6\u6D88"));
2230
- return;
2231
- }
2232
- for (const file of filesToStage) {
2233
- execSync5(`git add "${file}"`, { stdio: "pipe" });
2234
- }
2235
- console.log(colors.green(`\u2714 \u5DF2\u6682\u5B58 ${filesToStage.length} \u4E2A\u6587\u4EF6`));
2236
- divider();
2237
- const newStatus = parseGitStatus();
2238
- staged = newStatus.staged;
2237
+ if (staged.length === 0 && unstaged.length > 0 && !autoStage) {
2238
+ console.log(colors.yellow("\u6CA1\u6709\u6682\u5B58\u7684\u66F4\u6539"));
2239
+ divider();
2240
+ console.log("\u672A\u6682\u5B58\u7684\u6587\u4EF6:");
2241
+ for (const { status, file } of unstaged) {
2242
+ console.log(` ${formatFileStatus(status)} ${file}`);
2243
+ }
2244
+ divider();
2245
+ const filesToStage = await checkbox({
2246
+ message: "\u9009\u62E9\u8981\u6682\u5B58\u7684\u6587\u4EF6:",
2247
+ choices: unstaged.map(({ status, file }) => ({
2248
+ name: `${formatFileStatus(status)} ${file}`,
2249
+ value: file,
2250
+ checked: true
2251
+ })),
2252
+ theme
2253
+ });
2254
+ if (filesToStage.length === 0) {
2255
+ console.log(colors.yellow("\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55\u6587\u4EF6\uFF0C\u5DF2\u53D6\u6D88"));
2256
+ return;
2257
+ }
2258
+ for (const file of filesToStage) {
2259
+ execSync5(`git add "${file}"`, { stdio: "pipe" });
2239
2260
  }
2261
+ console.log(colors.green(`\u2714 \u5DF2\u6682\u5B58 ${filesToStage.length} \u4E2A\u6587\u4EF6`));
2262
+ divider();
2263
+ const newStatus = parseGitStatus();
2264
+ staged = newStatus.staged;
2240
2265
  }
2241
2266
  if (staged.length === 0) {
2242
2267
  console.log(colors.yellow("\u5DE5\u4F5C\u533A\u5E72\u51C0\uFF0C\u6CA1\u6709\u9700\u8981\u63D0\u4EA4\u7684\u66F4\u6539"));
@@ -2322,14 +2347,10 @@ async function commit() {
2322
2347
  }
2323
2348
  const spinner = ora4("\u6B63\u5728\u63D0\u4EA4...").start();
2324
2349
  try {
2325
- let finalStatus = parseGitStatus();
2326
- if (finalStatus.staged.length === 0 && finalStatus.unstaged.length > 0) {
2327
- const autoStage = config2.autoStage ?? true;
2328
- if (autoStage) {
2329
- execSync5("git add -A", { stdio: "pipe" });
2330
- finalStatus = parseGitStatus();
2331
- }
2350
+ if (autoStage) {
2351
+ execSync5("git add -A", { stdio: "pipe" });
2332
2352
  }
2353
+ const finalStatus = parseGitStatus();
2333
2354
  if (finalStatus.staged.length === 0) {
2334
2355
  spinner.fail("\u6CA1\u6709\u6682\u5B58\u7684\u6587\u4EF6\u53EF\u4EE5\u63D0\u4EA4");
2335
2356
  console.log("");
@@ -2340,9 +2361,18 @@ async function commit() {
2340
2361
  console.log("");
2341
2362
  return;
2342
2363
  }
2343
- execSync5(`git commit -F -`, {
2344
- input: message
2345
- });
2364
+ const tmpFile = join3(tmpdir(), `.gw-commit-msg-${Date.now()}`);
2365
+ try {
2366
+ writeFileSync3(tmpFile, message, "utf-8");
2367
+ execSync5(`git commit -F "${tmpFile}"`, {
2368
+ stdio: ["pipe", "pipe", "pipe"]
2369
+ });
2370
+ } finally {
2371
+ try {
2372
+ unlinkSync(tmpFile);
2373
+ } catch {
2374
+ }
2375
+ }
2346
2376
  spinner.succeed("\u63D0\u4EA4\u6210\u529F");
2347
2377
  const commitHash = execOutput("git rev-parse --short HEAD");
2348
2378
  console.log(colors.dim(`commit: ${commitHash}`));
@@ -2449,15 +2479,15 @@ import { execSync as execSync7 } from "child_process";
2449
2479
  import ora6 from "ora";
2450
2480
  import boxen2 from "boxen";
2451
2481
  import semver2 from "semver";
2452
- import { existsSync as existsSync4, unlinkSync as unlinkSync2 } from "fs";
2482
+ import { existsSync as existsSync4, unlinkSync as unlinkSync3 } from "fs";
2453
2483
  import { homedir as homedir4 } from "os";
2454
- import { join as join4 } from "path";
2484
+ import { join as join5 } from "path";
2455
2485
  var CACHE_FILE2 = ".gw-update-check";
2456
2486
  function clearUpdateCache2() {
2457
2487
  try {
2458
- const cacheFile = join4(homedir4(), CACHE_FILE2);
2488
+ const cacheFile = join5(homedir4(), CACHE_FILE2);
2459
2489
  if (existsSync4(cacheFile)) {
2460
- unlinkSync2(cacheFile);
2490
+ unlinkSync3(cacheFile);
2461
2491
  }
2462
2492
  } catch {
2463
2493
  }
@@ -2914,7 +2944,7 @@ process.on("SIGTERM", () => {
2914
2944
  console.log("");
2915
2945
  process.exit(0);
2916
2946
  });
2917
- var version = true ? "0.3.7" : "0.0.0-dev";
2947
+ var version = true ? "0.3.9" : "0.0.0-dev";
2918
2948
  async function mainMenu() {
2919
2949
  console.log(
2920
2950
  colors.green(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zjex/git-workflow",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "🚀 极简的 Git 工作流 CLI 工具,让分支管理和版本发布变得轻松愉快",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,15 +32,32 @@ export async function getBranchName(type: BranchType): Promise<string | null> {
32
32
  return null;
33
33
  }
34
34
 
35
- const description = await input({ message: "请输入描述:", theme });
36
- if (!description) {
35
+ // 描述是否必填,默认非必填
36
+ const requireDescription =
37
+ type === "feature"
38
+ ? config.featureRequireDescription ?? false
39
+ : config.hotfixRequireDescription ?? false;
40
+ const descMessage = requireDescription
41
+ ? "请输入描述:"
42
+ : "请输入描述 (可跳过):";
43
+
44
+ const description = await input({ message: descMessage, theme });
45
+
46
+ if (requireDescription && !description) {
37
47
  console.log(colors.red("描述不能为空"));
38
48
  return null;
39
49
  }
40
50
 
41
- return id
42
- ? `${branchPrefix}/${TODAY}-${id}-${description}`
43
- : `${branchPrefix}/${TODAY}-${description}`;
51
+ // 构建分支名
52
+ if (id && description) {
53
+ return `${branchPrefix}/${TODAY}-${id}-${description}`;
54
+ } else if (id) {
55
+ return `${branchPrefix}/${TODAY}-${id}`;
56
+ } else if (description) {
57
+ return `${branchPrefix}/${TODAY}-${description}`;
58
+ } else {
59
+ return `${branchPrefix}/${TODAY}`;
60
+ }
44
61
  }
45
62
 
46
63
  export async function createBranch(
@@ -1,4 +1,7 @@
1
1
  import { execSync } from "child_process";
2
+ import { writeFileSync, unlinkSync } from "fs";
3
+ import { tmpdir } from "os";
4
+ import { join } from "path";
2
5
  import { select, input, checkbox } from "@inquirer/prompts";
3
6
  import ora from "ora";
4
7
  import { colors, theme, execOutput, divider } from "../utils.js";
@@ -102,58 +105,52 @@ function formatFileStatus(status: string): string {
102
105
  */
103
106
  export async function commit(): Promise<void> {
104
107
  const config = getConfig();
105
- let { staged, unstaged } = parseGitStatus();
106
-
107
- // ========== 步骤 1: 处理未暂存的文件 ==========
108
- if (unstaged.length > 0) {
109
- const autoStage = config.autoStage ?? true;
108
+ const autoStage = config.autoStage ?? true;
110
109
 
111
- if (autoStage) {
112
- // 自动暂存所有文件
113
- execSync("git add -A", { stdio: "pipe" });
114
- console.log(colors.green("✔ 已自动暂存所有更改"));
115
- divider();
116
- // 重新获取状态
117
- const newStatus = parseGitStatus();
118
- staged = newStatus.staged;
119
- unstaged = newStatus.unstaged;
120
- } else if (staged.length === 0) {
121
- // 没有暂存的文件,且不自动暂存,让用户选择
122
- console.log(colors.yellow("没有暂存的更改"));
123
- divider();
124
- console.log("未暂存的文件:");
125
- for (const { status, file } of unstaged) {
126
- console.log(` ${formatFileStatus(status)} ${file}`);
127
- }
128
- divider();
110
+ // ========== 步骤 1: 自动暂存(如果启用)==========
111
+ if (autoStage) {
112
+ execSync("git add -A", { stdio: "pipe" });
113
+ }
129
114
 
130
- // 让用户选择要暂存的文件
131
- const filesToStage = await checkbox({
132
- message: "选择要暂存的文件:",
133
- choices: unstaged.map(({ status, file }) => ({
134
- name: `${formatFileStatus(status)} ${file}`,
135
- value: file,
136
- checked: true,
137
- })),
138
- theme,
139
- });
115
+ // 获取当前状态
116
+ let { staged, unstaged } = parseGitStatus();
140
117
 
141
- if (filesToStage.length === 0) {
142
- console.log(colors.yellow("没有选择任何文件,已取消"));
143
- return;
144
- }
118
+ // ========== 步骤 2: 如果没有暂存文件,让用户选择 ==========
119
+ if (staged.length === 0 && unstaged.length > 0 && !autoStage) {
120
+ console.log(colors.yellow("没有暂存的更改"));
121
+ divider();
122
+ console.log("未暂存的文件:");
123
+ for (const { status, file } of unstaged) {
124
+ console.log(` ${formatFileStatus(status)} ${file}`);
125
+ }
126
+ divider();
127
+
128
+ // 让用户选择要暂存的文件
129
+ const filesToStage = await checkbox({
130
+ message: "选择要暂存的文件:",
131
+ choices: unstaged.map(({ status, file }) => ({
132
+ name: `${formatFileStatus(status)} ${file}`,
133
+ value: file,
134
+ checked: true,
135
+ })),
136
+ theme,
137
+ });
145
138
 
146
- // 暂存选中的文件
147
- for (const file of filesToStage) {
148
- execSync(`git add "${file}"`, { stdio: "pipe" });
149
- }
150
- console.log(colors.green(`✔ 已暂存 ${filesToStage.length} 个文件`));
151
- divider();
139
+ if (filesToStage.length === 0) {
140
+ console.log(colors.yellow("没有选择任何文件,已取消"));
141
+ return;
142
+ }
152
143
 
153
- // 重新获取状态
154
- const newStatus = parseGitStatus();
155
- staged = newStatus.staged;
144
+ // 暂存选中的文件
145
+ for (const file of filesToStage) {
146
+ execSync(`git add "${file}"`, { stdio: "pipe" });
156
147
  }
148
+ console.log(colors.green(`✔ 已暂存 ${filesToStage.length} 个文件`));
149
+ divider();
150
+
151
+ // 重新获取状态
152
+ const newStatus = parseGitStatus();
153
+ staged = newStatus.staged;
157
154
  }
158
155
 
159
156
  // ========== 步骤 2: 检查是否有文件可提交 ==========
@@ -264,18 +261,13 @@ export async function commit(): Promise<void> {
264
261
  const spinner = ora("正在提交...").start();
265
262
 
266
263
  try {
267
- // 提交前再次检查是否有暂存的文件
268
- let finalStatus = parseGitStatus();
269
-
270
- // 如果暂存区为空,但有未暂存的更改,且开启了自动暂存,则重新暂存
271
- if (finalStatus.staged.length === 0 && finalStatus.unstaged.length > 0) {
272
- const autoStage = config.autoStage ?? true;
273
- if (autoStage) {
274
- execSync("git add -A", { stdio: "pipe" });
275
- finalStatus = parseGitStatus();
276
- }
264
+ // 提交前再次暂存所有更改(确保不会遗漏)
265
+ if (autoStage) {
266
+ execSync("git add -A", { stdio: "pipe" });
277
267
  }
278
268
 
269
+ // 检查是否有暂存的文件
270
+ const finalStatus = parseGitStatus();
279
271
  if (finalStatus.staged.length === 0) {
280
272
  spinner.fail("没有暂存的文件可以提交");
281
273
  console.log("");
@@ -287,11 +279,21 @@ export async function commit(): Promise<void> {
287
279
  return;
288
280
  }
289
281
 
290
- // 处理多行消息:使用 git commit -F - 通过 stdin 传递
291
- // 这样可以正确处理包含换行符的 commit message
292
- execSync(`git commit -F -`, {
293
- input: message,
294
- });
282
+ // 处理多行消息:使用临时文件传递 commit message
283
+ const tmpFile = join(tmpdir(), `.gw-commit-msg-${Date.now()}`);
284
+ try {
285
+ writeFileSync(tmpFile, message, "utf-8");
286
+ execSync(`git commit -F "${tmpFile}"`, {
287
+ stdio: ["pipe", "pipe", "pipe"],
288
+ });
289
+ } finally {
290
+ // 清理临时文件
291
+ try {
292
+ unlinkSync(tmpFile);
293
+ } catch {
294
+ // 忽略删除失败
295
+ }
296
+ }
295
297
  spinner.succeed("提交成功");
296
298
 
297
299
  // 显示提交信息
@@ -118,6 +118,29 @@ export async function init(): Promise<void> {
118
118
 
119
119
  divider();
120
120
 
121
+ // 描述必填配置
122
+ const featureRequireDescription = await select({
123
+ message: "Feature 分支是否要求必填描述?",
124
+ choices: [
125
+ { name: "否", value: false },
126
+ { name: "是", value: true },
127
+ ],
128
+ theme,
129
+ });
130
+ config.featureRequireDescription = featureRequireDescription;
131
+
132
+ const hotfixRequireDescription = await select({
133
+ message: "Hotfix 分支是否要求必填描述?",
134
+ choices: [
135
+ { name: "否", value: false },
136
+ { name: "是", value: true },
137
+ ],
138
+ theme,
139
+ });
140
+ config.hotfixRequireDescription = hotfixRequireDescription;
141
+
142
+ divider();
143
+
121
144
  // Tag 配置
122
145
  const defaultTagPrefix = await input({
123
146
  message: "默认 Tag 前缀 (留空则每次选择):",
@@ -269,15 +292,16 @@ export async function init(): Promise<void> {
269
292
  const detailedDescription = await select({
270
293
  message: "是否生成详细的修改点描述?",
271
294
  choices: [
272
- {
273
- name: "是(包含修改点列表,推荐)",
295
+ {
296
+ name: "是(包含修改点列表,推荐)",
274
297
  value: true,
275
- description: "如:feat(auth): 添加用户登录功能\n\n- 实现用户名密码登录接口\n- 添加登录状态验证中间件"
298
+ description:
299
+ "如:feat(auth): 添加用户登录功能\n\n- 实现用户名密码登录接口\n- 添加登录状态验证中间件",
276
300
  },
277
- {
278
- name: "否(仅生成标题)",
301
+ {
302
+ name: "否(仅生成标题)",
279
303
  value: false,
280
- description: "如:feat(auth): 添加用户登录功能"
304
+ description: "如:feat(auth): 添加用户登录功能",
281
305
  },
282
306
  ],
283
307
  theme,
@@ -286,20 +310,20 @@ export async function init(): Promise<void> {
286
310
  const aiUseEmoji = await select({
287
311
  message: "AI 生成的 commit message 是否包含 emoji?",
288
312
  choices: [
289
- {
290
- name: "是(推荐)",
313
+ {
314
+ name: "是(推荐)",
291
315
  value: true,
292
- description: "如:✨ feat(auth): 添加用户登录功能"
316
+ description: "如:✨ feat(auth): 添加用户登录功能",
293
317
  },
294
- {
295
- name: "否",
318
+ {
319
+ name: "否",
296
320
  value: false,
297
- description: "如:feat(auth): 添加用户登录功能"
321
+ description: "如:feat(auth): 添加用户登录功能",
298
322
  },
299
- {
300
- name: "跟随全局设置",
323
+ {
324
+ name: "跟随全局设置",
301
325
  value: undefined,
302
- description: `当前全局设置:${useEmoji ? '启用' : '禁用'} emoji`
326
+ description: `当前全局设置:${useEmoji ? "启用" : "禁用"} emoji`,
303
327
  },
304
328
  ],
305
329
  theme,
package/src/config.ts CHANGED
@@ -12,6 +12,10 @@ export interface GwConfig {
12
12
  hotfixPrefix: string;
13
13
  // 是否要求必填 ID,默认 false
14
14
  requireId: boolean;
15
+ // feature 分支是否要求必填描述,默认 false
16
+ featureRequireDescription?: boolean;
17
+ // hotfix 分支是否要求必填描述,默认 false
18
+ hotfixRequireDescription?: boolean;
15
19
  // ID 标签名称
16
20
  featureIdLabel: string;
17
21
  hotfixIdLabel: string;
@@ -151,11 +151,10 @@ function showSimpleNotification(current: string, latest: string): void {
151
151
  "gw update"
152
152
  )} ${colors.dim("更新")}`;
153
153
 
154
- console.log("");
155
154
  console.log(
156
155
  boxen(message, {
157
156
  padding: { top: 0, bottom: 0, left: 2, right: 2 },
158
- margin: { top: 0, bottom: 1, left: 0, right: 0 },
157
+ margin: { top: 0, bottom: 0, left: 0, right: 0 },
159
158
  borderStyle: "round",
160
159
  borderColor: "yellow",
161
160
  align: "center",