@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 +65 -7
- package/package.json +1 -1
- package/src/commands/tag.ts +94 -5
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
|
|
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.
|
|
712
|
+
colors.dim(
|
|
713
|
+
" " + "\u2500".repeat(columnWidth * columns.length + (columns.length - 1) * 2)
|
|
714
|
+
)
|
|
667
715
|
);
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
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.
|
|
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
package/src/commands/tag.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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
|
-
|
|
30
|
-
|
|
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
|
|