bbk-cli 1.1.2 → 1.2.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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/README.md +113 -132
- package/dist/cli/wrapper.d.ts +0 -1
- package/dist/cli/wrapper.d.ts.map +1 -1
- package/dist/cli/wrapper.js +19 -54
- package/dist/cli/wrapper.js.map +1 -1
- package/dist/commands/helpers.js +1 -1
- package/dist/commands/runner.d.ts.map +1 -1
- package/dist/commands/runner.js +22 -18
- package/dist/commands/runner.js.map +1 -1
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +37 -52
- package/dist/config/constants.js.map +1 -1
- package/dist/utils/arg-parser.d.ts.map +1 -1
- package/dist/utils/arg-parser.js +23 -8
- package/dist/utils/arg-parser.js.map +1 -1
- package/dist/utils/bitbucket-client.d.ts +24 -37
- package/dist/utils/bitbucket-client.d.ts.map +1 -1
- package/dist/utils/bitbucket-client.js +38 -52
- package/dist/utils/bitbucket-client.js.map +1 -1
- package/dist/utils/bitbucket-utils.d.ts +48 -68
- package/dist/utils/bitbucket-utils.d.ts.map +1 -1
- package/dist/utils/bitbucket-utils.js +100 -125
- package/dist/utils/bitbucket-utils.js.map +1 -1
- package/dist/utils/config-loader.d.ts +10 -29
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +277 -51
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -3
- package/tests/integration/cli-integration.test.ts +96 -217
- package/tests/unit/cli/wrapper.test.ts +28 -137
- package/tests/unit/commands/runner.test.ts +69 -197
- package/tests/unit/utils/arg-parser.test.ts +53 -4
- package/tests/unit/utils/config-loader.test.ts +441 -106
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
3
|
import { wrapper } from '../../../src/cli/wrapper.js';
|
|
4
4
|
|
|
@@ -64,6 +64,13 @@ vi.mock('../../../src/utils/index.js', () => ({
|
|
|
64
64
|
|
|
65
65
|
const originalEnv = process.env;
|
|
66
66
|
|
|
67
|
+
const mockConfig = {
|
|
68
|
+
email: 'user@example.com',
|
|
69
|
+
apiToken: 'test_token',
|
|
70
|
+
defaultWorkspace: 'myworkspace',
|
|
71
|
+
defaultFormat: 'json' as const,
|
|
72
|
+
};
|
|
73
|
+
|
|
67
74
|
describe('cli/wrapper', () => {
|
|
68
75
|
beforeEach(() => {
|
|
69
76
|
vi.clearAllMocks();
|
|
@@ -103,11 +110,7 @@ describe('cli/wrapper', () => {
|
|
|
103
110
|
describe('connect', () => {
|
|
104
111
|
it('should load config successfully', async () => {
|
|
105
112
|
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
106
|
-
vi.mocked(loadConfig).mockReturnValue(
|
|
107
|
-
profiles: { cloud: { email: 'test@test.com', apiToken: 'token123' } },
|
|
108
|
-
defaultProfile: 'cloud',
|
|
109
|
-
defaultFormat: 'json',
|
|
110
|
-
});
|
|
113
|
+
vi.mocked(loadConfig).mockReturnValue(mockConfig);
|
|
111
114
|
|
|
112
115
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
113
116
|
|
|
@@ -119,22 +122,16 @@ describe('cli/wrapper', () => {
|
|
|
119
122
|
consoleLogSpy.mockRestore();
|
|
120
123
|
});
|
|
121
124
|
|
|
122
|
-
it('should set default
|
|
125
|
+
it('should set default format', async () => {
|
|
123
126
|
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
124
|
-
vi.mocked(loadConfig).mockReturnValue(
|
|
125
|
-
profiles: { cloud: { email: 'test@test.com', apiToken: 'token123' } },
|
|
126
|
-
defaultProfile: 'cloud',
|
|
127
|
-
defaultFormat: 'toon',
|
|
128
|
-
});
|
|
127
|
+
vi.mocked(loadConfig).mockReturnValue(mockConfig);
|
|
129
128
|
|
|
130
129
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
131
130
|
|
|
132
131
|
await cli.connect();
|
|
133
132
|
|
|
134
133
|
// @ts-expect-error - accessing private property for testing
|
|
135
|
-
expect(cli.
|
|
136
|
-
// @ts-expect-error - accessing private property for testing
|
|
137
|
-
expect(cli.currentFormat).toBe('toon');
|
|
134
|
+
expect(cli.currentFormat).toBe('json');
|
|
138
135
|
|
|
139
136
|
consoleLogSpy.mockRestore();
|
|
140
137
|
});
|
|
@@ -156,60 +153,18 @@ describe('cli/wrapper', () => {
|
|
|
156
153
|
// Expected
|
|
157
154
|
}
|
|
158
155
|
|
|
159
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith('
|
|
160
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith('\nMake sure:');
|
|
161
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith('1. .claude/bitbucket-config.local.md exists');
|
|
156
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith('Config file not found');
|
|
162
157
|
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
163
158
|
|
|
164
159
|
consoleErrorSpy.mockRestore();
|
|
165
160
|
exitSpy.mockRestore();
|
|
166
161
|
});
|
|
167
|
-
|
|
168
|
-
it('should use CLAUDE_PROJECT_ROOT if set', async () => {
|
|
169
|
-
process.env.CLAUDE_PROJECT_ROOT = '/custom/root';
|
|
170
|
-
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
171
|
-
vi.mocked(loadConfig).mockReturnValue({
|
|
172
|
-
profiles: { cloud: { email: 'test@test.com', apiToken: 'token123' } },
|
|
173
|
-
defaultProfile: 'cloud',
|
|
174
|
-
defaultFormat: 'json',
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
178
|
-
|
|
179
|
-
await cli.connect();
|
|
180
|
-
|
|
181
|
-
expect(loadConfig).toHaveBeenCalledWith('/custom/root');
|
|
182
|
-
|
|
183
|
-
consoleLogSpy.mockRestore();
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('should use process.cwd() if CLAUDE_PROJECT_ROOT not set', async () => {
|
|
187
|
-
delete process.env.CLAUDE_PROJECT_ROOT;
|
|
188
|
-
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
189
|
-
vi.mocked(loadConfig).mockReturnValue({
|
|
190
|
-
profiles: { cloud: { email: 'test@test.com', apiToken: 'token123' } },
|
|
191
|
-
defaultProfile: 'cloud',
|
|
192
|
-
defaultFormat: 'json',
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
196
|
-
|
|
197
|
-
await cli.connect();
|
|
198
|
-
|
|
199
|
-
expect(loadConfig).toHaveBeenCalledWith(process.cwd());
|
|
200
|
-
|
|
201
|
-
consoleLogSpy.mockRestore();
|
|
202
|
-
});
|
|
203
162
|
});
|
|
204
163
|
|
|
205
164
|
describe('handleCommand', () => {
|
|
206
165
|
beforeEach(async () => {
|
|
207
166
|
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
208
|
-
vi.mocked(loadConfig).mockReturnValue(
|
|
209
|
-
profiles: { cloud: { host: 'https://test.atlassian.net', email: 'test@test.com', apiToken: 'token' } },
|
|
210
|
-
defaultProfile: 'cloud',
|
|
211
|
-
defaultFormat: 'json',
|
|
212
|
-
});
|
|
167
|
+
vi.mocked(loadConfig).mockReturnValue(mockConfig);
|
|
213
168
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
214
169
|
await cli.connect();
|
|
215
170
|
consoleLogSpy.mockRestore();
|
|
@@ -299,28 +254,6 @@ describe('cli/wrapper', () => {
|
|
|
299
254
|
consoleSpy.mockRestore();
|
|
300
255
|
});
|
|
301
256
|
|
|
302
|
-
it('should switch profile to valid profile', async () => {
|
|
303
|
-
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
304
|
-
|
|
305
|
-
await cli['handleCommand']('profile cloud');
|
|
306
|
-
|
|
307
|
-
expect(consoleLogSpy).toHaveBeenCalledWith('Switched to profile: cloud');
|
|
308
|
-
expect(mockRlInterface.prompt).toHaveBeenCalled();
|
|
309
|
-
|
|
310
|
-
consoleLogSpy.mockRestore();
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
it('should show error for invalid profile', async () => {
|
|
314
|
-
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
315
|
-
|
|
316
|
-
await cli['handleCommand']('profile nonexistent');
|
|
317
|
-
|
|
318
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('ERROR:'));
|
|
319
|
-
expect(mockRlInterface.prompt).toHaveBeenCalled();
|
|
320
|
-
|
|
321
|
-
consoleErrorSpy.mockRestore();
|
|
322
|
-
});
|
|
323
|
-
|
|
324
257
|
it('should switch format to valid format', async () => {
|
|
325
258
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
326
259
|
|
|
@@ -343,18 +276,6 @@ describe('cli/wrapper', () => {
|
|
|
343
276
|
consoleErrorSpy.mockRestore();
|
|
344
277
|
});
|
|
345
278
|
|
|
346
|
-
it('should list available profiles', async () => {
|
|
347
|
-
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
348
|
-
|
|
349
|
-
await cli['handleCommand']('profiles');
|
|
350
|
-
|
|
351
|
-
expect(consoleLogSpy).toHaveBeenCalledWith('\nAvailable profiles:');
|
|
352
|
-
expect(consoleLogSpy).toHaveBeenCalledWith('1. cloud (current)');
|
|
353
|
-
expect(mockRlInterface.prompt).toHaveBeenCalled();
|
|
354
|
-
|
|
355
|
-
consoleLogSpy.mockRestore();
|
|
356
|
-
});
|
|
357
|
-
|
|
358
279
|
it('should show command detail with -h flag', async () => {
|
|
359
280
|
const { printCommandDetail } = await import('../../../src/commands/index.js');
|
|
360
281
|
|
|
@@ -392,11 +313,7 @@ describe('cli/wrapper', () => {
|
|
|
392
313
|
describe('runCommand', () => {
|
|
393
314
|
beforeEach(async () => {
|
|
394
315
|
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
395
|
-
vi.mocked(loadConfig).mockReturnValue(
|
|
396
|
-
profiles: { cloud: { email: 'test@test.com', apiToken: 'token123' } },
|
|
397
|
-
defaultProfile: 'cloud',
|
|
398
|
-
defaultFormat: 'json',
|
|
399
|
-
});
|
|
316
|
+
vi.mocked(loadConfig).mockReturnValue(mockConfig);
|
|
400
317
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
401
318
|
await cli.connect();
|
|
402
319
|
consoleLogSpy.mockRestore();
|
|
@@ -409,7 +326,7 @@ describe('cli/wrapper', () => {
|
|
|
409
326
|
|
|
410
327
|
await cli['runCommand']('list-repositories', '{"workspace":"myworkspace"}');
|
|
411
328
|
|
|
412
|
-
expect(listRepositories).toHaveBeenCalledWith('
|
|
329
|
+
expect(listRepositories).toHaveBeenCalledWith('myworkspace', 'json');
|
|
413
330
|
|
|
414
331
|
consoleLogSpy.mockRestore();
|
|
415
332
|
});
|
|
@@ -421,7 +338,7 @@ describe('cli/wrapper', () => {
|
|
|
421
338
|
|
|
422
339
|
await cli['runCommand']('get-repository', '{"workspace":"myworkspace","repoSlug":"my-repo"}');
|
|
423
340
|
|
|
424
|
-
expect(getRepository).toHaveBeenCalledWith('
|
|
341
|
+
expect(getRepository).toHaveBeenCalledWith('myworkspace', 'my-repo', 'json');
|
|
425
342
|
|
|
426
343
|
consoleLogSpy.mockRestore();
|
|
427
344
|
});
|
|
@@ -444,7 +361,7 @@ describe('cli/wrapper', () => {
|
|
|
444
361
|
|
|
445
362
|
await cli['runCommand']('list-pullrequests', '{"workspace":"myworkspace","repoSlug":"my-repo","state":"OPEN"}');
|
|
446
363
|
|
|
447
|
-
expect(listPullRequests).toHaveBeenCalledWith('
|
|
364
|
+
expect(listPullRequests).toHaveBeenCalledWith('myworkspace', 'my-repo', 'OPEN', 'json');
|
|
448
365
|
|
|
449
366
|
consoleLogSpy.mockRestore();
|
|
450
367
|
});
|
|
@@ -456,7 +373,7 @@ describe('cli/wrapper', () => {
|
|
|
456
373
|
|
|
457
374
|
await cli['runCommand']('get-issue', '{"workspace":"myworkspace","repoSlug":"my-repo","issueId":"123"}');
|
|
458
375
|
|
|
459
|
-
expect(getIssue).toHaveBeenCalledWith('
|
|
376
|
+
expect(getIssue).toHaveBeenCalledWith('myworkspace', 'my-repo', '123', 'json');
|
|
460
377
|
|
|
461
378
|
consoleLogSpy.mockRestore();
|
|
462
379
|
});
|
|
@@ -483,7 +400,6 @@ describe('cli/wrapper', () => {
|
|
|
483
400
|
);
|
|
484
401
|
|
|
485
402
|
expect(createIssue).toHaveBeenCalledWith(
|
|
486
|
-
'cloud',
|
|
487
403
|
'myworkspace',
|
|
488
404
|
'my-repo',
|
|
489
405
|
'Bug report',
|
|
@@ -514,7 +430,7 @@ describe('cli/wrapper', () => {
|
|
|
514
430
|
|
|
515
431
|
await cli['runCommand']('list-branches', '{"workspace":"myworkspace","repoSlug":"my-repo"}');
|
|
516
432
|
|
|
517
|
-
expect(listBranches).toHaveBeenCalledWith('
|
|
433
|
+
expect(listBranches).toHaveBeenCalledWith('myworkspace', 'my-repo', undefined, undefined, 'json');
|
|
518
434
|
|
|
519
435
|
consoleLogSpy.mockRestore();
|
|
520
436
|
});
|
|
@@ -537,7 +453,7 @@ describe('cli/wrapper', () => {
|
|
|
537
453
|
|
|
538
454
|
await cli['runCommand']('test-connection', '{}');
|
|
539
455
|
|
|
540
|
-
expect(testConnection).toHaveBeenCalledWith(
|
|
456
|
+
expect(testConnection).toHaveBeenCalledWith();
|
|
541
457
|
|
|
542
458
|
consoleLogSpy.mockRestore();
|
|
543
459
|
});
|
|
@@ -549,19 +465,7 @@ describe('cli/wrapper', () => {
|
|
|
549
465
|
|
|
550
466
|
await cli['runCommand']('get-user', '{"userId":"5b10a2844c20165700ede21g"}');
|
|
551
467
|
|
|
552
|
-
expect(getUser).toHaveBeenCalledWith('
|
|
553
|
-
|
|
554
|
-
consoleLogSpy.mockRestore();
|
|
555
|
-
});
|
|
556
|
-
|
|
557
|
-
it('should use profile from args if provided', async () => {
|
|
558
|
-
const { listRepositories } = await import('../../../src/utils/index.js');
|
|
559
|
-
vi.mocked(listRepositories).mockResolvedValue({ success: true, result: '{}' });
|
|
560
|
-
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
561
|
-
|
|
562
|
-
await cli['runCommand']('list-repositories', '{"workspace":"myworkspace","profile":"staging"}');
|
|
563
|
-
|
|
564
|
-
expect(listRepositories).toHaveBeenCalledWith('staging', 'myworkspace', 'json');
|
|
468
|
+
expect(getUser).toHaveBeenCalledWith('5b10a2844c20165700ede21g', 'json');
|
|
565
469
|
|
|
566
470
|
consoleLogSpy.mockRestore();
|
|
567
471
|
});
|
|
@@ -573,19 +477,19 @@ describe('cli/wrapper', () => {
|
|
|
573
477
|
|
|
574
478
|
await cli['runCommand']('list-repositories', '{"workspace":"myworkspace","format":"toon"}');
|
|
575
479
|
|
|
576
|
-
expect(listRepositories).toHaveBeenCalledWith('
|
|
480
|
+
expect(listRepositories).toHaveBeenCalledWith('myworkspace', 'toon');
|
|
577
481
|
|
|
578
482
|
consoleLogSpy.mockRestore();
|
|
579
483
|
});
|
|
580
484
|
|
|
581
|
-
it('should use current
|
|
485
|
+
it('should use current format by default', async () => {
|
|
582
486
|
const { listRepositories } = await import('../../../src/utils/index.js');
|
|
583
487
|
vi.mocked(listRepositories).mockResolvedValue({ success: true, result: '{}' });
|
|
584
488
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
585
489
|
|
|
586
490
|
await cli['runCommand']('list-repositories', '{"workspace":"myworkspace"}');
|
|
587
491
|
|
|
588
|
-
expect(listRepositories).toHaveBeenCalledWith('
|
|
492
|
+
expect(listRepositories).toHaveBeenCalledWith('myworkspace', 'json');
|
|
589
493
|
|
|
590
494
|
consoleLogSpy.mockRestore();
|
|
591
495
|
});
|
|
@@ -643,11 +547,7 @@ describe('cli/wrapper', () => {
|
|
|
643
547
|
describe('printHelp', () => {
|
|
644
548
|
beforeEach(async () => {
|
|
645
549
|
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
646
|
-
vi.mocked(loadConfig).mockReturnValue(
|
|
647
|
-
profiles: { cloud: { email: 'test@test.com', apiToken: 'token123' } },
|
|
648
|
-
defaultProfile: 'cloud',
|
|
649
|
-
defaultFormat: 'json',
|
|
650
|
-
});
|
|
550
|
+
vi.mocked(loadConfig).mockReturnValue(mockConfig);
|
|
651
551
|
const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
652
552
|
await cli.connect();
|
|
653
553
|
consoleLogSpy.mockRestore();
|
|
@@ -659,7 +559,6 @@ describe('cli/wrapper', () => {
|
|
|
659
559
|
cli['printHelp']();
|
|
660
560
|
|
|
661
561
|
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Bitbucket CLI v0.0.0'));
|
|
662
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Profile: cloud'));
|
|
663
562
|
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Format: json'));
|
|
664
563
|
|
|
665
564
|
consoleLogSpy.mockRestore();
|
|
@@ -669,11 +568,7 @@ describe('cli/wrapper', () => {
|
|
|
669
568
|
describe('start', () => {
|
|
670
569
|
beforeEach(async () => {
|
|
671
570
|
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
672
|
-
vi.mocked(loadConfig).mockReturnValue(
|
|
673
|
-
profiles: { cloud: { email: 'test@test.com', apiToken: 'token123' } },
|
|
674
|
-
defaultProfile: 'cloud',
|
|
675
|
-
defaultFormat: 'json',
|
|
676
|
-
});
|
|
571
|
+
vi.mocked(loadConfig).mockReturnValue(mockConfig);
|
|
677
572
|
});
|
|
678
573
|
|
|
679
574
|
it('should setup readline event handlers', async () => {
|
|
@@ -699,11 +594,7 @@ describe('cli/wrapper', () => {
|
|
|
699
594
|
describe('disconnect', () => {
|
|
700
595
|
beforeEach(async () => {
|
|
701
596
|
const { loadConfig } = await import('../../../src/utils/index.js');
|
|
702
|
-
vi.mocked(loadConfig).mockReturnValue(
|
|
703
|
-
profiles: { cloud: { email: 'test@test.com', apiToken: 'token123' } },
|
|
704
|
-
defaultProfile: 'cloud',
|
|
705
|
-
defaultFormat: 'json',
|
|
706
|
-
});
|
|
597
|
+
vi.mocked(loadConfig).mockReturnValue(mockConfig);
|
|
707
598
|
});
|
|
708
599
|
|
|
709
600
|
it('should clear clients and close readline', async () => {
|