code-review-ai-cli 1.0.0__tar.gz → 1.0.1__tar.gz
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.
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/PKG-INFO +56 -79
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/README.md +55 -78
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/PKG-INFO +56 -79
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/SOURCES.txt +1 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/pyproject.toml +1 -1
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/ai_review.py +42 -19
- code_review_ai_cli-1.0.1/src/prompts/review_prompt.md.template +42 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_ai_review.py +162 -1
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/dependency_links.txt +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/entry_points.txt +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/requires.txt +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/top_level.txt +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/setup.cfg +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/__init__.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/config.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/formatter.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/git_utils.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/llm_client.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/prompts/config.yaml.template +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/src/tfs_client.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_config.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_formatter.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_git_utils.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_llm_client.py +0 -0
- {code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/tests/test_tfs_client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-review-ai-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Automated AI-powered code review CLI for Azure DevOps / TFS Pull Requests
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: code-review,ai,azure-devops,tfs,pull-request,llm
|
|
@@ -78,22 +78,26 @@ pip install "code-review-ai-cli[dev]"
|
|
|
78
78
|
|
|
79
79
|
## Configuration
|
|
80
80
|
|
|
81
|
-
After installing the package, generate
|
|
81
|
+
After installing the package, generate ready-to-edit configuration files in your working directory:
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
ai-review init
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
This copies
|
|
87
|
+
This copies two bundled templates:
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
- **`config.yaml`** — all available options with inline documentation
|
|
90
|
+
- **`review_prompt.md`** — default review style rules, injected into every LLM prompt
|
|
91
|
+
|
|
92
|
+
```text
|
|
90
93
|
✅ config.yaml created at: /home/user/my-project/config.yaml
|
|
91
|
-
|
|
94
|
+
✅ review_prompt.md created at: /home/user/my-project/review_prompt.md
|
|
95
|
+
Edit them to add your credentials, preferences and review rules.
|
|
92
96
|
```
|
|
93
97
|
|
|
94
|
-
If
|
|
98
|
+
If either file already exists you will be prompted individually before it is overwritten:
|
|
95
99
|
|
|
96
|
-
```
|
|
100
|
+
```text
|
|
97
101
|
config.yaml already exists in the current directory.
|
|
98
102
|
Overwrite? [y/N]
|
|
99
103
|
```
|
|
@@ -165,23 +169,22 @@ review:
|
|
|
165
169
|
|
|
166
170
|
### Markdown-Customizable Prompt
|
|
167
171
|
|
|
168
|
-
|
|
169
|
-
This file is loaded automatically and injected into LLM instructions on each run.
|
|
170
|
-
|
|
171
|
-
Example in `config.yaml`:
|
|
172
|
-
|
|
173
|
-
```yaml
|
|
174
|
-
review:
|
|
175
|
-
custom_prompt_file: review_prompt.md
|
|
176
|
-
```
|
|
172
|
+
`ai-review init` creates a `review_prompt.md` alongside `config.yaml`. This file is loaded automatically and injected into LLM instructions on every run.
|
|
177
173
|
|
|
178
|
-
|
|
174
|
+
Edit it to tailor the review to your team:
|
|
179
175
|
|
|
180
176
|
- Define comment tone and format
|
|
181
177
|
- Add mandatory validation rules
|
|
182
178
|
- Include business/architecture context
|
|
183
179
|
- Add examples of good/bad comments
|
|
184
180
|
|
|
181
|
+
The path is configurable in `config.yaml` (default: `review_prompt.md` in the current directory):
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
review:
|
|
185
|
+
custom_prompt_file: review_prompt.md
|
|
186
|
+
```
|
|
187
|
+
|
|
185
188
|
### Bedrock Example
|
|
186
189
|
|
|
187
190
|
```yaml
|
|
@@ -201,50 +204,23 @@ tfs:
|
|
|
201
204
|
project: ProjectName
|
|
202
205
|
pat: xxxxxxxxx
|
|
203
206
|
```
|
|
207
|
+
|
|
204
208
|
Bedrock notes:
|
|
205
209
|
|
|
206
210
|
- You can use `profile` or explicit credentials in YAML.
|
|
207
211
|
- If explicit credentials are not defined, the AWS SDK uses the default credentials chain.
|
|
208
212
|
|
|
209
|
-
## Review Flow
|
|
210
|
-
|
|
211
|
-
The main `pr-review` workflow is:
|
|
212
|
-
|
|
213
|
-
1. load and validate configuration
|
|
214
|
-
2. fetch Pull Request metadata from Azure DevOps/TFS
|
|
215
|
-
3. fetch the PR diff
|
|
216
|
-
4. filter and truncate the diff according to configuration
|
|
217
|
-
5. request textual analysis and structured comments from the LLM provider
|
|
218
|
-
6. display a preview in the terminal
|
|
219
|
-
7. post inline or general PR comments when applicable
|
|
220
|
-
|
|
221
|
-
## Tests
|
|
222
|
-
|
|
223
|
-
The project's functional coverage is reflected in the `tests/` folder, including:
|
|
224
|
-
|
|
225
|
-
- `tests/test_ai_review.py` for the CLI and main workflow
|
|
226
|
-
- `tests/test_config.py` for configuration and validation
|
|
227
|
-
- `tests/test_formatter.py` for terminal/markdown/json rendering
|
|
228
|
-
- `tests/test_git_utils.py` for diffs and Git utilities
|
|
229
|
-
- `tests/test_llm_client.py` for prompts, parsing, and LLM providers
|
|
230
|
-
- `tests/test_tfs_client.py` for TFS/Azure DevOps integration
|
|
231
|
-
|
|
232
|
-
Run the suite:
|
|
233
|
-
|
|
234
|
-
```bash
|
|
235
|
-
python -m pytest --cov=src --cov-report=term
|
|
236
|
-
```
|
|
237
|
-
|
|
238
213
|
## CLI Usage
|
|
239
214
|
|
|
240
215
|
### Help
|
|
216
|
+
|
|
241
217
|
```bash
|
|
242
|
-
|
|
218
|
+
ai-review pr-review --help
|
|
243
219
|
```
|
|
244
220
|
|
|
245
221
|
### Bootstrap configuration
|
|
246
222
|
|
|
247
|
-
Generate
|
|
223
|
+
Generate `config.yaml` and `review_prompt.md` templates in the current directory:
|
|
248
224
|
|
|
249
225
|
```bash
|
|
250
226
|
ai-review init
|
|
@@ -253,7 +229,7 @@ ai-review init
|
|
|
253
229
|
### Interactive Mode
|
|
254
230
|
|
|
255
231
|
```bash
|
|
256
|
-
|
|
232
|
+
ai-review pr-review
|
|
257
233
|
```
|
|
258
234
|
|
|
259
235
|
### Pull Request Review
|
|
@@ -261,51 +237,51 @@ python ai_review.py
|
|
|
261
237
|
List PRs and select interactively:
|
|
262
238
|
|
|
263
239
|
```bash
|
|
264
|
-
|
|
240
|
+
ai-review pr-review pr-review
|
|
265
241
|
```
|
|
266
242
|
|
|
267
243
|
Review a specific PR:
|
|
268
244
|
|
|
269
245
|
```bash
|
|
270
|
-
|
|
246
|
+
ai-review pr-review pr-review 42
|
|
271
247
|
```
|
|
272
248
|
|
|
273
249
|
Dry-run:
|
|
274
250
|
|
|
275
251
|
```bash
|
|
276
|
-
|
|
252
|
+
ai-review pr-review pr-review 42 --dry-run
|
|
277
253
|
```
|
|
278
254
|
|
|
279
255
|
Full review of changed files (in addition to diff-focused review):
|
|
280
256
|
|
|
281
257
|
```bash
|
|
282
|
-
|
|
258
|
+
ai-review pr-review pr-review 42 --review-scope full_code
|
|
283
259
|
```
|
|
284
260
|
|
|
285
261
|
Automatic posting (without confirmation):
|
|
286
262
|
|
|
287
263
|
```bash
|
|
288
|
-
|
|
264
|
+
ai-review pr-review pr-review 42 --auto-post
|
|
289
265
|
```
|
|
290
266
|
|
|
291
267
|
Filter PRs in interactive selection:
|
|
292
268
|
|
|
293
269
|
```bash
|
|
294
|
-
|
|
270
|
+
ai-review pr-review pr-review --author "John Smith" --target-branch main
|
|
295
271
|
```
|
|
296
272
|
|
|
297
273
|
Choose provider/model via CLI:
|
|
298
274
|
|
|
299
275
|
```bash
|
|
300
|
-
|
|
276
|
+
ai-review pr-review pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
|
|
301
277
|
```
|
|
302
278
|
|
|
303
279
|
### List Pull Requests
|
|
304
280
|
|
|
305
281
|
```bash
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
282
|
+
ai-review pr-review list-prs
|
|
283
|
+
ai-review pr-review list-prs --status completed
|
|
284
|
+
ai-review pr-review list-prs --repo-name backend --author "John"
|
|
309
285
|
```
|
|
310
286
|
|
|
311
287
|
## Execution Flow
|
|
@@ -314,7 +290,7 @@ The diagram below summarizes how the review application moves from CLI entry to
|
|
|
314
290
|
|
|
315
291
|
```mermaid
|
|
316
292
|
flowchart TD
|
|
317
|
-
A[Start:
|
|
293
|
+
A[Start: ai-review pr-review] --> B{Arguments provided?}
|
|
318
294
|
B -->|No| C[Interactive mode]
|
|
319
295
|
B -->|Yes| D[Parse CLI command]
|
|
320
296
|
|
|
@@ -364,7 +340,7 @@ flowchart TD
|
|
|
364
340
|
### `pr-review`
|
|
365
341
|
|
|
366
342
|
```bash
|
|
367
|
-
|
|
343
|
+
ai-review pr-review pr-review [pr_id]
|
|
368
344
|
```
|
|
369
345
|
|
|
370
346
|
Options:
|
|
@@ -388,7 +364,7 @@ Options:
|
|
|
388
364
|
### `list-prs`
|
|
389
365
|
|
|
390
366
|
```bash
|
|
391
|
-
|
|
367
|
+
ai-review pr-review list-prs
|
|
392
368
|
```
|
|
393
369
|
|
|
394
370
|
Options:
|
|
@@ -399,10 +375,10 @@ Options:
|
|
|
399
375
|
|
|
400
376
|
## Available VS Code Tasks
|
|
401
377
|
|
|
402
|
-
-
|
|
403
|
-
-
|
|
404
|
-
-
|
|
405
|
-
-
|
|
378
|
+
- `AI Review: Pull Request (Interactive)`
|
|
379
|
+
- `AI Review: PR (Dry-Run)`
|
|
380
|
+
- `AI Review: List Active PRs`
|
|
381
|
+
- `AI Review: Interactive Mode`
|
|
406
382
|
|
|
407
383
|
## Troubleshooting
|
|
408
384
|
|
|
@@ -424,18 +400,19 @@ Avoid `verify_ssl: false` except for temporary troubleshooting.
|
|
|
424
400
|
- Confirm `llm.model` with a valid Bedrock model ID in the chosen region.
|
|
425
401
|
- Validate AWS credentials (`profile` or explicit keys).
|
|
426
402
|
|
|
427
|
-
##
|
|
403
|
+
## Tests
|
|
428
404
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
405
|
+
The project's functional coverage is reflected in the `tests/` folder, including:
|
|
406
|
+
|
|
407
|
+
- `tests/test_ai_review.py` for the CLI and main workflow
|
|
408
|
+
- `tests/test_config.py` for configuration and validation
|
|
409
|
+
- `tests/test_formatter.py` for terminal/markdown/json rendering
|
|
410
|
+
- `tests/test_git_utils.py` for diffs and Git utilities
|
|
411
|
+
- `tests/test_llm_client.py` for prompts, parsing, and LLM providers
|
|
412
|
+
- `tests/test_tfs_client.py` for TFS/Azure DevOps integration
|
|
413
|
+
|
|
414
|
+
Run the suite:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
python -m pytest --cov=src --cov-report=term
|
|
441
418
|
```
|
|
@@ -41,22 +41,26 @@ pip install "code-review-ai-cli[dev]"
|
|
|
41
41
|
|
|
42
42
|
## Configuration
|
|
43
43
|
|
|
44
|
-
After installing the package, generate
|
|
44
|
+
After installing the package, generate ready-to-edit configuration files in your working directory:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
ai-review init
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
This copies
|
|
50
|
+
This copies two bundled templates:
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
- **`config.yaml`** — all available options with inline documentation
|
|
53
|
+
- **`review_prompt.md`** — default review style rules, injected into every LLM prompt
|
|
54
|
+
|
|
55
|
+
```text
|
|
53
56
|
✅ config.yaml created at: /home/user/my-project/config.yaml
|
|
54
|
-
|
|
57
|
+
✅ review_prompt.md created at: /home/user/my-project/review_prompt.md
|
|
58
|
+
Edit them to add your credentials, preferences and review rules.
|
|
55
59
|
```
|
|
56
60
|
|
|
57
|
-
If
|
|
61
|
+
If either file already exists you will be prompted individually before it is overwritten:
|
|
58
62
|
|
|
59
|
-
```
|
|
63
|
+
```text
|
|
60
64
|
config.yaml already exists in the current directory.
|
|
61
65
|
Overwrite? [y/N]
|
|
62
66
|
```
|
|
@@ -128,23 +132,22 @@ review:
|
|
|
128
132
|
|
|
129
133
|
### Markdown-Customizable Prompt
|
|
130
134
|
|
|
131
|
-
|
|
132
|
-
This file is loaded automatically and injected into LLM instructions on each run.
|
|
133
|
-
|
|
134
|
-
Example in `config.yaml`:
|
|
135
|
-
|
|
136
|
-
```yaml
|
|
137
|
-
review:
|
|
138
|
-
custom_prompt_file: review_prompt.md
|
|
139
|
-
```
|
|
135
|
+
`ai-review init` creates a `review_prompt.md` alongside `config.yaml`. This file is loaded automatically and injected into LLM instructions on every run.
|
|
140
136
|
|
|
141
|
-
|
|
137
|
+
Edit it to tailor the review to your team:
|
|
142
138
|
|
|
143
139
|
- Define comment tone and format
|
|
144
140
|
- Add mandatory validation rules
|
|
145
141
|
- Include business/architecture context
|
|
146
142
|
- Add examples of good/bad comments
|
|
147
143
|
|
|
144
|
+
The path is configurable in `config.yaml` (default: `review_prompt.md` in the current directory):
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
review:
|
|
148
|
+
custom_prompt_file: review_prompt.md
|
|
149
|
+
```
|
|
150
|
+
|
|
148
151
|
### Bedrock Example
|
|
149
152
|
|
|
150
153
|
```yaml
|
|
@@ -164,50 +167,23 @@ tfs:
|
|
|
164
167
|
project: ProjectName
|
|
165
168
|
pat: xxxxxxxxx
|
|
166
169
|
```
|
|
170
|
+
|
|
167
171
|
Bedrock notes:
|
|
168
172
|
|
|
169
173
|
- You can use `profile` or explicit credentials in YAML.
|
|
170
174
|
- If explicit credentials are not defined, the AWS SDK uses the default credentials chain.
|
|
171
175
|
|
|
172
|
-
## Review Flow
|
|
173
|
-
|
|
174
|
-
The main `pr-review` workflow is:
|
|
175
|
-
|
|
176
|
-
1. load and validate configuration
|
|
177
|
-
2. fetch Pull Request metadata from Azure DevOps/TFS
|
|
178
|
-
3. fetch the PR diff
|
|
179
|
-
4. filter and truncate the diff according to configuration
|
|
180
|
-
5. request textual analysis and structured comments from the LLM provider
|
|
181
|
-
6. display a preview in the terminal
|
|
182
|
-
7. post inline or general PR comments when applicable
|
|
183
|
-
|
|
184
|
-
## Tests
|
|
185
|
-
|
|
186
|
-
The project's functional coverage is reflected in the `tests/` folder, including:
|
|
187
|
-
|
|
188
|
-
- `tests/test_ai_review.py` for the CLI and main workflow
|
|
189
|
-
- `tests/test_config.py` for configuration and validation
|
|
190
|
-
- `tests/test_formatter.py` for terminal/markdown/json rendering
|
|
191
|
-
- `tests/test_git_utils.py` for diffs and Git utilities
|
|
192
|
-
- `tests/test_llm_client.py` for prompts, parsing, and LLM providers
|
|
193
|
-
- `tests/test_tfs_client.py` for TFS/Azure DevOps integration
|
|
194
|
-
|
|
195
|
-
Run the suite:
|
|
196
|
-
|
|
197
|
-
```bash
|
|
198
|
-
python -m pytest --cov=src --cov-report=term
|
|
199
|
-
```
|
|
200
|
-
|
|
201
176
|
## CLI Usage
|
|
202
177
|
|
|
203
178
|
### Help
|
|
179
|
+
|
|
204
180
|
```bash
|
|
205
|
-
|
|
181
|
+
ai-review pr-review --help
|
|
206
182
|
```
|
|
207
183
|
|
|
208
184
|
### Bootstrap configuration
|
|
209
185
|
|
|
210
|
-
Generate
|
|
186
|
+
Generate `config.yaml` and `review_prompt.md` templates in the current directory:
|
|
211
187
|
|
|
212
188
|
```bash
|
|
213
189
|
ai-review init
|
|
@@ -216,7 +192,7 @@ ai-review init
|
|
|
216
192
|
### Interactive Mode
|
|
217
193
|
|
|
218
194
|
```bash
|
|
219
|
-
|
|
195
|
+
ai-review pr-review
|
|
220
196
|
```
|
|
221
197
|
|
|
222
198
|
### Pull Request Review
|
|
@@ -224,51 +200,51 @@ python ai_review.py
|
|
|
224
200
|
List PRs and select interactively:
|
|
225
201
|
|
|
226
202
|
```bash
|
|
227
|
-
|
|
203
|
+
ai-review pr-review pr-review
|
|
228
204
|
```
|
|
229
205
|
|
|
230
206
|
Review a specific PR:
|
|
231
207
|
|
|
232
208
|
```bash
|
|
233
|
-
|
|
209
|
+
ai-review pr-review pr-review 42
|
|
234
210
|
```
|
|
235
211
|
|
|
236
212
|
Dry-run:
|
|
237
213
|
|
|
238
214
|
```bash
|
|
239
|
-
|
|
215
|
+
ai-review pr-review pr-review 42 --dry-run
|
|
240
216
|
```
|
|
241
217
|
|
|
242
218
|
Full review of changed files (in addition to diff-focused review):
|
|
243
219
|
|
|
244
220
|
```bash
|
|
245
|
-
|
|
221
|
+
ai-review pr-review pr-review 42 --review-scope full_code
|
|
246
222
|
```
|
|
247
223
|
|
|
248
224
|
Automatic posting (without confirmation):
|
|
249
225
|
|
|
250
226
|
```bash
|
|
251
|
-
|
|
227
|
+
ai-review pr-review pr-review 42 --auto-post
|
|
252
228
|
```
|
|
253
229
|
|
|
254
230
|
Filter PRs in interactive selection:
|
|
255
231
|
|
|
256
232
|
```bash
|
|
257
|
-
|
|
233
|
+
ai-review pr-review pr-review --author "John Smith" --target-branch main
|
|
258
234
|
```
|
|
259
235
|
|
|
260
236
|
Choose provider/model via CLI:
|
|
261
237
|
|
|
262
238
|
```bash
|
|
263
|
-
|
|
239
|
+
ai-review pr-review pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
|
|
264
240
|
```
|
|
265
241
|
|
|
266
242
|
### List Pull Requests
|
|
267
243
|
|
|
268
244
|
```bash
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
245
|
+
ai-review pr-review list-prs
|
|
246
|
+
ai-review pr-review list-prs --status completed
|
|
247
|
+
ai-review pr-review list-prs --repo-name backend --author "John"
|
|
272
248
|
```
|
|
273
249
|
|
|
274
250
|
## Execution Flow
|
|
@@ -277,7 +253,7 @@ The diagram below summarizes how the review application moves from CLI entry to
|
|
|
277
253
|
|
|
278
254
|
```mermaid
|
|
279
255
|
flowchart TD
|
|
280
|
-
A[Start:
|
|
256
|
+
A[Start: ai-review pr-review] --> B{Arguments provided?}
|
|
281
257
|
B -->|No| C[Interactive mode]
|
|
282
258
|
B -->|Yes| D[Parse CLI command]
|
|
283
259
|
|
|
@@ -327,7 +303,7 @@ flowchart TD
|
|
|
327
303
|
### `pr-review`
|
|
328
304
|
|
|
329
305
|
```bash
|
|
330
|
-
|
|
306
|
+
ai-review pr-review pr-review [pr_id]
|
|
331
307
|
```
|
|
332
308
|
|
|
333
309
|
Options:
|
|
@@ -351,7 +327,7 @@ Options:
|
|
|
351
327
|
### `list-prs`
|
|
352
328
|
|
|
353
329
|
```bash
|
|
354
|
-
|
|
330
|
+
ai-review pr-review list-prs
|
|
355
331
|
```
|
|
356
332
|
|
|
357
333
|
Options:
|
|
@@ -362,10 +338,10 @@ Options:
|
|
|
362
338
|
|
|
363
339
|
## Available VS Code Tasks
|
|
364
340
|
|
|
365
|
-
-
|
|
366
|
-
-
|
|
367
|
-
-
|
|
368
|
-
-
|
|
341
|
+
- `AI Review: Pull Request (Interactive)`
|
|
342
|
+
- `AI Review: PR (Dry-Run)`
|
|
343
|
+
- `AI Review: List Active PRs`
|
|
344
|
+
- `AI Review: Interactive Mode`
|
|
369
345
|
|
|
370
346
|
## Troubleshooting
|
|
371
347
|
|
|
@@ -387,18 +363,19 @@ Avoid `verify_ssl: false` except for temporary troubleshooting.
|
|
|
387
363
|
- Confirm `llm.model` with a valid Bedrock model ID in the chosen region.
|
|
388
364
|
- Validate AWS credentials (`profile` or explicit keys).
|
|
389
365
|
|
|
390
|
-
##
|
|
366
|
+
## Tests
|
|
391
367
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
368
|
+
The project's functional coverage is reflected in the `tests/` folder, including:
|
|
369
|
+
|
|
370
|
+
- `tests/test_ai_review.py` for the CLI and main workflow
|
|
371
|
+
- `tests/test_config.py` for configuration and validation
|
|
372
|
+
- `tests/test_formatter.py` for terminal/markdown/json rendering
|
|
373
|
+
- `tests/test_git_utils.py` for diffs and Git utilities
|
|
374
|
+
- `tests/test_llm_client.py` for prompts, parsing, and LLM providers
|
|
375
|
+
- `tests/test_tfs_client.py` for TFS/Azure DevOps integration
|
|
376
|
+
|
|
377
|
+
Run the suite:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
python -m pytest --cov=src --cov-report=term
|
|
404
381
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-review-ai-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Automated AI-powered code review CLI for Azure DevOps / TFS Pull Requests
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: code-review,ai,azure-devops,tfs,pull-request,llm
|
|
@@ -78,22 +78,26 @@ pip install "code-review-ai-cli[dev]"
|
|
|
78
78
|
|
|
79
79
|
## Configuration
|
|
80
80
|
|
|
81
|
-
After installing the package, generate
|
|
81
|
+
After installing the package, generate ready-to-edit configuration files in your working directory:
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
ai-review init
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
This copies
|
|
87
|
+
This copies two bundled templates:
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
- **`config.yaml`** — all available options with inline documentation
|
|
90
|
+
- **`review_prompt.md`** — default review style rules, injected into every LLM prompt
|
|
91
|
+
|
|
92
|
+
```text
|
|
90
93
|
✅ config.yaml created at: /home/user/my-project/config.yaml
|
|
91
|
-
|
|
94
|
+
✅ review_prompt.md created at: /home/user/my-project/review_prompt.md
|
|
95
|
+
Edit them to add your credentials, preferences and review rules.
|
|
92
96
|
```
|
|
93
97
|
|
|
94
|
-
If
|
|
98
|
+
If either file already exists you will be prompted individually before it is overwritten:
|
|
95
99
|
|
|
96
|
-
```
|
|
100
|
+
```text
|
|
97
101
|
config.yaml already exists in the current directory.
|
|
98
102
|
Overwrite? [y/N]
|
|
99
103
|
```
|
|
@@ -165,23 +169,22 @@ review:
|
|
|
165
169
|
|
|
166
170
|
### Markdown-Customizable Prompt
|
|
167
171
|
|
|
168
|
-
|
|
169
|
-
This file is loaded automatically and injected into LLM instructions on each run.
|
|
170
|
-
|
|
171
|
-
Example in `config.yaml`:
|
|
172
|
-
|
|
173
|
-
```yaml
|
|
174
|
-
review:
|
|
175
|
-
custom_prompt_file: review_prompt.md
|
|
176
|
-
```
|
|
172
|
+
`ai-review init` creates a `review_prompt.md` alongside `config.yaml`. This file is loaded automatically and injected into LLM instructions on every run.
|
|
177
173
|
|
|
178
|
-
|
|
174
|
+
Edit it to tailor the review to your team:
|
|
179
175
|
|
|
180
176
|
- Define comment tone and format
|
|
181
177
|
- Add mandatory validation rules
|
|
182
178
|
- Include business/architecture context
|
|
183
179
|
- Add examples of good/bad comments
|
|
184
180
|
|
|
181
|
+
The path is configurable in `config.yaml` (default: `review_prompt.md` in the current directory):
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
review:
|
|
185
|
+
custom_prompt_file: review_prompt.md
|
|
186
|
+
```
|
|
187
|
+
|
|
185
188
|
### Bedrock Example
|
|
186
189
|
|
|
187
190
|
```yaml
|
|
@@ -201,50 +204,23 @@ tfs:
|
|
|
201
204
|
project: ProjectName
|
|
202
205
|
pat: xxxxxxxxx
|
|
203
206
|
```
|
|
207
|
+
|
|
204
208
|
Bedrock notes:
|
|
205
209
|
|
|
206
210
|
- You can use `profile` or explicit credentials in YAML.
|
|
207
211
|
- If explicit credentials are not defined, the AWS SDK uses the default credentials chain.
|
|
208
212
|
|
|
209
|
-
## Review Flow
|
|
210
|
-
|
|
211
|
-
The main `pr-review` workflow is:
|
|
212
|
-
|
|
213
|
-
1. load and validate configuration
|
|
214
|
-
2. fetch Pull Request metadata from Azure DevOps/TFS
|
|
215
|
-
3. fetch the PR diff
|
|
216
|
-
4. filter and truncate the diff according to configuration
|
|
217
|
-
5. request textual analysis and structured comments from the LLM provider
|
|
218
|
-
6. display a preview in the terminal
|
|
219
|
-
7. post inline or general PR comments when applicable
|
|
220
|
-
|
|
221
|
-
## Tests
|
|
222
|
-
|
|
223
|
-
The project's functional coverage is reflected in the `tests/` folder, including:
|
|
224
|
-
|
|
225
|
-
- `tests/test_ai_review.py` for the CLI and main workflow
|
|
226
|
-
- `tests/test_config.py` for configuration and validation
|
|
227
|
-
- `tests/test_formatter.py` for terminal/markdown/json rendering
|
|
228
|
-
- `tests/test_git_utils.py` for diffs and Git utilities
|
|
229
|
-
- `tests/test_llm_client.py` for prompts, parsing, and LLM providers
|
|
230
|
-
- `tests/test_tfs_client.py` for TFS/Azure DevOps integration
|
|
231
|
-
|
|
232
|
-
Run the suite:
|
|
233
|
-
|
|
234
|
-
```bash
|
|
235
|
-
python -m pytest --cov=src --cov-report=term
|
|
236
|
-
```
|
|
237
|
-
|
|
238
213
|
## CLI Usage
|
|
239
214
|
|
|
240
215
|
### Help
|
|
216
|
+
|
|
241
217
|
```bash
|
|
242
|
-
|
|
218
|
+
ai-review pr-review --help
|
|
243
219
|
```
|
|
244
220
|
|
|
245
221
|
### Bootstrap configuration
|
|
246
222
|
|
|
247
|
-
Generate
|
|
223
|
+
Generate `config.yaml` and `review_prompt.md` templates in the current directory:
|
|
248
224
|
|
|
249
225
|
```bash
|
|
250
226
|
ai-review init
|
|
@@ -253,7 +229,7 @@ ai-review init
|
|
|
253
229
|
### Interactive Mode
|
|
254
230
|
|
|
255
231
|
```bash
|
|
256
|
-
|
|
232
|
+
ai-review pr-review
|
|
257
233
|
```
|
|
258
234
|
|
|
259
235
|
### Pull Request Review
|
|
@@ -261,51 +237,51 @@ python ai_review.py
|
|
|
261
237
|
List PRs and select interactively:
|
|
262
238
|
|
|
263
239
|
```bash
|
|
264
|
-
|
|
240
|
+
ai-review pr-review pr-review
|
|
265
241
|
```
|
|
266
242
|
|
|
267
243
|
Review a specific PR:
|
|
268
244
|
|
|
269
245
|
```bash
|
|
270
|
-
|
|
246
|
+
ai-review pr-review pr-review 42
|
|
271
247
|
```
|
|
272
248
|
|
|
273
249
|
Dry-run:
|
|
274
250
|
|
|
275
251
|
```bash
|
|
276
|
-
|
|
252
|
+
ai-review pr-review pr-review 42 --dry-run
|
|
277
253
|
```
|
|
278
254
|
|
|
279
255
|
Full review of changed files (in addition to diff-focused review):
|
|
280
256
|
|
|
281
257
|
```bash
|
|
282
|
-
|
|
258
|
+
ai-review pr-review pr-review 42 --review-scope full_code
|
|
283
259
|
```
|
|
284
260
|
|
|
285
261
|
Automatic posting (without confirmation):
|
|
286
262
|
|
|
287
263
|
```bash
|
|
288
|
-
|
|
264
|
+
ai-review pr-review pr-review 42 --auto-post
|
|
289
265
|
```
|
|
290
266
|
|
|
291
267
|
Filter PRs in interactive selection:
|
|
292
268
|
|
|
293
269
|
```bash
|
|
294
|
-
|
|
270
|
+
ai-review pr-review pr-review --author "John Smith" --target-branch main
|
|
295
271
|
```
|
|
296
272
|
|
|
297
273
|
Choose provider/model via CLI:
|
|
298
274
|
|
|
299
275
|
```bash
|
|
300
|
-
|
|
276
|
+
ai-review pr-review pr-review 42 --provider bedrock --model anthropic.claude-3-5-sonnet-20240620-v1:0
|
|
301
277
|
```
|
|
302
278
|
|
|
303
279
|
### List Pull Requests
|
|
304
280
|
|
|
305
281
|
```bash
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
282
|
+
ai-review pr-review list-prs
|
|
283
|
+
ai-review pr-review list-prs --status completed
|
|
284
|
+
ai-review pr-review list-prs --repo-name backend --author "John"
|
|
309
285
|
```
|
|
310
286
|
|
|
311
287
|
## Execution Flow
|
|
@@ -314,7 +290,7 @@ The diagram below summarizes how the review application moves from CLI entry to
|
|
|
314
290
|
|
|
315
291
|
```mermaid
|
|
316
292
|
flowchart TD
|
|
317
|
-
A[Start:
|
|
293
|
+
A[Start: ai-review pr-review] --> B{Arguments provided?}
|
|
318
294
|
B -->|No| C[Interactive mode]
|
|
319
295
|
B -->|Yes| D[Parse CLI command]
|
|
320
296
|
|
|
@@ -364,7 +340,7 @@ flowchart TD
|
|
|
364
340
|
### `pr-review`
|
|
365
341
|
|
|
366
342
|
```bash
|
|
367
|
-
|
|
343
|
+
ai-review pr-review pr-review [pr_id]
|
|
368
344
|
```
|
|
369
345
|
|
|
370
346
|
Options:
|
|
@@ -388,7 +364,7 @@ Options:
|
|
|
388
364
|
### `list-prs`
|
|
389
365
|
|
|
390
366
|
```bash
|
|
391
|
-
|
|
367
|
+
ai-review pr-review list-prs
|
|
392
368
|
```
|
|
393
369
|
|
|
394
370
|
Options:
|
|
@@ -399,10 +375,10 @@ Options:
|
|
|
399
375
|
|
|
400
376
|
## Available VS Code Tasks
|
|
401
377
|
|
|
402
|
-
-
|
|
403
|
-
-
|
|
404
|
-
-
|
|
405
|
-
-
|
|
378
|
+
- `AI Review: Pull Request (Interactive)`
|
|
379
|
+
- `AI Review: PR (Dry-Run)`
|
|
380
|
+
- `AI Review: List Active PRs`
|
|
381
|
+
- `AI Review: Interactive Mode`
|
|
406
382
|
|
|
407
383
|
## Troubleshooting
|
|
408
384
|
|
|
@@ -424,18 +400,19 @@ Avoid `verify_ssl: false` except for temporary troubleshooting.
|
|
|
424
400
|
- Confirm `llm.model` with a valid Bedrock model ID in the chosen region.
|
|
425
401
|
- Validate AWS credentials (`profile` or explicit keys).
|
|
426
402
|
|
|
427
|
-
##
|
|
403
|
+
## Tests
|
|
428
404
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
405
|
+
The project's functional coverage is reflected in the `tests/` folder, including:
|
|
406
|
+
|
|
407
|
+
- `tests/test_ai_review.py` for the CLI and main workflow
|
|
408
|
+
- `tests/test_config.py` for configuration and validation
|
|
409
|
+
- `tests/test_formatter.py` for terminal/markdown/json rendering
|
|
410
|
+
- `tests/test_git_utils.py` for diffs and Git utilities
|
|
411
|
+
- `tests/test_llm_client.py` for prompts, parsing, and LLM providers
|
|
412
|
+
- `tests/test_tfs_client.py` for TFS/Azure DevOps integration
|
|
413
|
+
|
|
414
|
+
Run the suite:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
python -m pytest --cov=src --cov-report=term
|
|
441
418
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-review-ai-cli"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.1"
|
|
8
8
|
description = "Automated AI-powered code review CLI for Azure DevOps / TFS Pull Requests"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -40,6 +40,7 @@ Version: see pyproject.toml
|
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
42
|
import argparse
|
|
43
|
+
import importlib.resources
|
|
43
44
|
import os
|
|
44
45
|
import sys
|
|
45
46
|
import time
|
|
@@ -872,16 +873,16 @@ def _show_config(config: ReviewConfig) -> None:
|
|
|
872
873
|
# Init command
|
|
873
874
|
# ---------------------------------------------------------------------------
|
|
874
875
|
def cmd_init() -> int:
|
|
875
|
-
"""Copies a config.yaml template to the current working directory.
|
|
876
|
+
"""Copies a config.yaml template and review_prompt.md to the current working directory.
|
|
876
877
|
|
|
877
878
|
Creates a ``config.yaml`` file pre-populated with all available options
|
|
878
|
-
and inline documentation
|
|
879
|
-
|
|
879
|
+
and inline documentation, and a ``review_prompt.md`` file with default
|
|
880
|
+
review style rules. If either file already exists in the current directory
|
|
881
|
+
the user is prompted for confirmation before overwriting.
|
|
880
882
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
was installed.
|
|
883
|
+
Both files are bundled with the package at ``src/prompts/`` and are
|
|
884
|
+
resolved at runtime via :mod:`importlib.resources`, so they work
|
|
885
|
+
regardless of how the package was installed.
|
|
885
886
|
|
|
886
887
|
Returns:
|
|
887
888
|
int: Exit code. ``0`` on success or user cancellation, ``1`` on error.
|
|
@@ -891,14 +892,15 @@ def cmd_init() -> int:
|
|
|
891
892
|
|
|
892
893
|
$ ai-review init
|
|
893
894
|
✅ config.yaml created at: /home/user/my-project/config.yaml
|
|
894
|
-
|
|
895
|
+
✅ review_prompt.md created at: /home/user/my-project/review_prompt.md
|
|
896
|
+
Edit them to add your credentials, preferences and review rules.
|
|
895
897
|
"""
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
dest = os.path.join(os.getcwd(), "config.yaml")
|
|
898
|
+
cwd = os.getcwd()
|
|
899
899
|
c = Colors()
|
|
900
900
|
|
|
901
|
-
|
|
901
|
+
# --- config.yaml ---
|
|
902
|
+
config_dest = os.path.join(cwd, "config.yaml")
|
|
903
|
+
if os.path.exists(config_dest):
|
|
902
904
|
print(f"{c.YELLOW}config.yaml already exists in the current directory.{c.RESET}")
|
|
903
905
|
answer = input("Overwrite? [y/N] ").strip().lower()
|
|
904
906
|
if answer != "y":
|
|
@@ -906,17 +908,38 @@ def cmd_init() -> int:
|
|
|
906
908
|
return 0
|
|
907
909
|
|
|
908
910
|
try:
|
|
909
|
-
ref =
|
|
910
|
-
|
|
911
|
+
ref = importlib.resources.files("src.prompts").joinpath("config.yaml.template")
|
|
912
|
+
config_content = ref.read_text(encoding="utf-8")
|
|
913
|
+
except (FileNotFoundError, TypeError) as exc:
|
|
914
|
+
print(f"{c.RED}Error: could not locate config template: {exc}{c.RESET}")
|
|
915
|
+
return 1
|
|
916
|
+
|
|
917
|
+
with open(config_dest, "w", encoding="utf-8") as fh:
|
|
918
|
+
fh.write(config_content)
|
|
919
|
+
|
|
920
|
+
# --- review_prompt.md ---
|
|
921
|
+
prompt_dest = os.path.join(cwd, "review_prompt.md")
|
|
922
|
+
if os.path.exists(prompt_dest):
|
|
923
|
+
print(f"{c.YELLOW}review_prompt.md already exists in the current directory.{c.RESET}")
|
|
924
|
+
answer = input("Overwrite? [y/N] ").strip().lower()
|
|
925
|
+
if answer != "y":
|
|
926
|
+
print(f"{c.GREEN}✅ config.yaml created at:{c.RESET} {config_dest}")
|
|
927
|
+
print(" Skipped review_prompt.md (kept existing).")
|
|
928
|
+
return 0
|
|
929
|
+
|
|
930
|
+
try:
|
|
931
|
+
ref = importlib.resources.files("src.prompts").joinpath("review_prompt.md.template")
|
|
932
|
+
prompt_content = ref.read_text(encoding="utf-8")
|
|
911
933
|
except (FileNotFoundError, TypeError) as exc:
|
|
912
|
-
print(f"{c.RED}Error: could not locate template
|
|
934
|
+
print(f"{c.RED}Error: could not locate review_prompt template: {exc}{c.RESET}")
|
|
913
935
|
return 1
|
|
914
936
|
|
|
915
|
-
with open(
|
|
916
|
-
fh.write(
|
|
937
|
+
with open(prompt_dest, "w", encoding="utf-8") as fh:
|
|
938
|
+
fh.write(prompt_content)
|
|
917
939
|
|
|
918
|
-
print(f"{c.GREEN}✅ config.yaml created at:{c.RESET} {
|
|
919
|
-
print(f"
|
|
940
|
+
print(f"{c.GREEN}✅ config.yaml created at:{c.RESET} {config_dest}")
|
|
941
|
+
print(f"{c.GREEN}✅ review_prompt.md created at:{c.RESET} {prompt_dest}")
|
|
942
|
+
print(" Edit them to add your credentials, preferences and review rules.")
|
|
920
943
|
return 0
|
|
921
944
|
|
|
922
945
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
## Style Rules
|
|
2
|
+
- Be direct and concise.
|
|
3
|
+
- No greetings.
|
|
4
|
+
- No emojis.
|
|
5
|
+
- Include file and line whenever possible.
|
|
6
|
+
|
|
7
|
+
## Project Context
|
|
8
|
+
- Focus on practical findings that can be posted as PR comments.
|
|
9
|
+
|
|
10
|
+
## Team Preferences
|
|
11
|
+
- Prioritize actionable comments over long explanations.
|
|
12
|
+
- Prefer concrete fix suggestions.
|
|
13
|
+
- Avoid style-only comments unless they affect maintainability.
|
|
14
|
+
|
|
15
|
+
## Good Comment Examples
|
|
16
|
+
- "[src/service.py:128] Missing timeout in external HTTP call. Add timeout and handle exceptions to avoid blocking requests."
|
|
17
|
+
- "[src/auth.py:57] Token is logged in plain text. Remove sensitive data from logs."
|
|
18
|
+
|
|
19
|
+
## Bad Comment Examples
|
|
20
|
+
- "Great work team!"
|
|
21
|
+
- "As a senior reviewer, I think..."
|
|
22
|
+
- "Maybe improve this part"
|
|
23
|
+
|
|
24
|
+
## Universal Rules (all languages)
|
|
25
|
+
|
|
26
|
+
### Security
|
|
27
|
+
- No hardcoded secrets, credentials, or tokens
|
|
28
|
+
- Validate and sanitize all external inputs
|
|
29
|
+
- No SQL/command injection vectors
|
|
30
|
+
- Least privilege principle applied
|
|
31
|
+
|
|
32
|
+
### Code Quality
|
|
33
|
+
- Single Responsibility Principle per function/class
|
|
34
|
+
- No dead code, commented-out blocks, or TODOs without tickets
|
|
35
|
+
- Meaningful names (no abbreviations unless domain-standard)
|
|
36
|
+
- Max function length: \~30 lines; max file: \~300 lines
|
|
37
|
+
- DRY: no duplicated logic
|
|
38
|
+
|
|
39
|
+
### Error Handling
|
|
40
|
+
- Errors must be caught, logged, and propagated correctly
|
|
41
|
+
- No silent catches (`catch {}` or `catch (e) {}`)
|
|
42
|
+
- Use typed/domain exceptions where applicable
|
|
@@ -390,4 +390,165 @@ def test_main_prints_help_when_no_command_is_parsed(mocker) -> None:
|
|
|
390
390
|
mocker.patch("src.ai_review.build_parser", return_value=parser)
|
|
391
391
|
|
|
392
392
|
assert ai_review.main() == 0
|
|
393
|
-
parser.print_help.assert_called_once_with()
|
|
393
|
+
parser.print_help.assert_called_once_with()
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
# ---------------------------------------------------------------------------
|
|
397
|
+
# cmd_init
|
|
398
|
+
# ---------------------------------------------------------------------------
|
|
399
|
+
|
|
400
|
+
def test_cmd_init_creates_both_files(mocker, tmp_path) -> None:
|
|
401
|
+
"""It should create config.yaml and review_prompt.md in the current directory."""
|
|
402
|
+
mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
|
|
403
|
+
mocker.patch(
|
|
404
|
+
"src.ai_review.importlib.resources.files",
|
|
405
|
+
side_effect=_fake_pkg_resources,
|
|
406
|
+
)
|
|
407
|
+
mocker.patch("builtins.print")
|
|
408
|
+
|
|
409
|
+
result = ai_review.cmd_init()
|
|
410
|
+
|
|
411
|
+
assert result == 0
|
|
412
|
+
assert (tmp_path / "config.yaml").read_text() == "config-template"
|
|
413
|
+
assert (tmp_path / "review_prompt.md").read_text() == "prompt-template"
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def test_cmd_init_aborts_when_user_declines_config_overwrite(mocker, tmp_path) -> None:
|
|
417
|
+
"""It should abort without writing either file when user declines config overwrite."""
|
|
418
|
+
(tmp_path / "config.yaml").write_text("existing")
|
|
419
|
+
mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
|
|
420
|
+
mocker.patch("builtins.input", return_value="n")
|
|
421
|
+
mocker.patch("builtins.print")
|
|
422
|
+
|
|
423
|
+
result = ai_review.cmd_init()
|
|
424
|
+
|
|
425
|
+
assert result == 0
|
|
426
|
+
assert (tmp_path / "config.yaml").read_text() == "existing"
|
|
427
|
+
assert not (tmp_path / "review_prompt.md").exists()
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def test_cmd_init_skips_prompt_overwrite_when_user_declines(mocker, tmp_path) -> None:
|
|
431
|
+
"""It should write config.yaml but keep existing review_prompt.md when user declines."""
|
|
432
|
+
(tmp_path / "review_prompt.md").write_text("existing-prompt")
|
|
433
|
+
mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
|
|
434
|
+
mocker.patch(
|
|
435
|
+
"src.ai_review.importlib.resources.files",
|
|
436
|
+
side_effect=_fake_pkg_resources,
|
|
437
|
+
)
|
|
438
|
+
mocker.patch("builtins.input", return_value="n")
|
|
439
|
+
mocker.patch("builtins.print")
|
|
440
|
+
|
|
441
|
+
result = ai_review.cmd_init()
|
|
442
|
+
|
|
443
|
+
assert result == 0
|
|
444
|
+
assert (tmp_path / "config.yaml").read_text() == "config-template"
|
|
445
|
+
assert (tmp_path / "review_prompt.md").read_text() == "existing-prompt"
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def test_cmd_init_returns_error_when_template_missing(mocker, tmp_path) -> None:
|
|
449
|
+
"""It should return 1 when the bundled config template cannot be found."""
|
|
450
|
+
mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
|
|
451
|
+
|
|
452
|
+
def _raise(*args: object, **kwargs: object) -> None:
|
|
453
|
+
raise FileNotFoundError("missing")
|
|
454
|
+
|
|
455
|
+
mocker.patch("src.ai_review.importlib.resources.files", side_effect=_raise)
|
|
456
|
+
mocker.patch("builtins.print")
|
|
457
|
+
|
|
458
|
+
result = ai_review.cmd_init()
|
|
459
|
+
|
|
460
|
+
assert result == 1
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def test_cmd_init_returns_error_when_prompt_template_missing(mocker, tmp_path) -> None:
|
|
464
|
+
"""It should return 1 when the review_prompt.md template cannot be found.
|
|
465
|
+
|
|
466
|
+
config.yaml is already written at that point; the function still surfaces the error.
|
|
467
|
+
"""
|
|
468
|
+
mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
|
|
469
|
+
|
|
470
|
+
class _ConfigOnlyResources(_FakeResource):
|
|
471
|
+
def __init__(self) -> None:
|
|
472
|
+
super().__init__("")
|
|
473
|
+
|
|
474
|
+
def joinpath(self, name: str) -> "_FakeResource":
|
|
475
|
+
if name == "config.yaml.template":
|
|
476
|
+
return _FakeResource("config-template")
|
|
477
|
+
raise FileNotFoundError(name)
|
|
478
|
+
|
|
479
|
+
mocker.patch(
|
|
480
|
+
"src.ai_review.importlib.resources.files",
|
|
481
|
+
return_value=_ConfigOnlyResources(),
|
|
482
|
+
)
|
|
483
|
+
mocker.patch("builtins.print")
|
|
484
|
+
|
|
485
|
+
result = ai_review.cmd_init()
|
|
486
|
+
|
|
487
|
+
assert result == 1
|
|
488
|
+
# config.yaml was already written before the error
|
|
489
|
+
assert (tmp_path / "config.yaml").read_text() == "config-template"
|
|
490
|
+
assert not (tmp_path / "review_prompt.md").exists()
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def test_cmd_init_overwrites_both_files_when_user_accepts(mocker, tmp_path) -> None:
|
|
494
|
+
"""It should overwrite both existing files when the user confirms both prompts."""
|
|
495
|
+
(tmp_path / "config.yaml").write_text("old-config")
|
|
496
|
+
(tmp_path / "review_prompt.md").write_text("old-prompt")
|
|
497
|
+
mocker.patch("src.ai_review.os.getcwd", return_value=str(tmp_path))
|
|
498
|
+
mocker.patch(
|
|
499
|
+
"src.ai_review.importlib.resources.files",
|
|
500
|
+
side_effect=_fake_pkg_resources,
|
|
501
|
+
)
|
|
502
|
+
mocker.patch("builtins.input", return_value="y")
|
|
503
|
+
mocker.patch("builtins.print")
|
|
504
|
+
|
|
505
|
+
result = ai_review.cmd_init()
|
|
506
|
+
|
|
507
|
+
assert result == 0
|
|
508
|
+
assert (tmp_path / "config.yaml").read_text() == "config-template"
|
|
509
|
+
assert (tmp_path / "review_prompt.md").read_text() == "prompt-template"
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def test_main_dispatches_to_cmd_init(mocker) -> None:
|
|
513
|
+
"""It should call cmd_init when the init subcommand is provided."""
|
|
514
|
+
mocker.patch("src.ai_review.sys.argv", ["ai_review.py", "init"])
|
|
515
|
+
cmd_init_mock = mocker.patch("src.ai_review.cmd_init", return_value=0)
|
|
516
|
+
|
|
517
|
+
result = ai_review.main()
|
|
518
|
+
|
|
519
|
+
assert result == 0
|
|
520
|
+
cmd_init_mock.assert_called_once_with()
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
# ---------------------------------------------------------------------------
|
|
524
|
+
# Helpers for cmd_init tests
|
|
525
|
+
# ---------------------------------------------------------------------------
|
|
526
|
+
|
|
527
|
+
class _FakeResource:
|
|
528
|
+
"""Minimal stand-in for an importlib.resources path object."""
|
|
529
|
+
|
|
530
|
+
def __init__(self, text: str) -> None:
|
|
531
|
+
self._text = text
|
|
532
|
+
|
|
533
|
+
def joinpath(self, name: str) -> "_FakeResource":
|
|
534
|
+
return self
|
|
535
|
+
|
|
536
|
+
def read_text(self, encoding: str = "utf-8") -> str:
|
|
537
|
+
return self._text
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def _fake_pkg_resources(package: str) -> _FakeResource:
|
|
541
|
+
"""Return a fake resource root whose joinpath distinguishes template names."""
|
|
542
|
+
|
|
543
|
+
class _Dispatcher(_FakeResource):
|
|
544
|
+
def __init__(self) -> None:
|
|
545
|
+
super().__init__("")
|
|
546
|
+
|
|
547
|
+
def joinpath(self, name: str) -> _FakeResource:
|
|
548
|
+
if name == "config.yaml.template":
|
|
549
|
+
return _FakeResource("config-template")
|
|
550
|
+
if name == "review_prompt.md.template":
|
|
551
|
+
return _FakeResource("prompt-template")
|
|
552
|
+
raise FileNotFoundError(name)
|
|
553
|
+
|
|
554
|
+
return _Dispatcher()
|
|
File without changes
|
{code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/requires.txt
RENAMED
|
File without changes
|
{code_review_ai_cli-1.0.0 → code_review_ai_cli-1.0.1}/code_review_ai_cli.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|