@zjex/git-workflow 0.2.22 → 0.2.23

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/dist/index.js CHANGED
@@ -655,20 +655,78 @@ async function listTags(prefix) {
655
655
  exec("git fetch --tags", true);
656
656
  spinner.stop();
657
657
  const pattern = prefix ? `${prefix}*` : "";
658
- const tags = execOutput(`git tag -l ${pattern} --sort=-v:refname`).split("\n").filter(Boolean);
658
+ const tags = execOutput(`git tag -l ${pattern} --sort=v:refname`).split("\n").filter(Boolean);
659
659
  if (tags.length === 0) {
660
660
  console.log(
661
661
  colors.yellow(prefix ? `\u6CA1\u6709 '${prefix}' \u5F00\u5934\u7684 tag` : "\u6CA1\u6709 tag")
662
662
  );
663
663
  return;
664
664
  }
665
+ if (prefix) {
666
+ console.log(colors.green(`\u4EE5 '${prefix}' \u5F00\u5934\u7684 tags:`));
667
+ const displayTags = tags.length > 20 ? tags.slice(-20) : tags;
668
+ displayTags.forEach((tag) => console.log(` ${tag}`));
669
+ if (tags.length > 20) {
670
+ console.log(colors.yellow(`
671
+ \u5171 ${tags.length} \u4E2A\uFF0C\u4EC5\u663E\u793A\u6700\u65B0 20 \u4E2A`));
672
+ }
673
+ return;
674
+ }
675
+ const grouped = /* @__PURE__ */ new Map();
676
+ tags.forEach((tag) => {
677
+ const prefix2 = tag.replace(/[0-9].*/, "") || "\u65E0\u524D\u7F00";
678
+ if (!grouped.has(prefix2)) {
679
+ grouped.set(prefix2, []);
680
+ }
681
+ grouped.get(prefix2).push(tag);
682
+ });
683
+ if (grouped.size === 1) {
684
+ console.log(colors.green("\u6240\u6709 tags:"));
685
+ const displayTags = tags.length > 20 ? tags.slice(-20) : tags;
686
+ displayTags.forEach((tag) => console.log(` ${tag}`));
687
+ if (tags.length > 20) {
688
+ console.log(colors.yellow(`
689
+ \u5171 ${tags.length} \u4E2A\uFF0C\u4EC5\u663E\u793A\u6700\u65B0 20 \u4E2A`));
690
+ }
691
+ return;
692
+ }
693
+ console.log(colors.green("\u6240\u6709 tags (\u6309\u524D\u7F00\u5206\u7EC4):"));
694
+ console.log("");
695
+ const columns = [];
696
+ grouped.forEach((tagList, prefix2) => {
697
+ const hasMore = tagList.length > 5;
698
+ const displayTags = hasMore ? tagList.slice(-5) : tagList;
699
+ columns.push({ prefix: prefix2, tags: displayTags, hasMore });
700
+ });
701
+ const maxTagLength = Math.max(
702
+ ...columns.flatMap((col) => col.tags.map((t) => t.length))
703
+ );
704
+ const columnWidth = Math.max(maxTagLength + 4, 20);
705
+ const headers = columns.map((col) => {
706
+ const total = grouped.get(col.prefix).length;
707
+ const header = `${col.prefix} (${total})`;
708
+ return header.padEnd(columnWidth);
709
+ });
710
+ console.log(colors.cyan(" " + headers.join(" ")));
665
711
  console.log(
666
- colors.green(prefix ? `\u4EE5 '${prefix}' \u5F00\u5934\u7684 tags:` : "\u6240\u6709 tags:")
712
+ colors.dim(
713
+ " " + "\u2500".repeat(columnWidth * columns.length + (columns.length - 1) * 2)
714
+ )
667
715
  );
668
- tags.slice(0, 20).forEach((tag) => console.log(` ${tag}`));
669
- if (tags.length > 20) {
670
- console.log(colors.yellow(`
671
- \u5171 ${tags.length} \u4E2A\uFF0C\u4EC5\u663E\u793A\u524D 20 \u4E2A`));
716
+ const ellipsisRow = columns.map((col) => {
717
+ const text = col.hasMore ? "..." : "";
718
+ return text.padEnd(columnWidth);
719
+ }).join(" ");
720
+ if (columns.some((col) => col.hasMore)) {
721
+ console.log(colors.dim(" " + ellipsisRow));
722
+ }
723
+ const maxRows = Math.max(...columns.map((col) => col.tags.length));
724
+ for (let i = 0; i < maxRows; i++) {
725
+ const row = columns.map((col) => {
726
+ const tag = col.tags[i] || "";
727
+ return tag.padEnd(columnWidth);
728
+ }).join(" ");
729
+ console.log(" " + row);
672
730
  }
673
731
  }
674
732
  function getLatestTag(prefix) {
@@ -2438,7 +2496,7 @@ process.on("SIGTERM", () => {
2438
2496
  console.log("");
2439
2497
  process.exit(0);
2440
2498
  });
2441
- var version = true ? "0.2.22" : "0.0.0-dev";
2499
+ var version = true ? "0.2.23" : "0.0.0-dev";
2442
2500
  async function mainMenu() {
2443
2501
  console.log(
2444
2502
  colors.green(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zjex/git-workflow",
3
- "version": "0.2.22",
3
+ "version": "0.2.23",
4
4
  "description": "🚀 极简的 Git 工作流 CLI 工具,让分支管理和版本发布变得轻松愉快",
5
5
  "type": "module",
6
6
  "bin": {
@@ -4,16 +4,23 @@ import ora from "ora";
4
4
  import { colors, theme, exec, execOutput, divider } from "../utils.js";
5
5
  import { getConfig } from "../config.js";
6
6
 
7
+ /**
8
+ * 列出 tags(最新的显示在最下面,多个前缀分列展示)
9
+ * @param prefix 可选的 tag 前缀过滤
10
+ */
7
11
  export async function listTags(prefix?: string): Promise<void> {
12
+ // 1. 获取远程 tags
8
13
  const spinner = ora("正在获取 tags...").start();
9
14
  exec("git fetch --tags", true);
10
15
  spinner.stop();
11
16
 
17
+ // 2. 获取 tags 列表(按版本号升序排序,最新的在最后)
12
18
  const pattern = prefix ? `${prefix}*` : "";
13
- const tags = execOutput(`git tag -l ${pattern} --sort=-v:refname`)
19
+ const tags = execOutput(`git tag -l ${pattern} --sort=v:refname`)
14
20
  .split("\n")
15
21
  .filter(Boolean);
16
22
 
23
+ // 3. 如果没有 tags,提示并返回
17
24
  if (tags.length === 0) {
18
25
  console.log(
19
26
  colors.yellow(prefix ? `没有 '${prefix}' 开头的 tag` : "没有 tag")
@@ -21,13 +28,95 @@ export async function listTags(prefix?: string): Promise<void> {
21
28
  return;
22
29
  }
23
30
 
31
+ // 4. 如果指定了前缀,直接显示单列(最多 20 个)
32
+ if (prefix) {
33
+ console.log(colors.green(`以 '${prefix}' 开头的 tags:`));
34
+ const displayTags = tags.length > 20 ? tags.slice(-20) : tags;
35
+ displayTags.forEach((tag) => console.log(` ${tag}`));
36
+ if (tags.length > 20) {
37
+ console.log(colors.yellow(`\n共 ${tags.length} 个,仅显示最新 20 个`));
38
+ }
39
+ return;
40
+ }
41
+
42
+ // 5. 按前缀分组(提取 tag 名称中数字前的部分作为前缀)
43
+ const grouped = new Map<string, string[]>();
44
+ tags.forEach((tag) => {
45
+ // 提取前缀:去掉数字及之后的部分,如 "v0.1.0" -> "v"
46
+ const prefix = tag.replace(/[0-9].*/, "") || "无前缀";
47
+ if (!grouped.has(prefix)) {
48
+ grouped.set(prefix, []);
49
+ }
50
+ grouped.get(prefix)!.push(tag);
51
+ });
52
+
53
+ // 6. 如果只有一个前缀,使用单列显示(最多 20 个)
54
+ if (grouped.size === 1) {
55
+ console.log(colors.green("所有 tags:"));
56
+ const displayTags = tags.length > 20 ? tags.slice(-20) : tags;
57
+ displayTags.forEach((tag) => console.log(` ${tag}`));
58
+ if (tags.length > 20) {
59
+ console.log(colors.yellow(`\n共 ${tags.length} 个,仅显示最新 20 个`));
60
+ }
61
+ return;
62
+ }
63
+
64
+ // 7. 多个前缀,分列显示
65
+ console.log(colors.green("所有 tags (按前缀分组):"));
66
+ console.log("");
67
+
68
+ // 8. 准备每列的数据(每列最多显示 5 个最新的 tag)
69
+ const columns: Array<{ prefix: string; tags: string[]; hasMore: boolean }> =
70
+ [];
71
+ grouped.forEach((tagList, prefix) => {
72
+ const hasMore = tagList.length > 5;
73
+ // 取最后 5 个(最新的)
74
+ const displayTags = hasMore ? tagList.slice(-5) : tagList;
75
+ columns.push({ prefix, tags: displayTags, hasMore });
76
+ });
77
+
78
+ // 9. 计算每列的宽度(取所有 tag 中最长的,至少 20 字符)
79
+ const maxTagLength = Math.max(
80
+ ...columns.flatMap((col) => col.tags.map((t) => t.length))
81
+ );
82
+ const columnWidth = Math.max(maxTagLength + 4, 20);
83
+
84
+ // 10. 打印表头(显示前缀和总数)
85
+ const headers = columns.map((col) => {
86
+ const total = grouped.get(col.prefix)!.length;
87
+ const header = `${col.prefix} (${total})`;
88
+ return header.padEnd(columnWidth);
89
+ });
90
+ console.log(colors.cyan(" " + headers.join(" ")));
91
+
92
+ // 11. 打印分隔线
24
93
  console.log(
25
- colors.green(prefix ? `以 '${prefix}' 开头的 tags:` : "所有 tags:")
94
+ colors.dim(
95
+ " " + "─".repeat(columnWidth * columns.length + (columns.length - 1) * 2)
96
+ )
26
97
  );
27
- tags.slice(0, 20).forEach((tag) => console.log(` ${tag}`));
28
98
 
29
- if (tags.length > 20) {
30
- console.log(colors.yellow(`\n共 ${tags.length} 个,仅显示前 20 个`));
99
+ // 12. 打印省略号(如果某列有超过 5 个 tag)
100
+ const ellipsisRow = columns
101
+ .map((col) => {
102
+ const text = col.hasMore ? "..." : "";
103
+ return text.padEnd(columnWidth);
104
+ })
105
+ .join(" ");
106
+ if (columns.some((col) => col.hasMore)) {
107
+ console.log(colors.dim(" " + ellipsisRow));
108
+ }
109
+
110
+ // 13. 打印 tags 内容(按行打印,每行包含所有列的对应 tag)
111
+ const maxRows = Math.max(...columns.map((col) => col.tags.length));
112
+ for (let i = 0; i < maxRows; i++) {
113
+ const row = columns
114
+ .map((col) => {
115
+ const tag = col.tags[i] || ""; // 如果该列没有这一行,填充空字符串
116
+ return tag.padEnd(columnWidth);
117
+ })
118
+ .join(" ");
119
+ console.log(" " + row);
31
120
  }
32
121
  }
33
122