@zjex/git-workflow 0.3.9 → 0.4.0
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 +1 -1
- package/TEST_COVERAGE_SUMMARY.md +264 -0
- package/dist/index.js +160 -11
- package/docs/commands/branch.md +33 -12
- package/docs/commands/index.md +38 -33
- package/docs/commands/tag.md +71 -15
- package/docs/commands/update.md +79 -3
- package/package.json +1 -1
- package/src/ai-service.ts +66 -33
- package/src/commands/tag.ts +120 -0
- package/src/index.ts +97 -16
- package/src/update-notifier.ts +1 -1
- package/tests/clean.test.ts +293 -0
- package/tests/commands.test.ts +409 -0
- package/tests/tag.test.ts +236 -0
- package/tests/update-notifier.test.ts +52 -0
- package/tests/COVERAGE_REPORT.md +0 -222
- package/tests/QUICK_START.md +0 -242
- package/tests/TEST_SUMMARY.md +0 -330
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { existsSync, unlinkSync, readdirSync, writeFileSync } from "fs";
|
|
3
|
+
import { homedir, tmpdir } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
|
|
6
|
+
// Mock 所有外部依赖
|
|
7
|
+
vi.mock("fs", () => ({
|
|
8
|
+
existsSync: vi.fn(),
|
|
9
|
+
unlinkSync: vi.fn(),
|
|
10
|
+
readdirSync: vi.fn(),
|
|
11
|
+
writeFileSync: vi.fn(),
|
|
12
|
+
readFileSync: vi.fn(),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
vi.mock("os", () => ({
|
|
16
|
+
homedir: vi.fn(),
|
|
17
|
+
tmpdir: vi.fn(),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
vi.mock("path", () => ({
|
|
21
|
+
join: vi.fn((...args) => args.join("/")),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
vi.mock("@inquirer/prompts", () => ({
|
|
25
|
+
select: vi.fn(),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
vi.mock("../src/update-notifier.js", () => ({
|
|
29
|
+
clearUpdateCache: vi.fn(),
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
describe("Clean 命令测试", () => {
|
|
33
|
+
const mockExistsSync = vi.mocked(existsSync);
|
|
34
|
+
const mockUnlinkSync = vi.mocked(unlinkSync);
|
|
35
|
+
const mockReaddirSync = vi.mocked(readdirSync);
|
|
36
|
+
const mockHomedir = vi.mocked(homedir);
|
|
37
|
+
const mockTmpdir = vi.mocked(tmpdir);
|
|
38
|
+
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
vi.clearAllMocks();
|
|
41
|
+
mockHomedir.mockReturnValue("/home/user");
|
|
42
|
+
mockTmpdir.mockReturnValue("/tmp");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
vi.restoreAllMocks();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe("清理更新缓存", () => {
|
|
50
|
+
it("应该清理更新缓存文件", async () => {
|
|
51
|
+
const { clearUpdateCache } = await import("../src/update-notifier.js");
|
|
52
|
+
|
|
53
|
+
clearUpdateCache();
|
|
54
|
+
|
|
55
|
+
expect(clearUpdateCache).toHaveBeenCalled();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("清理全局配置文件", () => {
|
|
60
|
+
it("没有全局配置文件时不应该询问", async () => {
|
|
61
|
+
mockExistsSync.mockReturnValue(false);
|
|
62
|
+
mockReaddirSync.mockReturnValue([]);
|
|
63
|
+
|
|
64
|
+
const { select } = await import("@inquirer/prompts");
|
|
65
|
+
|
|
66
|
+
expect(mockExistsSync).not.toHaveBeenCalledWith("/home/user/.gwrc.json");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("有全局配置文件时应该询问是否删除", async () => {
|
|
70
|
+
const globalConfig = "/home/user/.gwrc.json";
|
|
71
|
+
mockExistsSync.mockReturnValue(true);
|
|
72
|
+
mockReaddirSync.mockReturnValue([]);
|
|
73
|
+
|
|
74
|
+
const { select } = await import("@inquirer/prompts");
|
|
75
|
+
vi.mocked(select).mockResolvedValue(false);
|
|
76
|
+
|
|
77
|
+
// 模拟检查全局配置文件
|
|
78
|
+
const hasGlobalConfig = mockExistsSync(globalConfig);
|
|
79
|
+
|
|
80
|
+
expect(hasGlobalConfig).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("选择删除时应该删除全局配置文件", async () => {
|
|
84
|
+
const globalConfig = "/home/user/.gwrc.json";
|
|
85
|
+
mockExistsSync.mockReturnValue(true);
|
|
86
|
+
mockReaddirSync.mockReturnValue([]);
|
|
87
|
+
|
|
88
|
+
const { select } = await import("@inquirer/prompts");
|
|
89
|
+
vi.mocked(select).mockResolvedValue(true);
|
|
90
|
+
|
|
91
|
+
// 模拟删除操作
|
|
92
|
+
if (mockExistsSync(globalConfig)) {
|
|
93
|
+
mockUnlinkSync(globalConfig);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
expect(mockUnlinkSync).toHaveBeenCalledWith(globalConfig);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("选择不删除时应该保留全局配置文件", async () => {
|
|
100
|
+
const globalConfig = "/home/user/.gwrc.json";
|
|
101
|
+
mockExistsSync.mockReturnValue(true);
|
|
102
|
+
mockReaddirSync.mockReturnValue([]);
|
|
103
|
+
|
|
104
|
+
const { select } = await import("@inquirer/prompts");
|
|
105
|
+
vi.mocked(select).mockResolvedValue(false);
|
|
106
|
+
|
|
107
|
+
// 模拟不删除的情况
|
|
108
|
+
const shouldDelete = await vi.mocked(select)();
|
|
109
|
+
|
|
110
|
+
if (!shouldDelete) {
|
|
111
|
+
expect(mockUnlinkSync).not.toHaveBeenCalledWith(globalConfig);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe("清理临时 commit 文件", () => {
|
|
117
|
+
it("应该清理所有临时 commit 文件", () => {
|
|
118
|
+
mockReaddirSync.mockReturnValue([
|
|
119
|
+
".gw-commit-msg-123456",
|
|
120
|
+
".gw-commit-msg-789012",
|
|
121
|
+
"other-file.txt",
|
|
122
|
+
] as any);
|
|
123
|
+
|
|
124
|
+
const tmpDir = mockTmpdir();
|
|
125
|
+
const files = mockReaddirSync(tmpDir);
|
|
126
|
+
const gwTmpFiles = files.filter((f: string) =>
|
|
127
|
+
f.startsWith(".gw-commit-msg-")
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
expect(gwTmpFiles).toHaveLength(2);
|
|
131
|
+
expect(gwTmpFiles).toContain(".gw-commit-msg-123456");
|
|
132
|
+
expect(gwTmpFiles).toContain(".gw-commit-msg-789012");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("应该忽略非 gw 临时文件", () => {
|
|
136
|
+
mockReaddirSync.mockReturnValue([
|
|
137
|
+
".gw-commit-msg-123456",
|
|
138
|
+
"other-temp-file",
|
|
139
|
+
".other-file",
|
|
140
|
+
] as any);
|
|
141
|
+
|
|
142
|
+
const tmpDir = mockTmpdir();
|
|
143
|
+
const files = mockReaddirSync(tmpDir);
|
|
144
|
+
const gwTmpFiles = files.filter((f: string) =>
|
|
145
|
+
f.startsWith(".gw-commit-msg-")
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
expect(gwTmpFiles).toHaveLength(1);
|
|
149
|
+
expect(gwTmpFiles).toContain(".gw-commit-msg-123456");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("没有临时文件时不应该报错", () => {
|
|
153
|
+
mockReaddirSync.mockReturnValue([]);
|
|
154
|
+
|
|
155
|
+
const tmpDir = mockTmpdir();
|
|
156
|
+
const files = mockReaddirSync(tmpDir);
|
|
157
|
+
const gwTmpFiles = files.filter((f: string) =>
|
|
158
|
+
f.startsWith(".gw-commit-msg-")
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
expect(gwTmpFiles).toHaveLength(0);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("应该删除找到的临时文件", () => {
|
|
165
|
+
mockReaddirSync.mockReturnValue([
|
|
166
|
+
".gw-commit-msg-123456",
|
|
167
|
+
".gw-commit-msg-789012",
|
|
168
|
+
] as any);
|
|
169
|
+
|
|
170
|
+
const tmpDir = mockTmpdir();
|
|
171
|
+
const files = mockReaddirSync(tmpDir);
|
|
172
|
+
const gwTmpFiles = files.filter((f: string) =>
|
|
173
|
+
f.startsWith(".gw-commit-msg-")
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
gwTmpFiles.forEach((file: string) => {
|
|
177
|
+
mockUnlinkSync(join(tmpDir, file));
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
expect(mockUnlinkSync).toHaveBeenCalledTimes(2);
|
|
181
|
+
expect(mockUnlinkSync).toHaveBeenCalledWith("/tmp/.gw-commit-msg-123456");
|
|
182
|
+
expect(mockUnlinkSync).toHaveBeenCalledWith("/tmp/.gw-commit-msg-789012");
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe("清理统计", () => {
|
|
187
|
+
it("应该正确统计清理的文件数量", () => {
|
|
188
|
+
let cleanedCount = 0;
|
|
189
|
+
|
|
190
|
+
// 清理更新缓存
|
|
191
|
+
cleanedCount++;
|
|
192
|
+
|
|
193
|
+
// 清理全局配置
|
|
194
|
+
mockExistsSync.mockReturnValue(true);
|
|
195
|
+
if (mockExistsSync("/home/user/.gwrc.json")) {
|
|
196
|
+
cleanedCount++;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// 清理临时文件
|
|
200
|
+
mockReaddirSync.mockReturnValue([
|
|
201
|
+
".gw-commit-msg-123456",
|
|
202
|
+
".gw-commit-msg-789012",
|
|
203
|
+
] as any);
|
|
204
|
+
const gwTmpFiles = mockReaddirSync("/tmp").filter((f: string) =>
|
|
205
|
+
f.startsWith(".gw-commit-msg-")
|
|
206
|
+
);
|
|
207
|
+
cleanedCount += gwTmpFiles.length;
|
|
208
|
+
|
|
209
|
+
expect(cleanedCount).toBe(4); // 1 缓存 + 1 配置 + 2 临时文件
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("没有全局配置时应该统计正确", () => {
|
|
213
|
+
let cleanedCount = 0;
|
|
214
|
+
|
|
215
|
+
// 清理更新缓存
|
|
216
|
+
cleanedCount++;
|
|
217
|
+
|
|
218
|
+
// 没有全局配置
|
|
219
|
+
mockExistsSync.mockReturnValue(false);
|
|
220
|
+
|
|
221
|
+
// 清理临时文件
|
|
222
|
+
mockReaddirSync.mockReturnValue([".gw-commit-msg-123456"] as any);
|
|
223
|
+
const gwTmpFiles = mockReaddirSync("/tmp").filter((f: string) =>
|
|
224
|
+
f.startsWith(".gw-commit-msg-")
|
|
225
|
+
);
|
|
226
|
+
cleanedCount += gwTmpFiles.length;
|
|
227
|
+
|
|
228
|
+
expect(cleanedCount).toBe(2); // 1 缓存 + 1 临时文件
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("没有任何文件时应该只清理缓存", () => {
|
|
232
|
+
let cleanedCount = 0;
|
|
233
|
+
|
|
234
|
+
// 清理更新缓存
|
|
235
|
+
cleanedCount++;
|
|
236
|
+
|
|
237
|
+
// 没有全局配置
|
|
238
|
+
mockExistsSync.mockReturnValue(false);
|
|
239
|
+
|
|
240
|
+
// 没有临时文件
|
|
241
|
+
mockReaddirSync.mockReturnValue([]);
|
|
242
|
+
|
|
243
|
+
expect(cleanedCount).toBe(1); // 只有缓存
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe("错误处理", () => {
|
|
248
|
+
it("删除文件失败时应该静默处理", () => {
|
|
249
|
+
mockUnlinkSync.mockImplementation(() => {
|
|
250
|
+
throw new Error("Permission denied");
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
expect(() => {
|
|
254
|
+
try {
|
|
255
|
+
mockUnlinkSync("/home/user/.gwrc.json");
|
|
256
|
+
} catch {
|
|
257
|
+
// 静默失败
|
|
258
|
+
}
|
|
259
|
+
}).not.toThrow();
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it("读取目录失败时应该静默处理", () => {
|
|
263
|
+
mockReaddirSync.mockImplementation(() => {
|
|
264
|
+
throw new Error("Directory not found");
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(() => {
|
|
268
|
+
try {
|
|
269
|
+
mockReaddirSync("/tmp");
|
|
270
|
+
} catch {
|
|
271
|
+
// 静默失败
|
|
272
|
+
}
|
|
273
|
+
}).not.toThrow();
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe("文件路径", () => {
|
|
278
|
+
it("应该使用正确的全局配置路径", () => {
|
|
279
|
+
const globalConfig = join(mockHomedir(), ".gwrc.json");
|
|
280
|
+
expect(globalConfig).toBe("/home/user/.gwrc.json");
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("应该使用正确的临时目录路径", () => {
|
|
284
|
+
const tmpDir = mockTmpdir();
|
|
285
|
+
expect(tmpDir).toBe("/tmp");
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it("应该正确拼接临时文件路径", () => {
|
|
289
|
+
const tmpFile = join(mockTmpdir(), ".gw-commit-msg-123456");
|
|
290
|
+
expect(tmpFile).toBe("/tmp/.gw-commit-msg-123456");
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
});
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
|
|
3
|
+
describe("命令别名测试", () => {
|
|
4
|
+
describe("分支命令", () => {
|
|
5
|
+
it("应该支持 feature 命令及其别名", () => {
|
|
6
|
+
const commands = ["feature", "feat", "f"];
|
|
7
|
+
const expectedCommand = "feature";
|
|
8
|
+
|
|
9
|
+
commands.forEach((cmd) => {
|
|
10
|
+
// 验证命令映射
|
|
11
|
+
const isValid = cmd === "feature" || cmd === "feat" || cmd === "f";
|
|
12
|
+
expect(isValid).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("应该支持 hotfix 命令及其别名", () => {
|
|
17
|
+
const commands = ["hotfix", "fix", "h"];
|
|
18
|
+
const expectedCommand = "hotfix";
|
|
19
|
+
|
|
20
|
+
commands.forEach((cmd) => {
|
|
21
|
+
const isValid = cmd === "hotfix" || cmd === "fix" || cmd === "h";
|
|
22
|
+
expect(isValid).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("应该支持 br:del 命令及其别名", () => {
|
|
27
|
+
const commands = ["br:del", "brd"];
|
|
28
|
+
const expectedCommand = "br:del";
|
|
29
|
+
|
|
30
|
+
commands.forEach((cmd) => {
|
|
31
|
+
const isValid = cmd === "br:del" || cmd === "brd";
|
|
32
|
+
expect(isValid).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("br:del 命令应该替代旧的 delete 命令", () => {
|
|
37
|
+
const newCommands = ["br:del", "brd"];
|
|
38
|
+
const oldCommands = ["delete", "del", "d"];
|
|
39
|
+
|
|
40
|
+
// 新命令应该存在
|
|
41
|
+
expect(newCommands.length).toBeGreaterThan(0);
|
|
42
|
+
|
|
43
|
+
// 验证新命令格式
|
|
44
|
+
expect(newCommands[0]).toBe("br:del");
|
|
45
|
+
expect(newCommands[1]).toBe("brd");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe("Tag 命令", () => {
|
|
50
|
+
it("应该支持 tag 命令及其别名", () => {
|
|
51
|
+
const commands = ["tag", "t"];
|
|
52
|
+
|
|
53
|
+
commands.forEach((cmd) => {
|
|
54
|
+
const isValid = cmd === "tag" || cmd === "t";
|
|
55
|
+
expect(isValid).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("应该支持 tags 命令及其别名", () => {
|
|
60
|
+
const commands = ["tags", "ts"];
|
|
61
|
+
|
|
62
|
+
commands.forEach((cmd) => {
|
|
63
|
+
const isValid = cmd === "tags" || cmd === "ts";
|
|
64
|
+
expect(isValid).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("应该支持 tag:del 命令及其别名", () => {
|
|
69
|
+
const commands = ["tag:del", "td"];
|
|
70
|
+
|
|
71
|
+
commands.forEach((cmd) => {
|
|
72
|
+
const isValid = cmd === "tag:del" || cmd === "td";
|
|
73
|
+
expect(isValid).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("应该支持 tag:update 命令及其别名", () => {
|
|
78
|
+
const commands = ["tag:update", "tu"];
|
|
79
|
+
|
|
80
|
+
commands.forEach((cmd) => {
|
|
81
|
+
const isValid = cmd === "tag:update" || cmd === "tu";
|
|
82
|
+
expect(isValid).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("应该支持 tag:clean 命令及其别名", () => {
|
|
87
|
+
const commands = ["tag:clean", "tc"];
|
|
88
|
+
|
|
89
|
+
commands.forEach((cmd) => {
|
|
90
|
+
const isValid = cmd === "tag:clean" || cmd === "tc";
|
|
91
|
+
expect(isValid).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("提交命令", () => {
|
|
97
|
+
it("应该支持 commit 命令及其别名", () => {
|
|
98
|
+
const commands = ["commit", "c", "cm"];
|
|
99
|
+
|
|
100
|
+
commands.forEach((cmd) => {
|
|
101
|
+
const isValid = cmd === "commit" || cmd === "c" || cmd === "cm";
|
|
102
|
+
expect(isValid).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe("Stash 命令", () => {
|
|
108
|
+
it("应该支持 stash 命令及其别名", () => {
|
|
109
|
+
const commands = ["stash", "s", "st"];
|
|
110
|
+
|
|
111
|
+
commands.forEach((cmd) => {
|
|
112
|
+
const isValid = cmd === "stash" || cmd === "s" || cmd === "st";
|
|
113
|
+
expect(isValid).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe("日志命令", () => {
|
|
119
|
+
it("应该支持 log 命令及其别名", () => {
|
|
120
|
+
const commands = ["log", "ls", "l"];
|
|
121
|
+
|
|
122
|
+
commands.forEach((cmd) => {
|
|
123
|
+
const isValid = cmd === "log" || cmd === "ls" || cmd === "l";
|
|
124
|
+
expect(isValid).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("版本命令", () => {
|
|
130
|
+
it("应该支持 release 命令及其别名", () => {
|
|
131
|
+
const commands = ["release", "r"];
|
|
132
|
+
|
|
133
|
+
commands.forEach((cmd) => {
|
|
134
|
+
const isValid = cmd === "release" || cmd === "r";
|
|
135
|
+
expect(isValid).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe("更新命令", () => {
|
|
141
|
+
it("应该支持 update 命令及其别名", () => {
|
|
142
|
+
const commands = ["update", "upt"];
|
|
143
|
+
|
|
144
|
+
commands.forEach((cmd) => {
|
|
145
|
+
const isValid = cmd === "update" || cmd === "upt";
|
|
146
|
+
expect(isValid).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("清理命令", () => {
|
|
152
|
+
it("应该支持 clean 命令及其别名", () => {
|
|
153
|
+
const commands = ["clean", "cc"];
|
|
154
|
+
|
|
155
|
+
commands.forEach((cmd) => {
|
|
156
|
+
const isValid = cmd === "clean" || cmd === "cc";
|
|
157
|
+
expect(isValid).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("初始化命令", () => {
|
|
163
|
+
it("应该支持 init 命令", () => {
|
|
164
|
+
const command = "init";
|
|
165
|
+
expect(command).toBe("init");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("init 命令不应该有别名", () => {
|
|
169
|
+
const aliases: string[] = [];
|
|
170
|
+
expect(aliases.length).toBe(0);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe("命令命名规范", () => {
|
|
175
|
+
it("分支删除命令应该使用 br:del 格式", () => {
|
|
176
|
+
const command = "br:del";
|
|
177
|
+
expect(command).toMatch(/^br:del$/);
|
|
178
|
+
expect(command).toContain(":");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("tag 删除命令应该使用 tag:del 格式", () => {
|
|
182
|
+
const command = "tag:del";
|
|
183
|
+
expect(command).toMatch(/^tag:del$/);
|
|
184
|
+
expect(command).toContain(":");
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("tag 更新命令应该使用 tag:update 格式", () => {
|
|
188
|
+
const command = "tag:update";
|
|
189
|
+
expect(command).toMatch(/^tag:update$/);
|
|
190
|
+
expect(command).toContain(":");
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("tag 清理命令应该使用 tag:clean 格式", () => {
|
|
194
|
+
const command = "tag:clean";
|
|
195
|
+
expect(command).toMatch(/^tag:clean$/);
|
|
196
|
+
expect(command).toContain(":");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("子命令应该使用冒号分隔", () => {
|
|
200
|
+
const subCommands = ["br:del", "tag:del", "tag:update", "tag:clean"];
|
|
201
|
+
|
|
202
|
+
subCommands.forEach((cmd) => {
|
|
203
|
+
expect(cmd).toContain(":");
|
|
204
|
+
const parts = cmd.split(":");
|
|
205
|
+
expect(parts.length).toBe(2);
|
|
206
|
+
expect(parts[0].length).toBeGreaterThan(0);
|
|
207
|
+
expect(parts[1].length).toBeGreaterThan(0);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe("别名简洁性", () => {
|
|
213
|
+
it("所有别名应该不超过 4 个字符", () => {
|
|
214
|
+
const aliases = [
|
|
215
|
+
"f",
|
|
216
|
+
"feat",
|
|
217
|
+
"h",
|
|
218
|
+
"fix",
|
|
219
|
+
"brd",
|
|
220
|
+
"t",
|
|
221
|
+
"ts",
|
|
222
|
+
"td",
|
|
223
|
+
"tu",
|
|
224
|
+
"tc",
|
|
225
|
+
"c",
|
|
226
|
+
"cm",
|
|
227
|
+
"s",
|
|
228
|
+
"st",
|
|
229
|
+
"l",
|
|
230
|
+
"ls",
|
|
231
|
+
"r",
|
|
232
|
+
"upt",
|
|
233
|
+
"cc",
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
aliases.forEach((alias) => {
|
|
237
|
+
expect(alias.length).toBeLessThanOrEqual(4);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("单字母别名应该是最常用的命令", () => {
|
|
242
|
+
const singleLetterAliases = {
|
|
243
|
+
f: "feature",
|
|
244
|
+
h: "hotfix",
|
|
245
|
+
t: "tag",
|
|
246
|
+
c: "commit",
|
|
247
|
+
s: "stash",
|
|
248
|
+
l: "log",
|
|
249
|
+
r: "release",
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
Object.entries(singleLetterAliases).forEach(([alias, command]) => {
|
|
253
|
+
expect(alias.length).toBe(1);
|
|
254
|
+
expect(command.length).toBeGreaterThan(1);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("两字母别名应该是次常用的命令", () => {
|
|
259
|
+
const twoLetterAliases = {
|
|
260
|
+
ts: "tags",
|
|
261
|
+
td: "tag:del",
|
|
262
|
+
tu: "tag:update",
|
|
263
|
+
tc: "tag:clean",
|
|
264
|
+
cm: "commit",
|
|
265
|
+
st: "stash",
|
|
266
|
+
ls: "log",
|
|
267
|
+
cc: "clean",
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
Object.entries(twoLetterAliases).forEach(([alias, command]) => {
|
|
271
|
+
expect(alias.length).toBe(2);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("三字母别名应该是较少使用的命令", () => {
|
|
276
|
+
const threeLetterAliases = {
|
|
277
|
+
brd: "br:del",
|
|
278
|
+
upt: "update",
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
Object.entries(threeLetterAliases).forEach(([alias, command]) => {
|
|
282
|
+
expect(alias.length).toBe(3);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("四字母别名应该是完整单词缩写", () => {
|
|
287
|
+
const fourLetterAliases = {
|
|
288
|
+
feat: "feature",
|
|
289
|
+
fix: "hotfix",
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
Object.entries(fourLetterAliases).forEach(([alias, command]) => {
|
|
293
|
+
expect(alias.length).toBeGreaterThanOrEqual(3);
|
|
294
|
+
expect(alias.length).toBeLessThanOrEqual(4);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
describe("命令一致性", () => {
|
|
300
|
+
it("删除操作应该使用统一的 del 后缀", () => {
|
|
301
|
+
const deleteCommands = ["br:del", "tag:del"];
|
|
302
|
+
|
|
303
|
+
deleteCommands.forEach((cmd) => {
|
|
304
|
+
expect(cmd).toMatch(/del$/);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it("删除操作的别名应该以 d 结尾", () => {
|
|
309
|
+
const deleteAliases = ["brd", "td"];
|
|
310
|
+
|
|
311
|
+
deleteAliases.forEach((alias) => {
|
|
312
|
+
expect(alias).toMatch(/d$/);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it("清理操作应该使用 clean 命名", () => {
|
|
317
|
+
const cleanCommands = ["clean", "tag:clean"];
|
|
318
|
+
|
|
319
|
+
cleanCommands.forEach((cmd) => {
|
|
320
|
+
expect(cmd).toContain("clean");
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("清理操作的别名应该以 c 结尾", () => {
|
|
325
|
+
const cleanAliases = ["cc", "tc"];
|
|
326
|
+
|
|
327
|
+
cleanAliases.forEach((alias) => {
|
|
328
|
+
expect(alias).toMatch(/c$/);
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
describe("命令分组", () => {
|
|
334
|
+
it("应该有分支管理命令组", () => {
|
|
335
|
+
const branchCommands = ["feature", "hotfix", "br:del"];
|
|
336
|
+
expect(branchCommands.length).toBe(3);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("应该有 tag 管理命令组", () => {
|
|
340
|
+
const tagCommands = ["tag", "tags", "tag:del", "tag:update", "tag:clean"];
|
|
341
|
+
expect(tagCommands.length).toBe(5);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("应该有提交管理命令组", () => {
|
|
345
|
+
const commitCommands = ["commit", "log"];
|
|
346
|
+
expect(commitCommands.length).toBe(2);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("应该有工具管理命令组", () => {
|
|
350
|
+
const toolCommands = ["init", "update", "clean"];
|
|
351
|
+
expect(toolCommands.length).toBe(3);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("应该有其他辅助命令组", () => {
|
|
355
|
+
const otherCommands = ["stash", "release"];
|
|
356
|
+
expect(otherCommands.length).toBe(2);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
describe("命令总数统计", () => {
|
|
361
|
+
it("应该有正确数量的主命令", () => {
|
|
362
|
+
const mainCommands = [
|
|
363
|
+
"feature",
|
|
364
|
+
"hotfix",
|
|
365
|
+
"br:del",
|
|
366
|
+
"tag",
|
|
367
|
+
"tags",
|
|
368
|
+
"tag:del",
|
|
369
|
+
"tag:update",
|
|
370
|
+
"tag:clean",
|
|
371
|
+
"commit",
|
|
372
|
+
"log",
|
|
373
|
+
"stash",
|
|
374
|
+
"release",
|
|
375
|
+
"init",
|
|
376
|
+
"update",
|
|
377
|
+
"clean",
|
|
378
|
+
];
|
|
379
|
+
|
|
380
|
+
expect(mainCommands.length).toBe(15);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it("应该有正确数量的别名", () => {
|
|
384
|
+
const aliases = [
|
|
385
|
+
"f",
|
|
386
|
+
"feat",
|
|
387
|
+
"h",
|
|
388
|
+
"fix",
|
|
389
|
+
"brd",
|
|
390
|
+
"t",
|
|
391
|
+
"ts",
|
|
392
|
+
"td",
|
|
393
|
+
"tu",
|
|
394
|
+
"tc",
|
|
395
|
+
"c",
|
|
396
|
+
"cm",
|
|
397
|
+
"l",
|
|
398
|
+
"ls",
|
|
399
|
+
"s",
|
|
400
|
+
"st",
|
|
401
|
+
"r",
|
|
402
|
+
"upt",
|
|
403
|
+
"cc",
|
|
404
|
+
];
|
|
405
|
+
|
|
406
|
+
expect(aliases.length).toBe(19);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|