@zjex/git-workflow 0.3.8 → 0.3.10
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/dist/index.js +89 -9
- package/package.json +1 -1
- package/src/ai-service.ts +66 -33
- package/src/commands/branch.ts +22 -5
- package/src/commands/init.ts +39 -15
- package/src/config.ts +4 -0
- package/src/index.ts +66 -2
- package/src/update-notifier.ts +1 -2
- package/tests/branch.test.ts +116 -0
- package/tests/clean.test.ts +293 -0
- package/tests/commit.test.ts +186 -1
- package/tests/init.test.ts +240 -297
- package/tests/COVERAGE_REPORT.md +0 -222
- package/tests/QUICK_START.md +0 -242
- package/tests/TEST_SUMMARY.md +0 -330
package/tests/init.test.ts
CHANGED
|
@@ -43,8 +43,6 @@ describe("Init 模块测试", () => {
|
|
|
43
43
|
beforeEach(() => {
|
|
44
44
|
vi.clearAllMocks();
|
|
45
45
|
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
46
|
-
|
|
47
|
-
// Default mocks
|
|
48
46
|
mockHomedir.mockReturnValue("/home/user");
|
|
49
47
|
mockJoin.mockReturnValue("/home/user/.gwrc.json");
|
|
50
48
|
});
|
|
@@ -56,28 +54,25 @@ describe("Init 模块测试", () => {
|
|
|
56
54
|
describe("配置范围选择", () => {
|
|
57
55
|
it("应该支持全局配置", async () => {
|
|
58
56
|
mockExistsSync.mockReturnValue(false);
|
|
59
|
-
|
|
60
57
|
const { select, input } = await import("@inquirer/prompts");
|
|
61
58
|
vi.mocked(select)
|
|
62
|
-
.mockResolvedValueOnce("global")
|
|
63
|
-
.mockResolvedValueOnce(false)
|
|
64
|
-
.mockResolvedValueOnce(
|
|
65
|
-
.mockResolvedValueOnce(
|
|
66
|
-
.mockResolvedValueOnce(
|
|
67
|
-
.mockResolvedValueOnce(
|
|
68
|
-
|
|
59
|
+
.mockResolvedValueOnce("global")
|
|
60
|
+
.mockResolvedValueOnce(false)
|
|
61
|
+
.mockResolvedValueOnce(false)
|
|
62
|
+
.mockResolvedValueOnce(false)
|
|
63
|
+
.mockResolvedValueOnce("ask")
|
|
64
|
+
.mockResolvedValueOnce(true)
|
|
65
|
+
.mockResolvedValueOnce(true)
|
|
66
|
+
.mockResolvedValueOnce(false);
|
|
69
67
|
vi.mocked(input)
|
|
70
|
-
.mockResolvedValueOnce("")
|
|
71
|
-
.mockResolvedValueOnce("feature")
|
|
72
|
-
.mockResolvedValueOnce("hotfix")
|
|
73
|
-
.mockResolvedValueOnce("Story ID")
|
|
74
|
-
.mockResolvedValueOnce("Issue ID")
|
|
75
|
-
.mockResolvedValueOnce("");
|
|
76
|
-
|
|
68
|
+
.mockResolvedValueOnce("")
|
|
69
|
+
.mockResolvedValueOnce("feature")
|
|
70
|
+
.mockResolvedValueOnce("hotfix")
|
|
71
|
+
.mockResolvedValueOnce("Story ID")
|
|
72
|
+
.mockResolvedValueOnce("Issue ID")
|
|
73
|
+
.mockResolvedValueOnce("");
|
|
77
74
|
const { init } = await import("../src/commands/init.js");
|
|
78
|
-
|
|
79
75
|
await init();
|
|
80
|
-
|
|
81
76
|
expect(mockJoin).toHaveBeenCalledWith("/home/user", ".gwrc.json");
|
|
82
77
|
expect(mockWriteFileSync).toHaveBeenCalledWith(
|
|
83
78
|
"/home/user/.gwrc.json",
|
|
@@ -87,28 +82,25 @@ describe("Init 模块测试", () => {
|
|
|
87
82
|
|
|
88
83
|
it("应该支持项目配置", async () => {
|
|
89
84
|
mockExistsSync.mockReturnValue(false);
|
|
90
|
-
|
|
91
85
|
const { select, input } = await import("@inquirer/prompts");
|
|
92
86
|
vi.mocked(select)
|
|
93
|
-
.mockResolvedValueOnce("project")
|
|
94
|
-
.mockResolvedValueOnce(false)
|
|
95
|
-
.mockResolvedValueOnce(
|
|
96
|
-
.mockResolvedValueOnce(
|
|
97
|
-
.mockResolvedValueOnce(
|
|
98
|
-
.mockResolvedValueOnce(
|
|
99
|
-
|
|
87
|
+
.mockResolvedValueOnce("project")
|
|
88
|
+
.mockResolvedValueOnce(false)
|
|
89
|
+
.mockResolvedValueOnce(false)
|
|
90
|
+
.mockResolvedValueOnce(false)
|
|
91
|
+
.mockResolvedValueOnce("ask")
|
|
92
|
+
.mockResolvedValueOnce(true)
|
|
93
|
+
.mockResolvedValueOnce(true)
|
|
94
|
+
.mockResolvedValueOnce(false);
|
|
100
95
|
vi.mocked(input)
|
|
101
|
-
.mockResolvedValueOnce("")
|
|
102
|
-
.mockResolvedValueOnce("feature")
|
|
103
|
-
.mockResolvedValueOnce("hotfix")
|
|
104
|
-
.mockResolvedValueOnce("Story ID")
|
|
105
|
-
.mockResolvedValueOnce("Issue ID")
|
|
106
|
-
.mockResolvedValueOnce("");
|
|
107
|
-
|
|
96
|
+
.mockResolvedValueOnce("")
|
|
97
|
+
.mockResolvedValueOnce("feature")
|
|
98
|
+
.mockResolvedValueOnce("hotfix")
|
|
99
|
+
.mockResolvedValueOnce("Story ID")
|
|
100
|
+
.mockResolvedValueOnce("Issue ID")
|
|
101
|
+
.mockResolvedValueOnce("");
|
|
108
102
|
const { init } = await import("../src/commands/init.js");
|
|
109
|
-
|
|
110
103
|
await init();
|
|
111
|
-
|
|
112
104
|
expect(mockWriteFileSync).toHaveBeenCalledWith(
|
|
113
105
|
".gwrc.json",
|
|
114
106
|
expect.stringContaining('"featurePrefix": "feature"')
|
|
@@ -119,44 +111,37 @@ describe("Init 模块测试", () => {
|
|
|
119
111
|
describe("配置文件覆盖", () => {
|
|
120
112
|
it("应该处理配置文件已存在的情况", async () => {
|
|
121
113
|
mockExistsSync.mockReturnValue(true);
|
|
122
|
-
|
|
123
114
|
const { select, input } = await import("@inquirer/prompts");
|
|
124
115
|
vi.mocked(select)
|
|
125
|
-
.mockResolvedValueOnce("global")
|
|
126
|
-
.mockResolvedValueOnce(true)
|
|
127
|
-
.mockResolvedValueOnce(false)
|
|
128
|
-
.mockResolvedValueOnce(
|
|
129
|
-
.mockResolvedValueOnce(
|
|
130
|
-
.mockResolvedValueOnce(
|
|
131
|
-
.mockResolvedValueOnce(
|
|
132
|
-
|
|
116
|
+
.mockResolvedValueOnce("global")
|
|
117
|
+
.mockResolvedValueOnce(true)
|
|
118
|
+
.mockResolvedValueOnce(false)
|
|
119
|
+
.mockResolvedValueOnce(false)
|
|
120
|
+
.mockResolvedValueOnce(false)
|
|
121
|
+
.mockResolvedValueOnce("ask")
|
|
122
|
+
.mockResolvedValueOnce(true)
|
|
123
|
+
.mockResolvedValueOnce(true)
|
|
124
|
+
.mockResolvedValueOnce(false);
|
|
133
125
|
vi.mocked(input)
|
|
134
|
-
.mockResolvedValueOnce("")
|
|
135
|
-
.mockResolvedValueOnce("feature")
|
|
136
|
-
.mockResolvedValueOnce("hotfix")
|
|
137
|
-
.mockResolvedValueOnce("Story ID")
|
|
138
|
-
.mockResolvedValueOnce("Issue ID")
|
|
139
|
-
.mockResolvedValueOnce("");
|
|
140
|
-
|
|
126
|
+
.mockResolvedValueOnce("")
|
|
127
|
+
.mockResolvedValueOnce("feature")
|
|
128
|
+
.mockResolvedValueOnce("hotfix")
|
|
129
|
+
.mockResolvedValueOnce("Story ID")
|
|
130
|
+
.mockResolvedValueOnce("Issue ID")
|
|
131
|
+
.mockResolvedValueOnce("");
|
|
141
132
|
const { init } = await import("../src/commands/init.js");
|
|
142
|
-
|
|
143
133
|
await init();
|
|
144
|
-
|
|
145
134
|
expect(mockWriteFileSync).toHaveBeenCalled();
|
|
146
135
|
});
|
|
147
136
|
|
|
148
137
|
it("应该处理用户取消覆盖", async () => {
|
|
149
138
|
mockExistsSync.mockReturnValue(true);
|
|
150
|
-
|
|
151
139
|
const { select } = await import("@inquirer/prompts");
|
|
152
140
|
vi.mocked(select)
|
|
153
|
-
.mockResolvedValueOnce("global")
|
|
154
|
-
.mockResolvedValueOnce(false);
|
|
155
|
-
|
|
141
|
+
.mockResolvedValueOnce("global")
|
|
142
|
+
.mockResolvedValueOnce(false);
|
|
156
143
|
const { init } = await import("../src/commands/init.js");
|
|
157
|
-
|
|
158
144
|
await init();
|
|
159
|
-
|
|
160
145
|
expect(console.log).toHaveBeenCalledWith("已取消");
|
|
161
146
|
expect(mockWriteFileSync).not.toHaveBeenCalled();
|
|
162
147
|
});
|
|
@@ -165,31 +150,27 @@ describe("Init 模块测试", () => {
|
|
|
165
150
|
describe("基础配置", () => {
|
|
166
151
|
it("应该正确配置分支前缀", async () => {
|
|
167
152
|
mockExistsSync.mockReturnValue(false);
|
|
168
|
-
|
|
169
153
|
const { select, input } = await import("@inquirer/prompts");
|
|
170
154
|
vi.mocked(select)
|
|
171
|
-
.mockResolvedValueOnce("project")
|
|
172
|
-
.mockResolvedValueOnce(false)
|
|
173
|
-
.mockResolvedValueOnce(
|
|
174
|
-
.mockResolvedValueOnce(
|
|
175
|
-
.mockResolvedValueOnce(
|
|
176
|
-
.mockResolvedValueOnce(
|
|
177
|
-
|
|
155
|
+
.mockResolvedValueOnce("project")
|
|
156
|
+
.mockResolvedValueOnce(false)
|
|
157
|
+
.mockResolvedValueOnce(false)
|
|
158
|
+
.mockResolvedValueOnce(false)
|
|
159
|
+
.mockResolvedValueOnce("ask")
|
|
160
|
+
.mockResolvedValueOnce(true)
|
|
161
|
+
.mockResolvedValueOnce(true)
|
|
162
|
+
.mockResolvedValueOnce(false);
|
|
178
163
|
vi.mocked(input)
|
|
179
|
-
.mockResolvedValueOnce("develop")
|
|
180
|
-
.mockResolvedValueOnce("feat")
|
|
181
|
-
.mockResolvedValueOnce("fix")
|
|
182
|
-
.mockResolvedValueOnce("Jira ID")
|
|
183
|
-
.mockResolvedValueOnce("Bug ID")
|
|
184
|
-
.mockResolvedValueOnce("v");
|
|
185
|
-
|
|
164
|
+
.mockResolvedValueOnce("develop")
|
|
165
|
+
.mockResolvedValueOnce("feat")
|
|
166
|
+
.mockResolvedValueOnce("fix")
|
|
167
|
+
.mockResolvedValueOnce("Jira ID")
|
|
168
|
+
.mockResolvedValueOnce("Bug ID")
|
|
169
|
+
.mockResolvedValueOnce("v");
|
|
186
170
|
const { init } = await import("../src/commands/init.js");
|
|
187
|
-
|
|
188
171
|
await init();
|
|
189
|
-
|
|
190
172
|
const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
|
|
191
173
|
const config = JSON.parse(writtenConfig);
|
|
192
|
-
|
|
193
174
|
expect(config.baseBranch).toBe("develop");
|
|
194
175
|
expect(config.featurePrefix).toBe("feat");
|
|
195
176
|
expect(config.hotfixPrefix).toBe("fix");
|
|
@@ -200,61 +181,53 @@ describe("Init 模块测试", () => {
|
|
|
200
181
|
|
|
201
182
|
it("应该正确配置 ID 要求", async () => {
|
|
202
183
|
mockExistsSync.mockReturnValue(false);
|
|
203
|
-
|
|
204
184
|
const { select, input } = await import("@inquirer/prompts");
|
|
205
185
|
vi.mocked(select)
|
|
206
|
-
.mockResolvedValueOnce("project")
|
|
207
|
-
.mockResolvedValueOnce(true)
|
|
208
|
-
.mockResolvedValueOnce(
|
|
209
|
-
.mockResolvedValueOnce(
|
|
210
|
-
.mockResolvedValueOnce(
|
|
211
|
-
.mockResolvedValueOnce(
|
|
212
|
-
|
|
186
|
+
.mockResolvedValueOnce("project")
|
|
187
|
+
.mockResolvedValueOnce(true)
|
|
188
|
+
.mockResolvedValueOnce(false)
|
|
189
|
+
.mockResolvedValueOnce(false)
|
|
190
|
+
.mockResolvedValueOnce("ask")
|
|
191
|
+
.mockResolvedValueOnce(true)
|
|
192
|
+
.mockResolvedValueOnce(true)
|
|
193
|
+
.mockResolvedValueOnce(false);
|
|
213
194
|
vi.mocked(input)
|
|
214
|
-
.mockResolvedValueOnce("")
|
|
215
|
-
.mockResolvedValueOnce("feature")
|
|
216
|
-
.mockResolvedValueOnce("hotfix")
|
|
217
|
-
.mockResolvedValueOnce("Story ID")
|
|
218
|
-
.mockResolvedValueOnce("Issue ID")
|
|
219
|
-
.mockResolvedValueOnce("");
|
|
220
|
-
|
|
195
|
+
.mockResolvedValueOnce("")
|
|
196
|
+
.mockResolvedValueOnce("feature")
|
|
197
|
+
.mockResolvedValueOnce("hotfix")
|
|
198
|
+
.mockResolvedValueOnce("Story ID")
|
|
199
|
+
.mockResolvedValueOnce("Issue ID")
|
|
200
|
+
.mockResolvedValueOnce("");
|
|
221
201
|
const { init } = await import("../src/commands/init.js");
|
|
222
|
-
|
|
223
202
|
await init();
|
|
224
|
-
|
|
225
203
|
const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
|
|
226
204
|
const config = JSON.parse(writtenConfig);
|
|
227
|
-
|
|
228
205
|
expect(config.requireId).toBe(true);
|
|
229
206
|
});
|
|
230
207
|
|
|
231
208
|
it("应该正确配置自动推送选项", async () => {
|
|
232
209
|
mockExistsSync.mockReturnValue(false);
|
|
233
|
-
|
|
234
210
|
const { select, input } = await import("@inquirer/prompts");
|
|
235
211
|
vi.mocked(select)
|
|
236
|
-
.mockResolvedValueOnce("project")
|
|
237
|
-
.mockResolvedValueOnce(false)
|
|
238
|
-
.mockResolvedValueOnce(
|
|
239
|
-
.mockResolvedValueOnce(
|
|
240
|
-
.mockResolvedValueOnce(
|
|
241
|
-
.mockResolvedValueOnce(
|
|
242
|
-
|
|
212
|
+
.mockResolvedValueOnce("project")
|
|
213
|
+
.mockResolvedValueOnce(false)
|
|
214
|
+
.mockResolvedValueOnce(false)
|
|
215
|
+
.mockResolvedValueOnce(false)
|
|
216
|
+
.mockResolvedValueOnce("yes")
|
|
217
|
+
.mockResolvedValueOnce(true)
|
|
218
|
+
.mockResolvedValueOnce(true)
|
|
219
|
+
.mockResolvedValueOnce(false);
|
|
243
220
|
vi.mocked(input)
|
|
244
|
-
.mockResolvedValueOnce("")
|
|
245
|
-
.mockResolvedValueOnce("feature")
|
|
246
|
-
.mockResolvedValueOnce("hotfix")
|
|
247
|
-
.mockResolvedValueOnce("Story ID")
|
|
248
|
-
.mockResolvedValueOnce("Issue ID")
|
|
249
|
-
.mockResolvedValueOnce("");
|
|
250
|
-
|
|
221
|
+
.mockResolvedValueOnce("")
|
|
222
|
+
.mockResolvedValueOnce("feature")
|
|
223
|
+
.mockResolvedValueOnce("hotfix")
|
|
224
|
+
.mockResolvedValueOnce("Story ID")
|
|
225
|
+
.mockResolvedValueOnce("Issue ID")
|
|
226
|
+
.mockResolvedValueOnce("");
|
|
251
227
|
const { init } = await import("../src/commands/init.js");
|
|
252
|
-
|
|
253
228
|
await init();
|
|
254
|
-
|
|
255
229
|
const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
|
|
256
230
|
const config = JSON.parse(writtenConfig);
|
|
257
|
-
|
|
258
231
|
expect(config.autoPush).toBe(true);
|
|
259
232
|
});
|
|
260
233
|
});
|
|
@@ -262,34 +235,32 @@ describe("Init 模块测试", () => {
|
|
|
262
235
|
describe("AI 配置", () => {
|
|
263
236
|
it("应该正确配置 GitHub Models", async () => {
|
|
264
237
|
mockExistsSync.mockReturnValue(false);
|
|
265
|
-
|
|
266
238
|
const { select, input } = await import("@inquirer/prompts");
|
|
267
239
|
vi.mocked(select)
|
|
268
|
-
.mockResolvedValueOnce("project")
|
|
269
|
-
.mockResolvedValueOnce(false)
|
|
270
|
-
.mockResolvedValueOnce(
|
|
271
|
-
.mockResolvedValueOnce(
|
|
272
|
-
.mockResolvedValueOnce(
|
|
273
|
-
.mockResolvedValueOnce(true)
|
|
274
|
-
.mockResolvedValueOnce(
|
|
275
|
-
.mockResolvedValueOnce(
|
|
276
|
-
|
|
240
|
+
.mockResolvedValueOnce("project")
|
|
241
|
+
.mockResolvedValueOnce(false)
|
|
242
|
+
.mockResolvedValueOnce(false)
|
|
243
|
+
.mockResolvedValueOnce(false)
|
|
244
|
+
.mockResolvedValueOnce("ask")
|
|
245
|
+
.mockResolvedValueOnce(true)
|
|
246
|
+
.mockResolvedValueOnce(true)
|
|
247
|
+
.mockResolvedValueOnce(true)
|
|
248
|
+
.mockResolvedValueOnce("github")
|
|
249
|
+
.mockResolvedValueOnce("zh-CN")
|
|
250
|
+
.mockResolvedValueOnce(true)
|
|
251
|
+
.mockResolvedValueOnce(true);
|
|
277
252
|
vi.mocked(input)
|
|
278
|
-
.mockResolvedValueOnce("")
|
|
279
|
-
.mockResolvedValueOnce("feature")
|
|
280
|
-
.mockResolvedValueOnce("hotfix")
|
|
281
|
-
.mockResolvedValueOnce("Story ID")
|
|
282
|
-
.mockResolvedValueOnce("Issue ID")
|
|
283
|
-
.mockResolvedValueOnce("")
|
|
284
|
-
.mockResolvedValueOnce("ghp_test_token");
|
|
285
|
-
|
|
253
|
+
.mockResolvedValueOnce("")
|
|
254
|
+
.mockResolvedValueOnce("feature")
|
|
255
|
+
.mockResolvedValueOnce("hotfix")
|
|
256
|
+
.mockResolvedValueOnce("Story ID")
|
|
257
|
+
.mockResolvedValueOnce("Issue ID")
|
|
258
|
+
.mockResolvedValueOnce("")
|
|
259
|
+
.mockResolvedValueOnce("ghp_test_token");
|
|
286
260
|
const { init } = await import("../src/commands/init.js");
|
|
287
|
-
|
|
288
261
|
await init();
|
|
289
|
-
|
|
290
262
|
const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
|
|
291
263
|
const config = JSON.parse(writtenConfig);
|
|
292
|
-
|
|
293
264
|
expect(config.aiCommit.enabled).toBe(true);
|
|
294
265
|
expect(config.aiCommit.provider).toBe("github");
|
|
295
266
|
expect(config.aiCommit.apiKey).toBe("ghp_test_token");
|
|
@@ -299,34 +270,32 @@ describe("Init 模块测试", () => {
|
|
|
299
270
|
|
|
300
271
|
it("应该正确配置 OpenAI", async () => {
|
|
301
272
|
mockExistsSync.mockReturnValue(false);
|
|
302
|
-
|
|
303
273
|
const { select, input } = await import("@inquirer/prompts");
|
|
304
274
|
vi.mocked(select)
|
|
305
|
-
.mockResolvedValueOnce("project")
|
|
306
|
-
.mockResolvedValueOnce(false)
|
|
307
|
-
.mockResolvedValueOnce(
|
|
308
|
-
.mockResolvedValueOnce(
|
|
309
|
-
.mockResolvedValueOnce(
|
|
310
|
-
.mockResolvedValueOnce(true)
|
|
311
|
-
.mockResolvedValueOnce(
|
|
312
|
-
.mockResolvedValueOnce(
|
|
313
|
-
|
|
275
|
+
.mockResolvedValueOnce("project")
|
|
276
|
+
.mockResolvedValueOnce(false)
|
|
277
|
+
.mockResolvedValueOnce(false)
|
|
278
|
+
.mockResolvedValueOnce(false)
|
|
279
|
+
.mockResolvedValueOnce("ask")
|
|
280
|
+
.mockResolvedValueOnce(true)
|
|
281
|
+
.mockResolvedValueOnce(true)
|
|
282
|
+
.mockResolvedValueOnce(true)
|
|
283
|
+
.mockResolvedValueOnce("openai")
|
|
284
|
+
.mockResolvedValueOnce("en-US")
|
|
285
|
+
.mockResolvedValueOnce(true)
|
|
286
|
+
.mockResolvedValueOnce(true);
|
|
314
287
|
vi.mocked(input)
|
|
315
|
-
.mockResolvedValueOnce("")
|
|
316
|
-
.mockResolvedValueOnce("feature")
|
|
317
|
-
.mockResolvedValueOnce("hotfix")
|
|
318
|
-
.mockResolvedValueOnce("Story ID")
|
|
319
|
-
.mockResolvedValueOnce("Issue ID")
|
|
320
|
-
.mockResolvedValueOnce("")
|
|
321
|
-
.mockResolvedValueOnce("sk-test-key");
|
|
322
|
-
|
|
288
|
+
.mockResolvedValueOnce("")
|
|
289
|
+
.mockResolvedValueOnce("feature")
|
|
290
|
+
.mockResolvedValueOnce("hotfix")
|
|
291
|
+
.mockResolvedValueOnce("Story ID")
|
|
292
|
+
.mockResolvedValueOnce("Issue ID")
|
|
293
|
+
.mockResolvedValueOnce("")
|
|
294
|
+
.mockResolvedValueOnce("sk-test-key");
|
|
323
295
|
const { init } = await import("../src/commands/init.js");
|
|
324
|
-
|
|
325
296
|
await init();
|
|
326
|
-
|
|
327
297
|
const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
|
|
328
298
|
const config = JSON.parse(writtenConfig);
|
|
329
|
-
|
|
330
299
|
expect(config.aiCommit.enabled).toBe(true);
|
|
331
300
|
expect(config.aiCommit.provider).toBe("openai");
|
|
332
301
|
expect(config.aiCommit.apiKey).toBe("sk-test-key");
|
|
@@ -336,33 +305,31 @@ describe("Init 模块测试", () => {
|
|
|
336
305
|
|
|
337
306
|
it("应该正确配置 Ollama", async () => {
|
|
338
307
|
mockExistsSync.mockReturnValue(false);
|
|
339
|
-
|
|
340
308
|
const { select, input } = await import("@inquirer/prompts");
|
|
341
309
|
vi.mocked(select)
|
|
342
|
-
.mockResolvedValueOnce("project")
|
|
343
|
-
.mockResolvedValueOnce(false)
|
|
344
|
-
.mockResolvedValueOnce(
|
|
345
|
-
.mockResolvedValueOnce(
|
|
346
|
-
.mockResolvedValueOnce(
|
|
347
|
-
.mockResolvedValueOnce(true)
|
|
348
|
-
.mockResolvedValueOnce(
|
|
349
|
-
.mockResolvedValueOnce(
|
|
350
|
-
|
|
310
|
+
.mockResolvedValueOnce("project")
|
|
311
|
+
.mockResolvedValueOnce(false)
|
|
312
|
+
.mockResolvedValueOnce(false)
|
|
313
|
+
.mockResolvedValueOnce(false)
|
|
314
|
+
.mockResolvedValueOnce("ask")
|
|
315
|
+
.mockResolvedValueOnce(true)
|
|
316
|
+
.mockResolvedValueOnce(true)
|
|
317
|
+
.mockResolvedValueOnce(true)
|
|
318
|
+
.mockResolvedValueOnce("ollama")
|
|
319
|
+
.mockResolvedValueOnce("zh-CN")
|
|
320
|
+
.mockResolvedValueOnce(true)
|
|
321
|
+
.mockResolvedValueOnce(true);
|
|
351
322
|
vi.mocked(input)
|
|
352
|
-
.mockResolvedValueOnce("")
|
|
353
|
-
.mockResolvedValueOnce("feature")
|
|
354
|
-
.mockResolvedValueOnce("hotfix")
|
|
355
|
-
.mockResolvedValueOnce("Story ID")
|
|
356
|
-
.mockResolvedValueOnce("Issue ID")
|
|
357
|
-
.mockResolvedValueOnce("");
|
|
358
|
-
|
|
323
|
+
.mockResolvedValueOnce("")
|
|
324
|
+
.mockResolvedValueOnce("feature")
|
|
325
|
+
.mockResolvedValueOnce("hotfix")
|
|
326
|
+
.mockResolvedValueOnce("Story ID")
|
|
327
|
+
.mockResolvedValueOnce("Issue ID")
|
|
328
|
+
.mockResolvedValueOnce("");
|
|
359
329
|
const { init } = await import("../src/commands/init.js");
|
|
360
|
-
|
|
361
330
|
await init();
|
|
362
|
-
|
|
363
331
|
const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
|
|
364
332
|
const config = JSON.parse(writtenConfig);
|
|
365
|
-
|
|
366
333
|
expect(config.aiCommit.enabled).toBe(true);
|
|
367
334
|
expect(config.aiCommit.provider).toBe("ollama");
|
|
368
335
|
expect(config.aiCommit.apiKey).toBeUndefined();
|
|
@@ -372,31 +339,27 @@ describe("Init 模块测试", () => {
|
|
|
372
339
|
|
|
373
340
|
it("应该正确配置禁用 AI", async () => {
|
|
374
341
|
mockExistsSync.mockReturnValue(false);
|
|
375
|
-
|
|
376
342
|
const { select, input } = await import("@inquirer/prompts");
|
|
377
343
|
vi.mocked(select)
|
|
378
|
-
.mockResolvedValueOnce("project")
|
|
379
|
-
.mockResolvedValueOnce(false)
|
|
380
|
-
.mockResolvedValueOnce(
|
|
381
|
-
.mockResolvedValueOnce(
|
|
382
|
-
.mockResolvedValueOnce(
|
|
383
|
-
.mockResolvedValueOnce(
|
|
384
|
-
|
|
344
|
+
.mockResolvedValueOnce("project")
|
|
345
|
+
.mockResolvedValueOnce(false)
|
|
346
|
+
.mockResolvedValueOnce(false)
|
|
347
|
+
.mockResolvedValueOnce(false)
|
|
348
|
+
.mockResolvedValueOnce("ask")
|
|
349
|
+
.mockResolvedValueOnce(true)
|
|
350
|
+
.mockResolvedValueOnce(true)
|
|
351
|
+
.mockResolvedValueOnce(false);
|
|
385
352
|
vi.mocked(input)
|
|
386
|
-
.mockResolvedValueOnce("")
|
|
387
|
-
.mockResolvedValueOnce("feature")
|
|
388
|
-
.mockResolvedValueOnce("hotfix")
|
|
389
|
-
.mockResolvedValueOnce("Story ID")
|
|
390
|
-
.mockResolvedValueOnce("Issue ID")
|
|
391
|
-
.mockResolvedValueOnce("");
|
|
392
|
-
|
|
353
|
+
.mockResolvedValueOnce("")
|
|
354
|
+
.mockResolvedValueOnce("feature")
|
|
355
|
+
.mockResolvedValueOnce("hotfix")
|
|
356
|
+
.mockResolvedValueOnce("Story ID")
|
|
357
|
+
.mockResolvedValueOnce("Issue ID")
|
|
358
|
+
.mockResolvedValueOnce("");
|
|
393
359
|
const { init } = await import("../src/commands/init.js");
|
|
394
|
-
|
|
395
360
|
await init();
|
|
396
|
-
|
|
397
361
|
const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
|
|
398
362
|
const config = JSON.parse(writtenConfig);
|
|
399
|
-
|
|
400
363
|
expect(config.aiCommit.enabled).toBe(false);
|
|
401
364
|
});
|
|
402
365
|
});
|
|
@@ -404,41 +367,36 @@ describe("Init 模块测试", () => {
|
|
|
404
367
|
describe("配置验证", () => {
|
|
405
368
|
it("应该验证 GitHub Token 不为空", async () => {
|
|
406
369
|
mockExistsSync.mockReturnValue(false);
|
|
407
|
-
|
|
408
370
|
const { select, input } = await import("@inquirer/prompts");
|
|
409
371
|
vi.mocked(select)
|
|
410
|
-
.mockResolvedValueOnce("project")
|
|
411
|
-
.mockResolvedValueOnce(false)
|
|
412
|
-
.mockResolvedValueOnce(
|
|
413
|
-
.mockResolvedValueOnce(
|
|
414
|
-
.mockResolvedValueOnce(
|
|
415
|
-
.mockResolvedValueOnce(true)
|
|
416
|
-
.mockResolvedValueOnce(
|
|
417
|
-
.mockResolvedValueOnce(
|
|
418
|
-
|
|
372
|
+
.mockResolvedValueOnce("project")
|
|
373
|
+
.mockResolvedValueOnce(false)
|
|
374
|
+
.mockResolvedValueOnce(false)
|
|
375
|
+
.mockResolvedValueOnce(false)
|
|
376
|
+
.mockResolvedValueOnce("ask")
|
|
377
|
+
.mockResolvedValueOnce(true)
|
|
378
|
+
.mockResolvedValueOnce(true)
|
|
379
|
+
.mockResolvedValueOnce(true)
|
|
380
|
+
.mockResolvedValueOnce("github")
|
|
381
|
+
.mockResolvedValueOnce("zh-CN")
|
|
382
|
+
.mockResolvedValueOnce(true)
|
|
383
|
+
.mockResolvedValueOnce(true);
|
|
419
384
|
vi.mocked(input)
|
|
420
|
-
.mockResolvedValueOnce("")
|
|
421
|
-
.mockResolvedValueOnce("feature")
|
|
422
|
-
.mockResolvedValueOnce("hotfix")
|
|
423
|
-
.mockResolvedValueOnce("Story ID")
|
|
424
|
-
.mockResolvedValueOnce("Issue ID")
|
|
425
|
-
.mockResolvedValueOnce("")
|
|
426
|
-
.mockResolvedValueOnce("ghp_valid_token");
|
|
427
|
-
|
|
385
|
+
.mockResolvedValueOnce("")
|
|
386
|
+
.mockResolvedValueOnce("feature")
|
|
387
|
+
.mockResolvedValueOnce("hotfix")
|
|
388
|
+
.mockResolvedValueOnce("Story ID")
|
|
389
|
+
.mockResolvedValueOnce("Issue ID")
|
|
390
|
+
.mockResolvedValueOnce("")
|
|
391
|
+
.mockResolvedValueOnce("ghp_valid_token");
|
|
428
392
|
const { init } = await import("../src/commands/init.js");
|
|
429
|
-
|
|
430
393
|
await init();
|
|
431
|
-
|
|
432
|
-
// 验证 input 被调用时包含验证函数
|
|
433
394
|
const inputCalls = vi.mocked(input).mock.calls;
|
|
434
|
-
const tokenInputCall = inputCalls.find(call =>
|
|
395
|
+
const tokenInputCall = inputCalls.find((call) =>
|
|
435
396
|
call[0].message?.includes("GitHub Token")
|
|
436
397
|
);
|
|
437
|
-
|
|
438
398
|
expect(tokenInputCall).toBeDefined();
|
|
439
399
|
expect(tokenInputCall![0].validate).toBeDefined();
|
|
440
|
-
|
|
441
|
-
// 测试验证函数
|
|
442
400
|
const validate = tokenInputCall![0].validate!;
|
|
443
401
|
expect(validate("")).toBe("GitHub Token 不能为空");
|
|
444
402
|
expect(validate("valid-token")).toBe(true);
|
|
@@ -446,41 +404,36 @@ describe("Init 模块测试", () => {
|
|
|
446
404
|
|
|
447
405
|
it("应该验证 OpenAI API Key 不为空", async () => {
|
|
448
406
|
mockExistsSync.mockReturnValue(false);
|
|
449
|
-
|
|
450
407
|
const { select, input } = await import("@inquirer/prompts");
|
|
451
408
|
vi.mocked(select)
|
|
452
|
-
.mockResolvedValueOnce("project")
|
|
453
|
-
.mockResolvedValueOnce(false)
|
|
454
|
-
.mockResolvedValueOnce(
|
|
455
|
-
.mockResolvedValueOnce(
|
|
456
|
-
.mockResolvedValueOnce(
|
|
457
|
-
.mockResolvedValueOnce(true)
|
|
458
|
-
.mockResolvedValueOnce(
|
|
459
|
-
.mockResolvedValueOnce(
|
|
460
|
-
|
|
409
|
+
.mockResolvedValueOnce("project")
|
|
410
|
+
.mockResolvedValueOnce(false)
|
|
411
|
+
.mockResolvedValueOnce(false)
|
|
412
|
+
.mockResolvedValueOnce(false)
|
|
413
|
+
.mockResolvedValueOnce("ask")
|
|
414
|
+
.mockResolvedValueOnce(true)
|
|
415
|
+
.mockResolvedValueOnce(true)
|
|
416
|
+
.mockResolvedValueOnce(true)
|
|
417
|
+
.mockResolvedValueOnce("openai")
|
|
418
|
+
.mockResolvedValueOnce("en-US")
|
|
419
|
+
.mockResolvedValueOnce(true)
|
|
420
|
+
.mockResolvedValueOnce(true);
|
|
461
421
|
vi.mocked(input)
|
|
462
|
-
.mockResolvedValueOnce("")
|
|
463
|
-
.mockResolvedValueOnce("feature")
|
|
464
|
-
.mockResolvedValueOnce("hotfix")
|
|
465
|
-
.mockResolvedValueOnce("Story ID")
|
|
466
|
-
.mockResolvedValueOnce("Issue ID")
|
|
467
|
-
.mockResolvedValueOnce("")
|
|
468
|
-
.mockResolvedValueOnce("sk-valid-key");
|
|
469
|
-
|
|
422
|
+
.mockResolvedValueOnce("")
|
|
423
|
+
.mockResolvedValueOnce("feature")
|
|
424
|
+
.mockResolvedValueOnce("hotfix")
|
|
425
|
+
.mockResolvedValueOnce("Story ID")
|
|
426
|
+
.mockResolvedValueOnce("Issue ID")
|
|
427
|
+
.mockResolvedValueOnce("")
|
|
428
|
+
.mockResolvedValueOnce("sk-valid-key");
|
|
470
429
|
const { init } = await import("../src/commands/init.js");
|
|
471
|
-
|
|
472
430
|
await init();
|
|
473
|
-
|
|
474
|
-
// 验证 input 被调用时包含验证函数
|
|
475
431
|
const inputCalls = vi.mocked(input).mock.calls;
|
|
476
|
-
const keyInputCall = inputCalls.find(call =>
|
|
432
|
+
const keyInputCall = inputCalls.find((call) =>
|
|
477
433
|
call[0].message?.includes("OpenAI API Key")
|
|
478
434
|
);
|
|
479
|
-
|
|
480
435
|
expect(keyInputCall).toBeDefined();
|
|
481
436
|
expect(keyInputCall![0].validate).toBeDefined();
|
|
482
|
-
|
|
483
|
-
// 测试验证函数
|
|
484
437
|
const validate = keyInputCall![0].validate!;
|
|
485
438
|
expect(validate("")).toBe("API Key 不能为空");
|
|
486
439
|
expect(validate("valid-key")).toBe(true);
|
|
@@ -490,31 +443,27 @@ describe("Init 模块测试", () => {
|
|
|
490
443
|
describe("配置输出", () => {
|
|
491
444
|
it("应该包含默认的 commit emojis", async () => {
|
|
492
445
|
mockExistsSync.mockReturnValue(false);
|
|
493
|
-
|
|
494
446
|
const { select, input } = await import("@inquirer/prompts");
|
|
495
447
|
vi.mocked(select)
|
|
496
|
-
.mockResolvedValueOnce("project")
|
|
497
|
-
.mockResolvedValueOnce(false)
|
|
498
|
-
.mockResolvedValueOnce(
|
|
499
|
-
.mockResolvedValueOnce(
|
|
500
|
-
.mockResolvedValueOnce(
|
|
501
|
-
.mockResolvedValueOnce(
|
|
502
|
-
|
|
448
|
+
.mockResolvedValueOnce("project")
|
|
449
|
+
.mockResolvedValueOnce(false)
|
|
450
|
+
.mockResolvedValueOnce(false)
|
|
451
|
+
.mockResolvedValueOnce(false)
|
|
452
|
+
.mockResolvedValueOnce("ask")
|
|
453
|
+
.mockResolvedValueOnce(true)
|
|
454
|
+
.mockResolvedValueOnce(true)
|
|
455
|
+
.mockResolvedValueOnce(false);
|
|
503
456
|
vi.mocked(input)
|
|
504
|
-
.mockResolvedValueOnce("")
|
|
505
|
-
.mockResolvedValueOnce("feature")
|
|
506
|
-
.mockResolvedValueOnce("hotfix")
|
|
507
|
-
.mockResolvedValueOnce("Story ID")
|
|
508
|
-
.mockResolvedValueOnce("Issue ID")
|
|
509
|
-
.mockResolvedValueOnce("");
|
|
510
|
-
|
|
457
|
+
.mockResolvedValueOnce("")
|
|
458
|
+
.mockResolvedValueOnce("feature")
|
|
459
|
+
.mockResolvedValueOnce("hotfix")
|
|
460
|
+
.mockResolvedValueOnce("Story ID")
|
|
461
|
+
.mockResolvedValueOnce("Issue ID")
|
|
462
|
+
.mockResolvedValueOnce("");
|
|
511
463
|
const { init } = await import("../src/commands/init.js");
|
|
512
|
-
|
|
513
464
|
await init();
|
|
514
|
-
|
|
515
465
|
const writtenConfig = mockWriteFileSync.mock.calls[0][1] as string;
|
|
516
466
|
const config = JSON.parse(writtenConfig);
|
|
517
|
-
|
|
518
467
|
expect(config.commitEmojis).toBeDefined();
|
|
519
468
|
expect(config.commitEmojis.feat).toBe("✨");
|
|
520
469
|
expect(config.commitEmojis.fix).toBe("🐛");
|
|
@@ -523,28 +472,25 @@ describe("Init 模块测试", () => {
|
|
|
523
472
|
|
|
524
473
|
it("应该显示成功消息", async () => {
|
|
525
474
|
mockExistsSync.mockReturnValue(false);
|
|
526
|
-
|
|
527
475
|
const { select, input } = await import("@inquirer/prompts");
|
|
528
476
|
vi.mocked(select)
|
|
529
|
-
.mockResolvedValueOnce("global")
|
|
530
|
-
.mockResolvedValueOnce(false)
|
|
531
|
-
.mockResolvedValueOnce(
|
|
532
|
-
.mockResolvedValueOnce(
|
|
533
|
-
.mockResolvedValueOnce(
|
|
534
|
-
.mockResolvedValueOnce(
|
|
535
|
-
|
|
477
|
+
.mockResolvedValueOnce("global")
|
|
478
|
+
.mockResolvedValueOnce(false)
|
|
479
|
+
.mockResolvedValueOnce(false)
|
|
480
|
+
.mockResolvedValueOnce(false)
|
|
481
|
+
.mockResolvedValueOnce("ask")
|
|
482
|
+
.mockResolvedValueOnce(true)
|
|
483
|
+
.mockResolvedValueOnce(true)
|
|
484
|
+
.mockResolvedValueOnce(false);
|
|
536
485
|
vi.mocked(input)
|
|
537
|
-
.mockResolvedValueOnce("")
|
|
538
|
-
.mockResolvedValueOnce("feature")
|
|
539
|
-
.mockResolvedValueOnce("hotfix")
|
|
540
|
-
.mockResolvedValueOnce("Story ID")
|
|
541
|
-
.mockResolvedValueOnce("Issue ID")
|
|
542
|
-
.mockResolvedValueOnce("");
|
|
543
|
-
|
|
486
|
+
.mockResolvedValueOnce("")
|
|
487
|
+
.mockResolvedValueOnce("feature")
|
|
488
|
+
.mockResolvedValueOnce("hotfix")
|
|
489
|
+
.mockResolvedValueOnce("Story ID")
|
|
490
|
+
.mockResolvedValueOnce("Issue ID")
|
|
491
|
+
.mockResolvedValueOnce("");
|
|
544
492
|
const { init } = await import("../src/commands/init.js");
|
|
545
|
-
|
|
546
493
|
await init();
|
|
547
|
-
|
|
548
494
|
expect(console.log).toHaveBeenCalledWith(
|
|
549
495
|
expect.stringContaining("✓ 配置已保存到 全局配置文件")
|
|
550
496
|
);
|
|
@@ -552,31 +498,28 @@ describe("Init 模块测试", () => {
|
|
|
552
498
|
|
|
553
499
|
it("应该显示全局配置的提示信息", async () => {
|
|
554
500
|
mockExistsSync.mockReturnValue(false);
|
|
555
|
-
|
|
556
501
|
const { select, input } = await import("@inquirer/prompts");
|
|
557
502
|
vi.mocked(select)
|
|
558
|
-
.mockResolvedValueOnce("global")
|
|
559
|
-
.mockResolvedValueOnce(false)
|
|
560
|
-
.mockResolvedValueOnce(
|
|
561
|
-
.mockResolvedValueOnce(
|
|
562
|
-
.mockResolvedValueOnce(
|
|
563
|
-
.mockResolvedValueOnce(
|
|
564
|
-
|
|
503
|
+
.mockResolvedValueOnce("global")
|
|
504
|
+
.mockResolvedValueOnce(false)
|
|
505
|
+
.mockResolvedValueOnce(false)
|
|
506
|
+
.mockResolvedValueOnce(false)
|
|
507
|
+
.mockResolvedValueOnce("ask")
|
|
508
|
+
.mockResolvedValueOnce(true)
|
|
509
|
+
.mockResolvedValueOnce(true)
|
|
510
|
+
.mockResolvedValueOnce(false);
|
|
565
511
|
vi.mocked(input)
|
|
566
|
-
.mockResolvedValueOnce("")
|
|
567
|
-
.mockResolvedValueOnce("feature")
|
|
568
|
-
.mockResolvedValueOnce("hotfix")
|
|
569
|
-
.mockResolvedValueOnce("Story ID")
|
|
570
|
-
.mockResolvedValueOnce("Issue ID")
|
|
571
|
-
.mockResolvedValueOnce("");
|
|
572
|
-
|
|
512
|
+
.mockResolvedValueOnce("")
|
|
513
|
+
.mockResolvedValueOnce("feature")
|
|
514
|
+
.mockResolvedValueOnce("hotfix")
|
|
515
|
+
.mockResolvedValueOnce("Story ID")
|
|
516
|
+
.mockResolvedValueOnce("Issue ID")
|
|
517
|
+
.mockResolvedValueOnce("");
|
|
573
518
|
const { init } = await import("../src/commands/init.js");
|
|
574
|
-
|
|
575
519
|
await init();
|
|
576
|
-
|
|
577
520
|
expect(console.log).toHaveBeenCalledWith(
|
|
578
521
|
expect.stringContaining("全局配置对所有项目生效")
|
|
579
522
|
);
|
|
580
523
|
});
|
|
581
524
|
});
|
|
582
|
-
});
|
|
525
|
+
});
|