reviewflow 3.1.0 → 3.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/CHANGELOG.md +16 -0
- package/README.md +38 -13
- package/dist/cli/formatters/initSummary.d.ts +11 -0
- package/dist/cli/formatters/initSummary.d.ts.map +1 -0
- package/dist/cli/formatters/initSummary.js +35 -0
- package/dist/cli/formatters/initSummary.js.map +1 -0
- package/dist/cli/parseCliArgs.d.ts +12 -1
- package/dist/cli/parseCliArgs.d.ts.map +1 -1
- package/dist/cli/parseCliArgs.js +29 -1
- package/dist/cli/parseCliArgs.js.map +1 -1
- package/dist/frameworks/config/configLoader.d.ts.map +1 -1
- package/dist/frameworks/config/configLoader.js +22 -3
- package/dist/frameworks/config/configLoader.js.map +1 -1
- package/dist/main/cli.d.ts +2 -0
- package/dist/main/cli.d.ts.map +1 -1
- package/dist/main/cli.js +233 -3
- package/dist/main/cli.js.map +1 -1
- package/dist/shared/services/configDir.d.ts +2 -0
- package/dist/shared/services/configDir.d.ts.map +1 -0
- package/dist/shared/services/configDir.js +20 -0
- package/dist/shared/services/configDir.js.map +1 -0
- package/dist/shared/services/secretGenerator.d.ts +6 -0
- package/dist/shared/services/secretGenerator.d.ts.map +1 -0
- package/dist/shared/services/secretGenerator.js +13 -0
- package/dist/shared/services/secretGenerator.js.map +1 -0
- package/dist/tests/units/cli/formatters/initSummary.test.d.ts +2 -0
- package/dist/tests/units/cli/formatters/initSummary.test.d.ts.map +1 -0
- package/dist/tests/units/cli/formatters/initSummary.test.js +45 -0
- package/dist/tests/units/cli/formatters/initSummary.test.js.map +1 -0
- package/dist/tests/units/cli/parseCliArgs.test.js +63 -0
- package/dist/tests/units/cli/parseCliArgs.test.js.map +1 -1
- package/dist/tests/units/shared/services/configDir.test.d.ts +2 -0
- package/dist/tests/units/shared/services/configDir.test.d.ts.map +1 -0
- package/dist/tests/units/shared/services/configDir.test.js +42 -0
- package/dist/tests/units/shared/services/configDir.test.js.map +1 -0
- package/dist/tests/units/shared/services/secretGenerator.test.d.ts +2 -0
- package/dist/tests/units/shared/services/secretGenerator.test.d.ts.map +1 -0
- package/dist/tests/units/shared/services/secretGenerator.test.js +46 -0
- package/dist/tests/units/shared/services/secretGenerator.test.js.map +1 -0
- package/dist/tests/units/usecases/cli/configureMcp.usecase.test.d.ts +2 -0
- package/dist/tests/units/usecases/cli/configureMcp.usecase.test.d.ts.map +1 -0
- package/dist/tests/units/usecases/cli/configureMcp.usecase.test.js +94 -0
- package/dist/tests/units/usecases/cli/configureMcp.usecase.test.js.map +1 -0
- package/dist/tests/units/usecases/cli/discoverRepositories.usecase.test.d.ts +2 -0
- package/dist/tests/units/usecases/cli/discoverRepositories.usecase.test.d.ts.map +1 -0
- package/dist/tests/units/usecases/cli/discoverRepositories.usecase.test.js +193 -0
- package/dist/tests/units/usecases/cli/discoverRepositories.usecase.test.js.map +1 -0
- package/dist/tests/units/usecases/cli/validateConfig.usecase.test.d.ts +2 -0
- package/dist/tests/units/usecases/cli/validateConfig.usecase.test.d.ts.map +1 -0
- package/dist/tests/units/usecases/cli/validateConfig.usecase.test.js +119 -0
- package/dist/tests/units/usecases/cli/validateConfig.usecase.test.js.map +1 -0
- package/dist/tests/units/usecases/cli/writeInitConfig.usecase.test.d.ts +2 -0
- package/dist/tests/units/usecases/cli/writeInitConfig.usecase.test.d.ts.map +1 -0
- package/dist/tests/units/usecases/cli/writeInitConfig.usecase.test.js +75 -0
- package/dist/tests/units/usecases/cli/writeInitConfig.usecase.test.js.map +1 -0
- package/dist/usecases/cli/configureMcp.usecase.d.ts +16 -0
- package/dist/usecases/cli/configureMcp.usecase.d.ts.map +1 -0
- package/dist/usecases/cli/configureMcp.usecase.js +36 -0
- package/dist/usecases/cli/configureMcp.usecase.js.map +1 -0
- package/dist/usecases/cli/discoverRepositories.usecase.d.ts +34 -0
- package/dist/usecases/cli/discoverRepositories.usecase.d.ts.map +1 -0
- package/dist/usecases/cli/discoverRepositories.usecase.js +67 -0
- package/dist/usecases/cli/discoverRepositories.usecase.js.map +1 -0
- package/dist/usecases/cli/validateConfig.usecase.d.ts +28 -0
- package/dist/usecases/cli/validateConfig.usecase.d.ts.map +1 -0
- package/dist/usecases/cli/validateConfig.usecase.js +74 -0
- package/dist/usecases/cli/validateConfig.usecase.js.map +1 -0
- package/dist/usecases/cli/writeInitConfig.usecase.d.ts +31 -0
- package/dist/usecases/cli/writeInitConfig.usecase.d.ts.map +1 -0
- package/dist/usecases/cli/writeInitConfig.usecase.js +37 -0
- package/dist/usecases/cli/writeInitConfig.usecase.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { DiscoverRepositoriesUseCase, } from '../../../../usecases/cli/discoverRepositories.usecase.js';
|
|
3
|
+
function createFakeDeps(overrides) {
|
|
4
|
+
return {
|
|
5
|
+
existsSync: vi.fn(() => false),
|
|
6
|
+
readdirSync: vi.fn(() => []),
|
|
7
|
+
getGitRemoteUrl: vi.fn(() => null),
|
|
8
|
+
...overrides,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function createFakeInput(overrides) {
|
|
12
|
+
return {
|
|
13
|
+
scanPaths: ['/home/user/projects'],
|
|
14
|
+
maxDepth: 3,
|
|
15
|
+
...overrides,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
describe('DiscoverRepositoriesUseCase', () => {
|
|
19
|
+
it('should return empty results when scan paths do not exist', () => {
|
|
20
|
+
const deps = createFakeDeps({ existsSync: vi.fn(() => false) });
|
|
21
|
+
const usecase = new DiscoverRepositoriesUseCase(deps);
|
|
22
|
+
const result = usecase.execute(createFakeInput());
|
|
23
|
+
expect(result.repositories).toEqual([]);
|
|
24
|
+
expect(result.skippedPaths).toContain('/home/user/projects');
|
|
25
|
+
});
|
|
26
|
+
it('should discover a repository with .git directory', () => {
|
|
27
|
+
const deps = createFakeDeps({
|
|
28
|
+
existsSync: vi.fn((path) => {
|
|
29
|
+
if (path === '/home/user/projects')
|
|
30
|
+
return true;
|
|
31
|
+
if (path === '/home/user/projects/my-app/.git')
|
|
32
|
+
return true;
|
|
33
|
+
return false;
|
|
34
|
+
}),
|
|
35
|
+
readdirSync: vi.fn((path) => {
|
|
36
|
+
if (path === '/home/user/projects') {
|
|
37
|
+
return [
|
|
38
|
+
{ name: 'my-app', isDirectory: () => true },
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
return [];
|
|
42
|
+
}),
|
|
43
|
+
getGitRemoteUrl: vi.fn(() => 'https://github.com/user/my-app'),
|
|
44
|
+
});
|
|
45
|
+
const usecase = new DiscoverRepositoriesUseCase(deps);
|
|
46
|
+
const result = usecase.execute(createFakeInput());
|
|
47
|
+
expect(result.repositories).toHaveLength(1);
|
|
48
|
+
expect(result.repositories[0]).toEqual({
|
|
49
|
+
name: 'my-app',
|
|
50
|
+
localPath: '/home/user/projects/my-app',
|
|
51
|
+
platform: 'github',
|
|
52
|
+
remoteUrl: 'https://github.com/user/my-app',
|
|
53
|
+
hasReviewConfig: false,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
it('should detect gitlab platform from remote url', () => {
|
|
57
|
+
const deps = createFakeDeps({
|
|
58
|
+
existsSync: vi.fn((path) => {
|
|
59
|
+
if (path === '/projects')
|
|
60
|
+
return true;
|
|
61
|
+
if (path === '/projects/repo/.git')
|
|
62
|
+
return true;
|
|
63
|
+
return false;
|
|
64
|
+
}),
|
|
65
|
+
readdirSync: vi.fn((path) => {
|
|
66
|
+
if (path === '/projects') {
|
|
67
|
+
return [{ name: 'repo', isDirectory: () => true }];
|
|
68
|
+
}
|
|
69
|
+
return [];
|
|
70
|
+
}),
|
|
71
|
+
getGitRemoteUrl: vi.fn(() => 'https://gitlab.com/team/repo'),
|
|
72
|
+
});
|
|
73
|
+
const usecase = new DiscoverRepositoriesUseCase(deps);
|
|
74
|
+
const result = usecase.execute(createFakeInput({ scanPaths: ['/projects'] }));
|
|
75
|
+
expect(result.repositories[0].platform).toBe('gitlab');
|
|
76
|
+
});
|
|
77
|
+
it('should detect review config presence', () => {
|
|
78
|
+
const deps = createFakeDeps({
|
|
79
|
+
existsSync: vi.fn((path) => {
|
|
80
|
+
if (path === '/projects')
|
|
81
|
+
return true;
|
|
82
|
+
if (path === '/projects/repo/.git')
|
|
83
|
+
return true;
|
|
84
|
+
if (path === '/projects/repo/.claude/reviews/config.json')
|
|
85
|
+
return true;
|
|
86
|
+
return false;
|
|
87
|
+
}),
|
|
88
|
+
readdirSync: vi.fn((path) => {
|
|
89
|
+
if (path === '/projects') {
|
|
90
|
+
return [{ name: 'repo', isDirectory: () => true }];
|
|
91
|
+
}
|
|
92
|
+
return [];
|
|
93
|
+
}),
|
|
94
|
+
getGitRemoteUrl: vi.fn(() => 'https://github.com/user/repo'),
|
|
95
|
+
});
|
|
96
|
+
const usecase = new DiscoverRepositoriesUseCase(deps);
|
|
97
|
+
const result = usecase.execute(createFakeInput({ scanPaths: ['/projects'] }));
|
|
98
|
+
expect(result.repositories[0].hasReviewConfig).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
it('should skip hidden directories', () => {
|
|
101
|
+
const deps = createFakeDeps({
|
|
102
|
+
existsSync: vi.fn((path) => {
|
|
103
|
+
if (path === '/projects')
|
|
104
|
+
return true;
|
|
105
|
+
return false;
|
|
106
|
+
}),
|
|
107
|
+
readdirSync: vi.fn((path) => {
|
|
108
|
+
if (path === '/projects') {
|
|
109
|
+
return [
|
|
110
|
+
{ name: '.hidden', isDirectory: () => true },
|
|
111
|
+
{ name: 'node_modules', isDirectory: () => true },
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
return [];
|
|
115
|
+
}),
|
|
116
|
+
});
|
|
117
|
+
const usecase = new DiscoverRepositoriesUseCase(deps);
|
|
118
|
+
const result = usecase.execute(createFakeInput({ scanPaths: ['/projects'] }));
|
|
119
|
+
expect(result.repositories).toEqual([]);
|
|
120
|
+
});
|
|
121
|
+
it('should respect maxDepth limit', () => {
|
|
122
|
+
const deps = createFakeDeps({
|
|
123
|
+
existsSync: vi.fn((path) => {
|
|
124
|
+
if (path === '/projects')
|
|
125
|
+
return true;
|
|
126
|
+
if (path === '/projects/level1/level2/level3/deep-repo/.git')
|
|
127
|
+
return true;
|
|
128
|
+
return false;
|
|
129
|
+
}),
|
|
130
|
+
readdirSync: vi.fn((path) => {
|
|
131
|
+
if (path === '/projects') {
|
|
132
|
+
return [{ name: 'level1', isDirectory: () => true }];
|
|
133
|
+
}
|
|
134
|
+
if (path === '/projects/level1') {
|
|
135
|
+
return [{ name: 'level2', isDirectory: () => true }];
|
|
136
|
+
}
|
|
137
|
+
return [];
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
const usecase = new DiscoverRepositoriesUseCase(deps);
|
|
141
|
+
const result = usecase.execute(createFakeInput({ maxDepth: 1 }));
|
|
142
|
+
expect(result.repositories).toEqual([]);
|
|
143
|
+
});
|
|
144
|
+
it('should handle repos without remote url', () => {
|
|
145
|
+
const deps = createFakeDeps({
|
|
146
|
+
existsSync: vi.fn((path) => {
|
|
147
|
+
if (path === '/projects')
|
|
148
|
+
return true;
|
|
149
|
+
if (path === '/projects/local-only/.git')
|
|
150
|
+
return true;
|
|
151
|
+
return false;
|
|
152
|
+
}),
|
|
153
|
+
readdirSync: vi.fn((path) => {
|
|
154
|
+
if (path === '/projects') {
|
|
155
|
+
return [{ name: 'local-only', isDirectory: () => true }];
|
|
156
|
+
}
|
|
157
|
+
return [];
|
|
158
|
+
}),
|
|
159
|
+
getGitRemoteUrl: vi.fn(() => null),
|
|
160
|
+
});
|
|
161
|
+
const usecase = new DiscoverRepositoriesUseCase(deps);
|
|
162
|
+
const result = usecase.execute(createFakeInput({ scanPaths: ['/projects'] }));
|
|
163
|
+
expect(result.repositories).toHaveLength(1);
|
|
164
|
+
expect(result.repositories[0].platform).toBeNull();
|
|
165
|
+
expect(result.repositories[0].remoteUrl).toBeNull();
|
|
166
|
+
});
|
|
167
|
+
it('should scan multiple paths', () => {
|
|
168
|
+
const deps = createFakeDeps({
|
|
169
|
+
existsSync: vi.fn((path) => {
|
|
170
|
+
if (path === '/path-a' || path === '/path-b')
|
|
171
|
+
return true;
|
|
172
|
+
if (path === '/path-a/repo1/.git')
|
|
173
|
+
return true;
|
|
174
|
+
if (path === '/path-b/repo2/.git')
|
|
175
|
+
return true;
|
|
176
|
+
return false;
|
|
177
|
+
}),
|
|
178
|
+
readdirSync: vi.fn((path) => {
|
|
179
|
+
if (path === '/path-a')
|
|
180
|
+
return [{ name: 'repo1', isDirectory: () => true }];
|
|
181
|
+
if (path === '/path-b')
|
|
182
|
+
return [{ name: 'repo2', isDirectory: () => true }];
|
|
183
|
+
return [];
|
|
184
|
+
}),
|
|
185
|
+
getGitRemoteUrl: vi.fn(() => 'https://github.com/user/repo'),
|
|
186
|
+
});
|
|
187
|
+
const usecase = new DiscoverRepositoriesUseCase(deps);
|
|
188
|
+
const result = usecase.execute(createFakeInput({ scanPaths: ['/path-a', '/path-b'] }));
|
|
189
|
+
expect(result.repositories).toHaveLength(2);
|
|
190
|
+
expect(result.scannedPaths).toEqual(['/path-a', '/path-b']);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
//# sourceMappingURL=discoverRepositories.usecase.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discoverRepositories.usecase.test.js","sourceRoot":"","sources":["../../../../../src/tests/units/usecases/cli/discoverRepositories.usecase.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateConfig.usecase.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/units/usecases/cli/validateConfig.usecase.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { ValidateConfigUseCase, } from '../../../../usecases/cli/validateConfig.usecase.js';
|
|
3
|
+
function createFakeDeps(overrides) {
|
|
4
|
+
return {
|
|
5
|
+
existsSync: vi.fn(() => true),
|
|
6
|
+
readFileSync: vi.fn(() => JSON.stringify({
|
|
7
|
+
server: { port: 3847 },
|
|
8
|
+
user: { gitlabUsername: 'user', githubUsername: 'user' },
|
|
9
|
+
queue: { maxConcurrent: 2, deduplicationWindowMs: 300000 },
|
|
10
|
+
repositories: [],
|
|
11
|
+
})),
|
|
12
|
+
...overrides,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
describe('ValidateConfigUseCase', () => {
|
|
16
|
+
it('should return not-found when config file does not exist', () => {
|
|
17
|
+
const deps = createFakeDeps({ existsSync: vi.fn(() => false) });
|
|
18
|
+
const usecase = new ValidateConfigUseCase(deps);
|
|
19
|
+
const result = usecase.execute({ configPath: '/missing/config.json', envPath: '/missing/.env' });
|
|
20
|
+
expect(result.status).toBe('not-found');
|
|
21
|
+
});
|
|
22
|
+
it('should return valid for correct config', () => {
|
|
23
|
+
const deps = createFakeDeps();
|
|
24
|
+
const usecase = new ValidateConfigUseCase(deps);
|
|
25
|
+
const result = usecase.execute({
|
|
26
|
+
configPath: '/home/user/.config/reviewflow/config.json',
|
|
27
|
+
envPath: '/home/user/.config/reviewflow/.env',
|
|
28
|
+
});
|
|
29
|
+
expect(result.status).toBe('valid');
|
|
30
|
+
expect(result.issues).toHaveLength(0);
|
|
31
|
+
});
|
|
32
|
+
it('should detect invalid JSON', () => {
|
|
33
|
+
const deps = createFakeDeps({
|
|
34
|
+
readFileSync: vi.fn((path) => {
|
|
35
|
+
if (path.endsWith('config.json'))
|
|
36
|
+
return 'not json{';
|
|
37
|
+
return 'GITLAB_WEBHOOK_TOKEN=abc\nGITHUB_WEBHOOK_SECRET=def';
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
const usecase = new ValidateConfigUseCase(deps);
|
|
41
|
+
const result = usecase.execute({
|
|
42
|
+
configPath: '/config.json',
|
|
43
|
+
envPath: '/.env',
|
|
44
|
+
});
|
|
45
|
+
expect(result.status).toBe('invalid');
|
|
46
|
+
expect(result.issues.some(i => i.field === 'config.json')).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
it('should detect invalid port', () => {
|
|
49
|
+
const deps = createFakeDeps({
|
|
50
|
+
readFileSync: vi.fn((path) => {
|
|
51
|
+
if (path.endsWith('config.json')) {
|
|
52
|
+
return JSON.stringify({
|
|
53
|
+
server: { port: 99999 },
|
|
54
|
+
user: { gitlabUsername: 'u', githubUsername: 'u' },
|
|
55
|
+
queue: { maxConcurrent: 2, deduplicationWindowMs: 300000 },
|
|
56
|
+
repositories: [],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return 'GITLAB_WEBHOOK_TOKEN=abc\nGITHUB_WEBHOOK_SECRET=def';
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
const usecase = new ValidateConfigUseCase(deps);
|
|
63
|
+
const result = usecase.execute({ configPath: '/config.json', envPath: '/.env' });
|
|
64
|
+
expect(result.status).toBe('invalid');
|
|
65
|
+
expect(result.issues.some(i => i.field === 'server.port')).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('should detect missing .env file', () => {
|
|
68
|
+
const deps = createFakeDeps({
|
|
69
|
+
existsSync: vi.fn((path) => !path.endsWith('.env')),
|
|
70
|
+
readFileSync: vi.fn(() => JSON.stringify({
|
|
71
|
+
server: { port: 3847 },
|
|
72
|
+
user: { gitlabUsername: 'u', githubUsername: 'u' },
|
|
73
|
+
queue: { maxConcurrent: 2, deduplicationWindowMs: 300000 },
|
|
74
|
+
repositories: [],
|
|
75
|
+
})),
|
|
76
|
+
});
|
|
77
|
+
const usecase = new ValidateConfigUseCase(deps);
|
|
78
|
+
const result = usecase.execute({ configPath: '/config.json', envPath: '/.env' });
|
|
79
|
+
expect(result.status).toBe('invalid');
|
|
80
|
+
expect(result.issues.some(i => i.field === '.env')).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
it('should detect missing required fields', () => {
|
|
83
|
+
const deps = createFakeDeps({
|
|
84
|
+
readFileSync: vi.fn((path) => {
|
|
85
|
+
if (path.endsWith('config.json')) {
|
|
86
|
+
return JSON.stringify({ server: { port: 3847 } });
|
|
87
|
+
}
|
|
88
|
+
return 'GITLAB_WEBHOOK_TOKEN=abc\nGITHUB_WEBHOOK_SECRET=def';
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
const usecase = new ValidateConfigUseCase(deps);
|
|
92
|
+
const result = usecase.execute({ configPath: '/config.json', envPath: '/.env' });
|
|
93
|
+
expect(result.status).toBe('invalid');
|
|
94
|
+
expect(result.issues.some(i => i.field === 'user')).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
it('should detect non-existent repository paths', () => {
|
|
97
|
+
const deps = createFakeDeps({
|
|
98
|
+
existsSync: vi.fn((path) => !path.startsWith('/nonexistent')),
|
|
99
|
+
readFileSync: vi.fn((path) => {
|
|
100
|
+
if (path.endsWith('config.json')) {
|
|
101
|
+
return JSON.stringify({
|
|
102
|
+
server: { port: 3847 },
|
|
103
|
+
user: { gitlabUsername: 'u', githubUsername: 'u' },
|
|
104
|
+
queue: { maxConcurrent: 2, deduplicationWindowMs: 300000 },
|
|
105
|
+
repositories: [
|
|
106
|
+
{ name: 'repo', localPath: '/nonexistent/repo', enabled: true },
|
|
107
|
+
],
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return 'GITLAB_WEBHOOK_TOKEN=abc\nGITHUB_WEBHOOK_SECRET=def';
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
const usecase = new ValidateConfigUseCase(deps);
|
|
114
|
+
const result = usecase.execute({ configPath: '/config.json', envPath: '/.env' });
|
|
115
|
+
expect(result.status).toBe('invalid');
|
|
116
|
+
expect(result.issues.some(i => i.field === 'repositories')).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=validateConfig.usecase.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateConfig.usecase.test.js","sourceRoot":"","sources":["../../../../../src/tests/units/usecases/cli/validateConfig.usecase.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeInitConfig.usecase.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/units/usecases/cli/writeInitConfig.usecase.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { WriteInitConfigUseCase, } from '../../../../usecases/cli/writeInitConfig.usecase.js';
|
|
3
|
+
function createFakeDeps(overrides) {
|
|
4
|
+
return {
|
|
5
|
+
mkdirSync: vi.fn(),
|
|
6
|
+
writeFileSync: vi.fn(),
|
|
7
|
+
...overrides,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function createFakeInput(overrides) {
|
|
11
|
+
return {
|
|
12
|
+
configDir: '/home/user/.config/reviewflow',
|
|
13
|
+
port: 3847,
|
|
14
|
+
gitlabUsername: 'damien',
|
|
15
|
+
githubUsername: 'DGouron',
|
|
16
|
+
repositories: [
|
|
17
|
+
{ name: 'my-app', localPath: '/home/user/projects/my-app', enabled: true },
|
|
18
|
+
],
|
|
19
|
+
gitlabWebhookSecret: 'abc123',
|
|
20
|
+
githubWebhookSecret: 'def456',
|
|
21
|
+
...overrides,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
describe('WriteInitConfigUseCase', () => {
|
|
25
|
+
it('should create config directory recursively', () => {
|
|
26
|
+
const deps = createFakeDeps();
|
|
27
|
+
const usecase = new WriteInitConfigUseCase(deps);
|
|
28
|
+
usecase.execute(createFakeInput());
|
|
29
|
+
expect(deps.mkdirSync).toHaveBeenCalledWith('/home/user/.config/reviewflow', { recursive: true });
|
|
30
|
+
});
|
|
31
|
+
it('should write config.json with correct structure', () => {
|
|
32
|
+
const deps = createFakeDeps();
|
|
33
|
+
const usecase = new WriteInitConfigUseCase(deps);
|
|
34
|
+
const result = usecase.execute(createFakeInput());
|
|
35
|
+
const writeCall = deps.writeFileSync.mock.calls.find((call) => call[0].endsWith('config.json'));
|
|
36
|
+
expect(writeCall).toBeDefined();
|
|
37
|
+
const config = JSON.parse(writeCall[1]);
|
|
38
|
+
expect(config.server.port).toBe(3847);
|
|
39
|
+
expect(config.user.gitlabUsername).toBe('damien');
|
|
40
|
+
expect(config.user.githubUsername).toBe('DGouron');
|
|
41
|
+
expect(config.queue.maxConcurrent).toBe(2);
|
|
42
|
+
expect(config.repositories).toHaveLength(1);
|
|
43
|
+
expect(result.configPath).toContain('config.json');
|
|
44
|
+
});
|
|
45
|
+
it('should write .env file with webhook secrets', () => {
|
|
46
|
+
const deps = createFakeDeps();
|
|
47
|
+
const usecase = new WriteInitConfigUseCase(deps);
|
|
48
|
+
const result = usecase.execute(createFakeInput());
|
|
49
|
+
const writeCall = deps.writeFileSync.mock.calls.find((call) => call[0].endsWith('.env'));
|
|
50
|
+
expect(writeCall).toBeDefined();
|
|
51
|
+
const envContent = writeCall[1];
|
|
52
|
+
expect(envContent).toContain('GITLAB_WEBHOOK_TOKEN=abc123');
|
|
53
|
+
expect(envContent).toContain('GITHUB_WEBHOOK_SECRET=def456');
|
|
54
|
+
expect(result.envPath).toContain('.env');
|
|
55
|
+
});
|
|
56
|
+
it('should handle empty repositories', () => {
|
|
57
|
+
const deps = createFakeDeps();
|
|
58
|
+
const usecase = new WriteInitConfigUseCase(deps);
|
|
59
|
+
const result = usecase.execute(createFakeInput({ repositories: [] }));
|
|
60
|
+
const writeCall = deps.writeFileSync.mock.calls.find((call) => call[0].endsWith('config.json'));
|
|
61
|
+
const config = JSON.parse(writeCall[1]);
|
|
62
|
+
expect(config.repositories).toEqual([]);
|
|
63
|
+
expect(result.configPath).toBeDefined();
|
|
64
|
+
});
|
|
65
|
+
it('should use empty string for omitted usernames', () => {
|
|
66
|
+
const deps = createFakeDeps();
|
|
67
|
+
const usecase = new WriteInitConfigUseCase(deps);
|
|
68
|
+
usecase.execute(createFakeInput({ gitlabUsername: '', githubUsername: '' }));
|
|
69
|
+
const writeCall = deps.writeFileSync.mock.calls.find((call) => call[0].endsWith('config.json'));
|
|
70
|
+
const config = JSON.parse(writeCall[1]);
|
|
71
|
+
expect(config.user.gitlabUsername).toBe('');
|
|
72
|
+
expect(config.user.githubUsername).toBe('');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=writeInitConfig.usecase.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeInitConfig.usecase.test.js","sourceRoot":"","sources":["../../../../../src/tests/units/usecases/cli/writeInitConfig.usecase.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ConfigureMcpResult = 'configured' | 'already-configured' | 'claude-not-found' | 'failed';
|
|
2
|
+
export interface ConfigureMcpDependencies {
|
|
3
|
+
isClaudeInstalled: () => boolean;
|
|
4
|
+
readFileSync: (path: string, encoding: string) => string;
|
|
5
|
+
writeFileSync: (path: string, content: string) => void;
|
|
6
|
+
existsSync: (path: string) => boolean;
|
|
7
|
+
copyFileSync: (src: string, dest: string) => void;
|
|
8
|
+
resolveMcpServerPath: () => string;
|
|
9
|
+
settingsPath: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class ConfigureMcpUseCase {
|
|
12
|
+
private readonly deps;
|
|
13
|
+
constructor(deps: ConfigureMcpDependencies);
|
|
14
|
+
execute(): ConfigureMcpResult;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=configureMcp.usecase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configureMcp.usecase.d.ts","sourceRoot":"","sources":["../../../src/usecases/cli/configureMcp.usecase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,oBAAoB,GAAG,kBAAkB,GAAG,QAAQ,CAAC;AAErG,MAAM,WAAW,wBAAwB;IACvC,iBAAiB,EAAE,MAAM,OAAO,CAAC;IACjC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,oBAAoB,EAAE,MAAM,MAAM,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,wBAAwB;IAE3D,OAAO,IAAI,kBAAkB;CA4C9B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export class ConfigureMcpUseCase {
|
|
2
|
+
deps;
|
|
3
|
+
constructor(deps) {
|
|
4
|
+
this.deps = deps;
|
|
5
|
+
}
|
|
6
|
+
execute() {
|
|
7
|
+
if (!this.deps.isClaudeInstalled()) {
|
|
8
|
+
return 'claude-not-found';
|
|
9
|
+
}
|
|
10
|
+
const mcpServerPath = this.deps.resolveMcpServerPath();
|
|
11
|
+
let settings;
|
|
12
|
+
try {
|
|
13
|
+
const content = this.deps.readFileSync(this.deps.settingsPath, 'utf-8');
|
|
14
|
+
settings = JSON.parse(content);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
settings = {};
|
|
18
|
+
}
|
|
19
|
+
const mcpServers = (settings.mcpServers ?? {});
|
|
20
|
+
const existing = mcpServers['review-progress'];
|
|
21
|
+
if (existing?.args?.[0] === mcpServerPath) {
|
|
22
|
+
return 'already-configured';
|
|
23
|
+
}
|
|
24
|
+
if (this.deps.existsSync(this.deps.settingsPath)) {
|
|
25
|
+
this.deps.copyFileSync(this.deps.settingsPath, `${this.deps.settingsPath}.bak`);
|
|
26
|
+
}
|
|
27
|
+
mcpServers['review-progress'] = {
|
|
28
|
+
command: 'node',
|
|
29
|
+
args: [mcpServerPath],
|
|
30
|
+
};
|
|
31
|
+
settings.mcpServers = mcpServers;
|
|
32
|
+
this.deps.writeFileSync(this.deps.settingsPath, JSON.stringify(settings, null, 2));
|
|
33
|
+
return 'configured';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=configureMcp.usecase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configureMcp.usecase.js","sourceRoot":"","sources":["../../../src/usecases/cli/configureMcp.usecase.ts"],"names":[],"mappings":"AAYA,MAAM,OAAO,mBAAmB;IACD;IAA7B,YAA6B,IAA8B;QAA9B,SAAI,GAAJ,IAAI,CAA0B;IAAG,CAAC;IAE/D,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;YACnC,OAAO,kBAAkB,CAAC;QAC5B,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QACvD,IAAI,QAAiC,CAAC;QAEtC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACxE,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,UAAU,GAAG,CAAC,QAAQ,CAAC,UAAU,IAAI,EAAE,CAA4B,CAAC;QAC1E,MAAM,QAAQ,GAAG,UAAU,CAAC,iBAAiB,CAEhC,CAAC;QAEd,IAAI,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,aAAa,EAAE,CAAC;YAC1C,OAAO,oBAAoB,CAAC;QAC9B,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,IAAI,CAAC,YAAY,CACpB,IAAI,CAAC,IAAI,CAAC,YAAY,EACtB,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,MAAM,CAChC,CAAC;QACJ,CAAC;QAED,UAAU,CAAC,iBAAiB,CAAC,GAAG;YAC9B,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,CAAC,aAAa,CAAC;SACtB,CAAC;QACF,QAAQ,CAAC,UAAU,GAAG,UAAU,CAAC;QAEjC,IAAI,CAAC,IAAI,CAAC,aAAa,CACrB,IAAI,CAAC,IAAI,CAAC,YAAY,EACtB,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAClC,CAAC;QAEF,OAAO,YAAY,CAAC;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { UseCase } from '../../shared/foundation/usecase.base.js';
|
|
2
|
+
interface DirEntry {
|
|
3
|
+
name: string;
|
|
4
|
+
isDirectory: () => boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface DiscoverRepositoriesDependencies {
|
|
7
|
+
existsSync: (path: string) => boolean;
|
|
8
|
+
readdirSync: (path: string) => DirEntry[];
|
|
9
|
+
getGitRemoteUrl: (localPath: string) => string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface DiscoverRepositoriesInput {
|
|
12
|
+
scanPaths: string[];
|
|
13
|
+
maxDepth: number;
|
|
14
|
+
}
|
|
15
|
+
export interface DiscoveredRepository {
|
|
16
|
+
name: string;
|
|
17
|
+
localPath: string;
|
|
18
|
+
platform: 'gitlab' | 'github' | null;
|
|
19
|
+
remoteUrl: string | null;
|
|
20
|
+
hasReviewConfig: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface DiscoverRepositoriesResult {
|
|
23
|
+
repositories: DiscoveredRepository[];
|
|
24
|
+
scannedPaths: string[];
|
|
25
|
+
skippedPaths: string[];
|
|
26
|
+
}
|
|
27
|
+
export declare class DiscoverRepositoriesUseCase implements UseCase<DiscoverRepositoriesInput, DiscoverRepositoriesResult> {
|
|
28
|
+
private readonly deps;
|
|
29
|
+
constructor(deps: DiscoverRepositoriesDependencies);
|
|
30
|
+
execute(input: DiscoverRepositoriesInput): DiscoverRepositoriesResult;
|
|
31
|
+
private scan;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=discoverRepositories.usecase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discoverRepositories.usecase.d.ts","sourceRoot":"","sources":["../../../src/usecases/cli/discoverRepositories.usecase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAEvE,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,gCAAgC;IAC/C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;IAC1C,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAcD,qBAAa,2BACX,YAAW,OAAO,CAAC,yBAAyB,EAAE,0BAA0B,CAAC;IAE7D,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,gCAAgC;IAEnE,OAAO,CAAC,KAAK,EAAE,yBAAyB,GAAG,0BAA0B;IAiBrE,OAAO,CAAC,IAAI;CAqCb"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const IGNORED_DIRS = new Set([
|
|
2
|
+
'node_modules', '.git', '.vscode', '.idea', 'dist', 'build', '.cache',
|
|
3
|
+
]);
|
|
4
|
+
function detectPlatform(remoteUrl) {
|
|
5
|
+
if (!remoteUrl)
|
|
6
|
+
return null;
|
|
7
|
+
const lower = remoteUrl.toLowerCase();
|
|
8
|
+
if (lower.includes('gitlab'))
|
|
9
|
+
return 'gitlab';
|
|
10
|
+
if (lower.includes('github'))
|
|
11
|
+
return 'github';
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
export class DiscoverRepositoriesUseCase {
|
|
15
|
+
deps;
|
|
16
|
+
constructor(deps) {
|
|
17
|
+
this.deps = deps;
|
|
18
|
+
}
|
|
19
|
+
execute(input) {
|
|
20
|
+
const repositories = [];
|
|
21
|
+
const scannedPaths = [];
|
|
22
|
+
const skippedPaths = [];
|
|
23
|
+
for (const scanPath of input.scanPaths) {
|
|
24
|
+
if (!this.deps.existsSync(scanPath)) {
|
|
25
|
+
skippedPaths.push(scanPath);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
scannedPaths.push(scanPath);
|
|
29
|
+
this.scan(scanPath, 0, input.maxDepth, repositories);
|
|
30
|
+
}
|
|
31
|
+
return { repositories, scannedPaths, skippedPaths };
|
|
32
|
+
}
|
|
33
|
+
scan(dirPath, currentDepth, maxDepth, results) {
|
|
34
|
+
if (currentDepth >= maxDepth)
|
|
35
|
+
return;
|
|
36
|
+
let entries;
|
|
37
|
+
try {
|
|
38
|
+
entries = this.deps.readdirSync(dirPath);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
if (!entry.isDirectory())
|
|
45
|
+
continue;
|
|
46
|
+
if (entry.name.startsWith('.') || IGNORED_DIRS.has(entry.name))
|
|
47
|
+
continue;
|
|
48
|
+
const fullPath = `${dirPath}/${entry.name}`;
|
|
49
|
+
const gitPath = `${fullPath}/.git`;
|
|
50
|
+
if (this.deps.existsSync(gitPath)) {
|
|
51
|
+
const remoteUrl = this.deps.getGitRemoteUrl(fullPath);
|
|
52
|
+
const reviewConfigPath = `${fullPath}/.claude/reviews/config.json`;
|
|
53
|
+
results.push({
|
|
54
|
+
name: entry.name,
|
|
55
|
+
localPath: fullPath,
|
|
56
|
+
platform: detectPlatform(remoteUrl),
|
|
57
|
+
remoteUrl,
|
|
58
|
+
hasReviewConfig: this.deps.existsSync(reviewConfigPath),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.scan(fullPath, currentDepth + 1, maxDepth, results);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=discoverRepositories.usecase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discoverRepositories.usecase.js","sourceRoot":"","sources":["../../../src/usecases/cli/discoverRepositories.usecase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ValidateConfigDependencies {
|
|
2
|
+
existsSync: (path: string) => boolean;
|
|
3
|
+
readFileSync: (path: string, encoding: string) => string;
|
|
4
|
+
}
|
|
5
|
+
export interface ValidateConfigInput {
|
|
6
|
+
configPath: string;
|
|
7
|
+
envPath: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ValidationIssue {
|
|
10
|
+
field: string;
|
|
11
|
+
message: string;
|
|
12
|
+
severity: 'error' | 'warning';
|
|
13
|
+
}
|
|
14
|
+
export interface ValidateConfigResult {
|
|
15
|
+
status: 'valid' | 'invalid' | 'not-found';
|
|
16
|
+
issues: ValidationIssue[];
|
|
17
|
+
}
|
|
18
|
+
export declare class ValidateConfigUseCase {
|
|
19
|
+
private readonly deps;
|
|
20
|
+
constructor(deps: ValidateConfigDependencies);
|
|
21
|
+
execute(input: ValidateConfigInput): ValidateConfigResult;
|
|
22
|
+
private validateServer;
|
|
23
|
+
private validateUser;
|
|
24
|
+
private validateQueue;
|
|
25
|
+
private validateRepositories;
|
|
26
|
+
private validateEnv;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=validateConfig.usecase.d.ts.map
|