cadr-cli 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/analysis.orchestrator.test.d.ts +2 -0
- package/dist/analysis/analysis.orchestrator.test.d.ts.map +1 -0
- package/dist/analysis/analysis.orchestrator.test.js +177 -0
- package/dist/analysis/analysis.orchestrator.test.js.map +1 -0
- package/dist/analysis/strategies/git-strategy.test.d.ts +2 -0
- package/dist/analysis/strategies/git-strategy.test.d.ts.map +1 -0
- package/dist/analysis/strategies/git-strategy.test.js +147 -0
- package/dist/analysis/strategies/git-strategy.test.js.map +1 -0
- package/dist/commands/analyze.test.d.ts +2 -0
- package/dist/commands/analyze.test.d.ts.map +1 -0
- package/dist/commands/analyze.test.js +70 -0
- package/dist/commands/analyze.test.js.map +1 -0
- package/dist/commands/init.test.js +128 -2
- package/dist/commands/init.test.js.map +1 -1
- package/dist/config.test.js +167 -0
- package/dist/config.test.js.map +1 -1
- package/dist/git/git.errors.test.d.ts +2 -0
- package/dist/git/git.errors.test.d.ts.map +1 -0
- package/dist/git/git.errors.test.js +34 -0
- package/dist/git/git.errors.test.js.map +1 -0
- package/dist/git/git.operations.test.d.ts +2 -0
- package/dist/git/git.operations.test.d.ts.map +1 -0
- package/dist/git/git.operations.test.js +164 -0
- package/dist/git/git.operations.test.js.map +1 -0
- package/dist/llm/llm.test.d.ts +2 -0
- package/dist/llm/llm.test.d.ts.map +1 -0
- package/dist/llm/llm.test.js +224 -0
- package/dist/llm/llm.test.js.map +1 -0
- package/dist/llm/response-parser.test.d.ts +2 -0
- package/dist/llm/response-parser.test.d.ts.map +1 -0
- package/dist/llm/response-parser.test.js +134 -0
- package/dist/llm/response-parser.test.js.map +1 -0
- package/dist/presenters/console-presenter.test.d.ts +2 -0
- package/dist/presenters/console-presenter.test.d.ts.map +1 -0
- package/dist/presenters/console-presenter.test.js +227 -0
- package/dist/presenters/console-presenter.test.js.map +1 -0
- package/dist/version.test.d.ts +1 -2
- package/dist/version.test.d.ts.map +1 -1
- package/dist/version.test.js +29 -16
- package/dist/version.test.js.map +1 -1
- package/package.json +1 -1
- package/src/analysis/analysis.orchestrator.test.ts +237 -0
- package/src/analysis/strategies/git-strategy.test.ts +210 -0
- package/src/commands/analyze.test.ts +91 -0
- package/src/commands/init.test.ts +200 -5
- package/src/config.test.ts +232 -2
- package/src/git/git.errors.test.ts +43 -0
- package/src/git/git.operations.test.ts +222 -0
- package/src/llm/llm.test.ts +315 -0
- package/src/llm/response-parser.test.ts +170 -0
- package/src/presenters/console-presenter.test.ts +259 -0
- package/src/version.test.ts +30 -16
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console-presenter.test.js","sourceRoot":"","sources":["../../src/presenters/console-presenter.test.ts"],"names":[],"mappings":"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"}
|
package/dist/version.test.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.test.d.ts","sourceRoot":"","sources":["../src/version.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"version.test.d.ts","sourceRoot":"","sources":["../src/version.test.ts"],"names":[],"mappings":""}
|
package/dist/version.test.js
CHANGED
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("./index");
|
|
4
|
+
jest.mock('./commands/init', () => ({ initCommand: jest.fn() }));
|
|
5
|
+
jest.mock('./commands/analyze', () => ({ analyzeCommand: jest.fn() }));
|
|
6
|
+
jest.mock('./commands/status', () => ({ statusCommand: jest.fn() }));
|
|
7
|
+
describe('showVersion', () => {
|
|
8
|
+
let stdoutSpy;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
jest.clearAllMocks();
|
|
11
|
+
stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
8
12
|
});
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
stdoutSpy.mockRestore();
|
|
11
15
|
});
|
|
12
|
-
test('
|
|
13
|
-
|
|
16
|
+
test('writes to process.stdout', () => {
|
|
17
|
+
(0, index_1.showVersion)();
|
|
18
|
+
expect(stdoutSpy).toHaveBeenCalled();
|
|
14
19
|
});
|
|
15
|
-
test('
|
|
16
|
-
|
|
20
|
+
test('output contains cADR version', () => {
|
|
21
|
+
(0, index_1.showVersion)();
|
|
22
|
+
const output = stdoutSpy.mock.calls[0][0];
|
|
23
|
+
expect(output).toContain('cADR version');
|
|
17
24
|
});
|
|
18
|
-
test('
|
|
19
|
-
|
|
25
|
+
test('output version string matches semver pattern', () => {
|
|
26
|
+
(0, index_1.showVersion)();
|
|
27
|
+
const output = stdoutSpy.mock.calls[0][0];
|
|
28
|
+
expect(output).toMatch(/\d+\.\d+\.\d+/);
|
|
20
29
|
});
|
|
21
|
-
test('
|
|
22
|
-
|
|
30
|
+
test('output contains the version from package.json', () => {
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
32
|
+
const pkg = require('../package.json');
|
|
33
|
+
(0, index_1.showVersion)();
|
|
34
|
+
const output = stdoutSpy.mock.calls[0][0];
|
|
35
|
+
expect(output).toContain(pkg.version);
|
|
23
36
|
});
|
|
24
37
|
});
|
|
25
38
|
//# sourceMappingURL=version.test.js.map
|
package/dist/version.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.test.js","sourceRoot":"","sources":["../src/version.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"version.test.js","sourceRoot":"","sources":["../src/version.test.ts"],"names":[],"mappings":";;AAAA,mCAAsC;AAEtC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACjE,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACvE,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAErE,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,IAAI,SAA2B,CAAC;IAEhC,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,SAAS,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACpC,IAAA,mBAAW,GAAE,CAAC;QACd,MAAM,CAAC,SAAS,CAAC,CAAC,gBAAgB,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACxC,IAAA,mBAAW,GAAE,CAAC;QACd,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACxD,IAAA,mBAAW,GAAE,CAAC;QACd,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACzD,8DAA8D;QAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACvC,IAAA,mBAAW,GAAE,CAAC;QACd,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
jest.mock('../config');
|
|
2
|
+
jest.mock('../llm/prompts');
|
|
3
|
+
jest.mock('../llm/llm');
|
|
4
|
+
jest.mock('../logger');
|
|
5
|
+
jest.mock('../adr/adr');
|
|
6
|
+
jest.mock('./strategies/git-strategy');
|
|
7
|
+
jest.mock('../presenters/console-presenter');
|
|
8
|
+
|
|
9
|
+
import { loadConfig, getDefaultConfigPath } from '../config';
|
|
10
|
+
import {
|
|
11
|
+
formatPrompt,
|
|
12
|
+
formatGenerationPrompt,
|
|
13
|
+
promptForGeneration,
|
|
14
|
+
} from '../llm/prompts';
|
|
15
|
+
import { analyzeChanges, generateADRContent } from '../llm/llm';
|
|
16
|
+
import { saveADR } from '../adr/adr';
|
|
17
|
+
import { createGitStrategy } from './strategies/git-strategy';
|
|
18
|
+
import { presenter } from '../presenters/console-presenter';
|
|
19
|
+
import { runAnalysis } from './analysis.orchestrator';
|
|
20
|
+
|
|
21
|
+
const mockPresenter = presenter as jest.Mocked<typeof presenter>;
|
|
22
|
+
const mockStrategy = { getFiles: jest.fn(), getDiff: jest.fn() };
|
|
23
|
+
|
|
24
|
+
(createGitStrategy as jest.Mock).mockReturnValue(mockStrategy);
|
|
25
|
+
(getDefaultConfigPath as jest.Mock).mockReturnValue('cadr.yaml');
|
|
26
|
+
(formatPrompt as jest.Mock).mockReturnValue('formatted-prompt');
|
|
27
|
+
(formatGenerationPrompt as jest.Mock).mockReturnValue('formatted-generation-prompt');
|
|
28
|
+
|
|
29
|
+
const mockConfig = {
|
|
30
|
+
provider: 'openai' as const,
|
|
31
|
+
analysis_model: 'gpt-4',
|
|
32
|
+
api_key_env: 'KEY',
|
|
33
|
+
timeout_seconds: 15,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const defaultDiffOptions = { mode: 'all' as const };
|
|
37
|
+
|
|
38
|
+
function setupHappyPath(overrides?: { isSignificant?: boolean; confidence?: number }) {
|
|
39
|
+
const isSignificant = overrides?.isSignificant ?? true;
|
|
40
|
+
const confidence = overrides?.confidence ?? 0.9;
|
|
41
|
+
|
|
42
|
+
(loadConfig as jest.Mock).mockResolvedValue(mockConfig);
|
|
43
|
+
mockStrategy.getFiles.mockResolvedValue(['src/index.ts', 'src/utils.ts']);
|
|
44
|
+
mockStrategy.getDiff.mockResolvedValue('diff content here');
|
|
45
|
+
(analyzeChanges as jest.Mock).mockResolvedValue({
|
|
46
|
+
result: {
|
|
47
|
+
is_significant: isSignificant,
|
|
48
|
+
reason: 'Introduced new dependency',
|
|
49
|
+
confidence,
|
|
50
|
+
timestamp: '2026-01-01T00:00:00.000Z',
|
|
51
|
+
},
|
|
52
|
+
error: undefined,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe('runAnalysis', () => {
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
jest.clearAllMocks();
|
|
59
|
+
(createGitStrategy as jest.Mock).mockReturnValue(mockStrategy);
|
|
60
|
+
(getDefaultConfigPath as jest.Mock).mockReturnValue('cadr.yaml');
|
|
61
|
+
(formatPrompt as jest.Mock).mockReturnValue('formatted-prompt');
|
|
62
|
+
(formatGenerationPrompt as jest.Mock).mockReturnValue('formatted-generation-prompt');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should show config error and return early when loadConfig returns null', async () => {
|
|
66
|
+
(loadConfig as jest.Mock).mockResolvedValue(null);
|
|
67
|
+
|
|
68
|
+
await runAnalysis(defaultDiffOptions);
|
|
69
|
+
|
|
70
|
+
expect(mockPresenter.showConfigError).toHaveBeenCalled();
|
|
71
|
+
expect(mockStrategy.getFiles).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should show git error when getFiles throws a GitError', async () => {
|
|
75
|
+
(loadConfig as jest.Mock).mockResolvedValue(mockConfig);
|
|
76
|
+
const gitError = new Error('Not a git repo');
|
|
77
|
+
gitError.name = 'GitError';
|
|
78
|
+
mockStrategy.getFiles.mockRejectedValue(gitError);
|
|
79
|
+
|
|
80
|
+
await runAnalysis(defaultDiffOptions);
|
|
81
|
+
|
|
82
|
+
expect(mockPresenter.showGitError).toHaveBeenCalledWith('Not a git repo');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should show read files error when getFiles throws a non-GitError', async () => {
|
|
86
|
+
(loadConfig as jest.Mock).mockResolvedValue(mockConfig);
|
|
87
|
+
mockStrategy.getFiles.mockRejectedValue(new Error('some other error'));
|
|
88
|
+
|
|
89
|
+
await runAnalysis(defaultDiffOptions);
|
|
90
|
+
|
|
91
|
+
expect(mockPresenter.showReadFilesError).toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should show no changes when getFiles returns empty array', async () => {
|
|
95
|
+
(loadConfig as jest.Mock).mockResolvedValue(mockConfig);
|
|
96
|
+
mockStrategy.getFiles.mockResolvedValue([]);
|
|
97
|
+
|
|
98
|
+
await runAnalysis(defaultDiffOptions);
|
|
99
|
+
|
|
100
|
+
expect(mockPresenter.showNoChanges).toHaveBeenCalledWith(defaultDiffOptions);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should show read files error when getDiff throws', async () => {
|
|
104
|
+
(loadConfig as jest.Mock).mockResolvedValue(mockConfig);
|
|
105
|
+
mockStrategy.getFiles.mockResolvedValue(['file.ts']);
|
|
106
|
+
mockStrategy.getDiff.mockRejectedValue(new Error('diff failed'));
|
|
107
|
+
|
|
108
|
+
await runAnalysis(defaultDiffOptions);
|
|
109
|
+
|
|
110
|
+
expect(mockPresenter.showReadFilesError).toHaveBeenCalled();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should show no diff content when getDiff returns empty string', async () => {
|
|
114
|
+
(loadConfig as jest.Mock).mockResolvedValue(mockConfig);
|
|
115
|
+
mockStrategy.getFiles.mockResolvedValue(['file.ts']);
|
|
116
|
+
mockStrategy.getDiff.mockResolvedValue('');
|
|
117
|
+
|
|
118
|
+
await runAnalysis(defaultDiffOptions);
|
|
119
|
+
|
|
120
|
+
expect(mockPresenter.showNoDiffContent).toHaveBeenCalled();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should show analysis failed when analyzeChanges returns error', async () => {
|
|
124
|
+
(loadConfig as jest.Mock).mockResolvedValue(mockConfig);
|
|
125
|
+
mockStrategy.getFiles.mockResolvedValue(['file.ts']);
|
|
126
|
+
mockStrategy.getDiff.mockResolvedValue('diff content');
|
|
127
|
+
(analyzeChanges as jest.Mock).mockResolvedValue({
|
|
128
|
+
result: null,
|
|
129
|
+
error: 'api error',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await runAnalysis(defaultDiffOptions);
|
|
133
|
+
|
|
134
|
+
expect(mockPresenter.showAnalysisFailed).toHaveBeenCalledWith('api error');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should show not significant result when analysis result is not significant', async () => {
|
|
138
|
+
setupHappyPath({ isSignificant: false });
|
|
139
|
+
|
|
140
|
+
await runAnalysis(defaultDiffOptions);
|
|
141
|
+
|
|
142
|
+
expect(mockPresenter.showNotSignificantResult).toHaveBeenCalledWith(
|
|
143
|
+
expect.objectContaining({
|
|
144
|
+
fileCount: 2,
|
|
145
|
+
mode: 'all',
|
|
146
|
+
isSignificant: false,
|
|
147
|
+
reason: 'Introduced new dependency',
|
|
148
|
+
confidence: 0.9,
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should show skipping generation when user declines', async () => {
|
|
154
|
+
setupHappyPath({ isSignificant: true });
|
|
155
|
+
(promptForGeneration as jest.Mock).mockResolvedValue(false);
|
|
156
|
+
|
|
157
|
+
await runAnalysis(defaultDiffOptions);
|
|
158
|
+
|
|
159
|
+
expect(mockPresenter.showSignificantResult).toHaveBeenCalled();
|
|
160
|
+
expect(mockPresenter.showSkippingGeneration).toHaveBeenCalled();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should show generation failed when generateADRContent returns error', async () => {
|
|
164
|
+
setupHappyPath({ isSignificant: true });
|
|
165
|
+
(promptForGeneration as jest.Mock).mockResolvedValue(true);
|
|
166
|
+
(generateADRContent as jest.Mock).mockResolvedValue({
|
|
167
|
+
result: null,
|
|
168
|
+
error: 'generation error',
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
await runAnalysis(defaultDiffOptions);
|
|
172
|
+
|
|
173
|
+
expect(mockPresenter.showGeneratingADR).toHaveBeenCalled();
|
|
174
|
+
expect(mockPresenter.showGenerationFailed).toHaveBeenCalledWith('generation error');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should show ADR success when generation and save succeed', async () => {
|
|
178
|
+
setupHappyPath({ isSignificant: true });
|
|
179
|
+
(promptForGeneration as jest.Mock).mockResolvedValue(true);
|
|
180
|
+
(generateADRContent as jest.Mock).mockResolvedValue({
|
|
181
|
+
result: { content: '# ADR Content', title: 'Use Redis', timestamp: '2026-01-01' },
|
|
182
|
+
error: undefined,
|
|
183
|
+
});
|
|
184
|
+
(saveADR as jest.Mock).mockReturnValue({
|
|
185
|
+
success: true,
|
|
186
|
+
filePath: 'docs/adr/0001-use-redis.md',
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
await runAnalysis(defaultDiffOptions);
|
|
190
|
+
|
|
191
|
+
expect(mockPresenter.showGeneratingADR).toHaveBeenCalled();
|
|
192
|
+
expect(saveADR).toHaveBeenCalledWith('# ADR Content', 'Use Redis');
|
|
193
|
+
expect(mockPresenter.showADRSuccess).toHaveBeenCalledWith('docs/adr/0001-use-redis.md');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should show ADR save error when save fails', async () => {
|
|
197
|
+
setupHappyPath({ isSignificant: true });
|
|
198
|
+
(promptForGeneration as jest.Mock).mockResolvedValue(true);
|
|
199
|
+
(generateADRContent as jest.Mock).mockResolvedValue({
|
|
200
|
+
result: { content: '# ADR Content', title: 'Use Redis', timestamp: '2026-01-01' },
|
|
201
|
+
error: undefined,
|
|
202
|
+
});
|
|
203
|
+
(saveADR as jest.Mock).mockReturnValue({
|
|
204
|
+
success: false,
|
|
205
|
+
error: 'permission denied',
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
await runAnalysis(defaultDiffOptions);
|
|
209
|
+
|
|
210
|
+
expect(mockPresenter.showADRSaveError).toHaveBeenCalledWith('permission denied');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should show unexpected error when runAnalysisInternal throws', async () => {
|
|
214
|
+
(loadConfig as jest.Mock).mockRejectedValue(new Error('unexpected boom'));
|
|
215
|
+
|
|
216
|
+
await runAnalysis(defaultDiffOptions);
|
|
217
|
+
|
|
218
|
+
expect(mockPresenter.showUnexpectedError).toHaveBeenCalled();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should call showAnalyzingFiles, showSendingToLLM, and showAnalysisComplete in happy path', async () => {
|
|
222
|
+
setupHappyPath({ isSignificant: false });
|
|
223
|
+
|
|
224
|
+
await runAnalysis(defaultDiffOptions);
|
|
225
|
+
|
|
226
|
+
expect(mockPresenter.showAnalyzingFiles).toHaveBeenCalledWith(
|
|
227
|
+
['src/index.ts', 'src/utils.ts'],
|
|
228
|
+
defaultDiffOptions
|
|
229
|
+
);
|
|
230
|
+
expect(mockPresenter.showSendingToLLM).toHaveBeenCalledWith(
|
|
231
|
+
defaultDiffOptions,
|
|
232
|
+
'openai',
|
|
233
|
+
'gpt-4'
|
|
234
|
+
);
|
|
235
|
+
expect(mockPresenter.showAnalysisComplete).toHaveBeenCalled();
|
|
236
|
+
});
|
|
237
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StagedChangesStrategy,
|
|
3
|
+
AllChangesStrategy,
|
|
4
|
+
BranchDiffStrategy,
|
|
5
|
+
createGitStrategy,
|
|
6
|
+
} from './git-strategy';
|
|
7
|
+
import { GitError } from '../../git/git.errors';
|
|
8
|
+
import {
|
|
9
|
+
getStagedFiles,
|
|
10
|
+
getStagedDiff,
|
|
11
|
+
getAllChanges,
|
|
12
|
+
getAllDiff,
|
|
13
|
+
type DiffOptions,
|
|
14
|
+
} from '../../git/git.operations';
|
|
15
|
+
|
|
16
|
+
jest.mock('../../git/git.operations');
|
|
17
|
+
|
|
18
|
+
let mockExecAsync: jest.Mock;
|
|
19
|
+
|
|
20
|
+
jest.mock('child_process', () => ({
|
|
21
|
+
exec: jest.fn(),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
jest.mock('util', () => {
|
|
25
|
+
const actual = jest.requireActual('util');
|
|
26
|
+
return {
|
|
27
|
+
...actual,
|
|
28
|
+
promisify: jest.fn(() => (...args: unknown[]) => mockExecAsync(...args)),
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const mockedGetStagedFiles = getStagedFiles as jest.MockedFunction<typeof getStagedFiles>;
|
|
33
|
+
const mockedGetStagedDiff = getStagedDiff as jest.MockedFunction<typeof getStagedDiff>;
|
|
34
|
+
const mockedGetAllChanges = getAllChanges as jest.MockedFunction<typeof getAllChanges>;
|
|
35
|
+
const mockedGetAllDiff = getAllDiff as jest.MockedFunction<typeof getAllDiff>;
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
mockExecAsync = jest.fn();
|
|
39
|
+
jest.clearAllMocks();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
jest.restoreAllMocks();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('StagedChangesStrategy', () => {
|
|
47
|
+
let strategy: StagedChangesStrategy;
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
strategy = new StagedChangesStrategy();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('getFiles() delegates to getStagedFiles', async () => {
|
|
54
|
+
const files = ['src/a.ts', 'src/b.ts'];
|
|
55
|
+
mockedGetStagedFiles.mockResolvedValue(files);
|
|
56
|
+
|
|
57
|
+
const result = await strategy.getFiles();
|
|
58
|
+
|
|
59
|
+
expect(result).toEqual(files);
|
|
60
|
+
expect(getStagedFiles).toHaveBeenCalledTimes(1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('getDiff() delegates to getStagedDiff', async () => {
|
|
64
|
+
const diff = 'diff --git a/file.ts b/file.ts\n+added line';
|
|
65
|
+
mockedGetStagedDiff.mockResolvedValue(diff);
|
|
66
|
+
|
|
67
|
+
const result = await strategy.getDiff();
|
|
68
|
+
|
|
69
|
+
expect(result).toBe(diff);
|
|
70
|
+
expect(getStagedDiff).toHaveBeenCalledTimes(1);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('AllChangesStrategy', () => {
|
|
75
|
+
let strategy: AllChangesStrategy;
|
|
76
|
+
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
strategy = new AllChangesStrategy();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('getFiles() delegates to getAllChanges', async () => {
|
|
82
|
+
const files = ['lib/x.ts'];
|
|
83
|
+
mockedGetAllChanges.mockResolvedValue(files);
|
|
84
|
+
|
|
85
|
+
const result = await strategy.getFiles();
|
|
86
|
+
|
|
87
|
+
expect(result).toEqual(files);
|
|
88
|
+
expect(getAllChanges).toHaveBeenCalledTimes(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('getDiff() delegates to getAllDiff', async () => {
|
|
92
|
+
const diff = 'diff output here';
|
|
93
|
+
mockedGetAllDiff.mockResolvedValue(diff);
|
|
94
|
+
|
|
95
|
+
const result = await strategy.getDiff();
|
|
96
|
+
|
|
97
|
+
expect(result).toBe(diff);
|
|
98
|
+
expect(getAllDiff).toHaveBeenCalledTimes(1);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('BranchDiffStrategy', () => {
|
|
103
|
+
let strategy: BranchDiffStrategy;
|
|
104
|
+
|
|
105
|
+
beforeEach(() => {
|
|
106
|
+
strategy = new BranchDiffStrategy('main', 'feat/test');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('getFiles()', () => {
|
|
110
|
+
it('parses stdout newline list and returns array of files', async () => {
|
|
111
|
+
mockExecAsync.mockResolvedValue({
|
|
112
|
+
stdout: 'src/a.ts\nsrc/b.ts\n',
|
|
113
|
+
stderr: '',
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const result = await strategy.getFiles();
|
|
117
|
+
|
|
118
|
+
expect(result).toEqual(['src/a.ts', 'src/b.ts']);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('throws GitError with "Invalid git reference" when exec fails with code 128', async () => {
|
|
122
|
+
const execError = Object.assign(new Error('fatal: bad revision'), { code: 128 });
|
|
123
|
+
mockExecAsync.mockRejectedValue(execError);
|
|
124
|
+
|
|
125
|
+
await expect(strategy.getFiles()).rejects.toThrow(GitError);
|
|
126
|
+
await expect(strategy.getFiles()).rejects.toThrow(/Invalid git reference/);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('throws GitError with "Unable to read Git repository" when exec fails with other code', async () => {
|
|
130
|
+
const execError = Object.assign(new Error('some error'), { code: 1 });
|
|
131
|
+
mockExecAsync.mockRejectedValue(execError);
|
|
132
|
+
|
|
133
|
+
await expect(strategy.getFiles()).rejects.toThrow(GitError);
|
|
134
|
+
await expect(strategy.getFiles()).rejects.toThrow(/Unable to read Git repository/);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('getDiff()', () => {
|
|
139
|
+
it('returns raw stdout on success', async () => {
|
|
140
|
+
const diffOutput = 'diff --git a/file.ts b/file.ts\n+new line';
|
|
141
|
+
mockExecAsync.mockResolvedValue({
|
|
142
|
+
stdout: diffOutput,
|
|
143
|
+
stderr: '',
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const result = await strategy.getDiff();
|
|
147
|
+
|
|
148
|
+
expect(result).toBe(diffOutput);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('throws GitError when exec fails with code 128', async () => {
|
|
152
|
+
const execError = Object.assign(new Error('fatal: bad revision'), { code: 128 });
|
|
153
|
+
mockExecAsync.mockRejectedValue(execError);
|
|
154
|
+
|
|
155
|
+
await expect(strategy.getDiff()).rejects.toThrow(GitError);
|
|
156
|
+
await expect(strategy.getDiff()).rejects.toThrow(/Invalid git reference/);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('throws GitError when exec fails with other code', async () => {
|
|
160
|
+
const execError = Object.assign(new Error('permission denied'), { code: 2 });
|
|
161
|
+
mockExecAsync.mockRejectedValue(execError);
|
|
162
|
+
|
|
163
|
+
await expect(strategy.getDiff()).rejects.toThrow(GitError);
|
|
164
|
+
await expect(strategy.getDiff()).rejects.toThrow(/Unable to read Git repository/);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('uses correct base and head in git commands', async () => {
|
|
169
|
+
const customStrategy = new BranchDiffStrategy('origin/develop', 'feature/abc');
|
|
170
|
+
mockExecAsync.mockResolvedValue({ stdout: '', stderr: '' });
|
|
171
|
+
|
|
172
|
+
await customStrategy.getFiles();
|
|
173
|
+
expect(mockExecAsync).toHaveBeenCalledWith(
|
|
174
|
+
'git diff --name-only origin/develop...feature/abc'
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
mockExecAsync.mockClear();
|
|
178
|
+
|
|
179
|
+
await customStrategy.getDiff();
|
|
180
|
+
expect(mockExecAsync).toHaveBeenCalledWith(
|
|
181
|
+
'git diff origin/develop...feature/abc --unified=1'
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('createGitStrategy', () => {
|
|
187
|
+
it('returns StagedChangesStrategy for mode "staged"', () => {
|
|
188
|
+
const strategy = createGitStrategy({ mode: 'staged' });
|
|
189
|
+
|
|
190
|
+
expect(strategy).toBeInstanceOf(StagedChangesStrategy);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('returns AllChangesStrategy for mode "all"', () => {
|
|
194
|
+
const strategy = createGitStrategy({ mode: 'all' });
|
|
195
|
+
|
|
196
|
+
expect(strategy).toBeInstanceOf(AllChangesStrategy);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('returns BranchDiffStrategy for mode "branch-diff"', () => {
|
|
200
|
+
const strategy = createGitStrategy({ mode: 'branch-diff', base: 'main', head: 'feat' });
|
|
201
|
+
|
|
202
|
+
expect(strategy).toBeInstanceOf(BranchDiffStrategy);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('returns AllChangesStrategy for unknown mode (default case)', () => {
|
|
206
|
+
const strategy = createGitStrategy({ mode: 'unknown' as unknown as DiffOptions['mode'] });
|
|
207
|
+
|
|
208
|
+
expect(strategy).toBeInstanceOf(AllChangesStrategy);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { analyzeCommand } from './analyze';
|
|
2
|
+
import { runAnalysis } from '../analysis/analysis.orchestrator';
|
|
3
|
+
import { loggerInstance as logger } from '../logger';
|
|
4
|
+
|
|
5
|
+
jest.mock('../analysis/analysis.orchestrator');
|
|
6
|
+
jest.mock('../logger');
|
|
7
|
+
|
|
8
|
+
const mockRunAnalysis = runAnalysis as jest.MockedFunction<typeof runAnalysis>;
|
|
9
|
+
const mockLogger = logger as jest.Mocked<typeof logger>;
|
|
10
|
+
|
|
11
|
+
describe('analyzeCommand', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.clearAllMocks();
|
|
14
|
+
mockRunAnalysis.mockResolvedValue(undefined);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
jest.restoreAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should call runAnalysis with mode "all" when no args provided', async () => {
|
|
22
|
+
await analyzeCommand([]);
|
|
23
|
+
|
|
24
|
+
expect(mockRunAnalysis).toHaveBeenCalledWith({ mode: 'all' });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should call runAnalysis with mode "all" when --all flag is provided', async () => {
|
|
28
|
+
await analyzeCommand(['--all']);
|
|
29
|
+
|
|
30
|
+
expect(mockRunAnalysis).toHaveBeenCalledWith({ mode: 'all' });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should call runAnalysis with mode "staged" when --staged flag is provided', async () => {
|
|
34
|
+
await analyzeCommand(['--staged']);
|
|
35
|
+
|
|
36
|
+
expect(mockRunAnalysis).toHaveBeenCalledWith({ mode: 'staged' });
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should call runAnalysis with mode "branch-diff" and base when --base is provided', async () => {
|
|
40
|
+
await analyzeCommand(['--base', 'origin/main']);
|
|
41
|
+
|
|
42
|
+
expect(mockRunAnalysis).toHaveBeenCalledWith({
|
|
43
|
+
mode: 'branch-diff',
|
|
44
|
+
base: 'origin/main',
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should call runAnalysis with mode "branch-diff", base and head when both flags are provided', async () => {
|
|
49
|
+
await analyzeCommand(['--base', 'origin/main', '--head', 'feature']);
|
|
50
|
+
|
|
51
|
+
expect(mockRunAnalysis).toHaveBeenCalledWith({
|
|
52
|
+
mode: 'branch-diff',
|
|
53
|
+
base: 'origin/main',
|
|
54
|
+
head: 'feature',
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should fall back to mode "all" when --base has no value after it', async () => {
|
|
59
|
+
await analyzeCommand(['--base']);
|
|
60
|
+
|
|
61
|
+
expect(mockRunAnalysis).toHaveBeenCalledWith({ mode: 'all' });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should detect --staged flag anywhere in the args array', async () => {
|
|
65
|
+
await analyzeCommand(['analyze', '--staged']);
|
|
66
|
+
|
|
67
|
+
expect(mockRunAnalysis).toHaveBeenCalledWith({ mode: 'staged' });
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should catch errors from runAnalysis and not re-throw', async () => {
|
|
71
|
+
mockRunAnalysis.mockRejectedValue(new Error('analysis failed'));
|
|
72
|
+
|
|
73
|
+
await expect(analyzeCommand(['--all'])).resolves.not.toThrow();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should log "Analyze command started" with mode information', async () => {
|
|
77
|
+
await analyzeCommand(['--staged']);
|
|
78
|
+
|
|
79
|
+
expect(mockLogger.info).toHaveBeenCalledWith('Analyze command started', {
|
|
80
|
+
mode: 'staged',
|
|
81
|
+
base: undefined,
|
|
82
|
+
head: undefined,
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should log "Analyze command completed" on success', async () => {
|
|
87
|
+
await analyzeCommand([]);
|
|
88
|
+
|
|
89
|
+
expect(mockLogger.info).toHaveBeenCalledWith('Analyze command completed');
|
|
90
|
+
});
|
|
91
|
+
});
|