code-review-ai-cli 2.1.0__tar.gz → 2.2.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-2.2.1/PKG-INFO +146 -0
- code_review_ai_cli-2.2.1/README.md +106 -0
- code_review_ai_cli-2.2.1/code_review_ai_cli.egg-info/PKG-INFO +146 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/pyproject.toml +1 -1
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/ai_review.py +3 -12
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/config.py +3 -1
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/git_utils.py +0 -38
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/prompts/config.yaml.template +8 -2
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/tfs_client.py +59 -10
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/tests/test_config.py +386 -360
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/tests/test_git_utils.py +156 -162
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/tests/test_tfs_client.py +197 -2
- code_review_ai_cli-2.1.0/PKG-INFO +0 -433
- code_review_ai_cli-2.1.0/README.md +0 -393
- code_review_ai_cli-2.1.0/code_review_ai_cli.egg-info/PKG-INFO +0 -433
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/code_review_ai_cli.egg-info/SOURCES.txt +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/code_review_ai_cli.egg-info/dependency_links.txt +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/code_review_ai_cli.egg-info/entry_points.txt +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/code_review_ai_cli.egg-info/requires.txt +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/code_review_ai_cli.egg-info/top_level.txt +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/setup.cfg +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/__init__.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/context_extractor.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/formatter.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/llm_client.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/prompt_utils.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/src/prompts/review_prompt.md.template +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/tests/test_ai_review.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/tests/test_context_extractor.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/tests/test_formatter.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/tests/test_llm_client.py +0 -0
- {code_review_ai_cli-2.1.0 → code_review_ai_cli-2.2.1}/tests/test_prompt_utils.py +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: code-review-ai-cli
|
|
3
|
+
Version: 2.2.1
|
|
4
|
+
Summary: Automated AI-powered code review CLI for Azure DevOps / TFS Pull Requests
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: code-review,ai,azure-devops,tfs,pull-request,llm
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: requests>=2.28.0
|
|
19
|
+
Requires-Dist: PyYAML>=6.0
|
|
20
|
+
Provides-Extra: bedrock
|
|
21
|
+
Requires-Dist: boto3>=1.34.0; extra == "bedrock"
|
|
22
|
+
Provides-Extra: openai
|
|
23
|
+
Requires-Dist: openai>=1.0.0; extra == "openai"
|
|
24
|
+
Provides-Extra: gemini
|
|
25
|
+
Requires-Dist: google-generativeai>=0.3.0; extra == "gemini"
|
|
26
|
+
Provides-Extra: claude
|
|
27
|
+
Requires-Dist: anthropic>=0.18.0; extra == "claude"
|
|
28
|
+
Provides-Extra: tree-sitter
|
|
29
|
+
Requires-Dist: tree-sitter-languages>=1.10.2; extra == "tree-sitter"
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: boto3>=1.34.0; extra == "all"
|
|
32
|
+
Requires-Dist: openai>=1.0.0; extra == "all"
|
|
33
|
+
Requires-Dist: google-generativeai>=0.3.0; extra == "all"
|
|
34
|
+
Requires-Dist: anthropic>=0.18.0; extra == "all"
|
|
35
|
+
Requires-Dist: tree-sitter-languages>=1.10.2; extra == "all"
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=8.3.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
|
|
40
|
+
|
|
41
|
+
# AI Code Review
|
|
42
|
+
|
|
43
|
+
AI Code Review is an automated AI-powered code review CLI, compatible with various LLM providers, designed for integration with Azure DevOps, whether in the cloud or on-premises. It allows you to run a review on demand or as part of a pipeline triggered before a commit or when a pull request is created.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- AI Pull Request review (`pr-review`)
|
|
48
|
+
- Structured PR comments (inline + general summary)
|
|
49
|
+
- `dry-run` mode to validate without posting
|
|
50
|
+
- PR listing with filters (`list-prs`)
|
|
51
|
+
- Configuration exclusively via `config.yaml`
|
|
52
|
+
- Providers LLM: OpenAI, Azure OpenAI, Gemini, Claude, Ollama, GitHub Copilot, AWS Bedrock
|
|
53
|
+
- Diff filtering by **excluded path prefixes** (`excluded_paths`) and/or **file extensions** (`file_extensions_filter`)
|
|
54
|
+
|
|
55
|
+
## Documentation
|
|
56
|
+
|
|
57
|
+
- [Configuration Guide](docs/configuration.md) - Details on YAML parameters and settings.
|
|
58
|
+
- [Commands Reference](docs/commands.md) - Complete list of CLI commands and arguments.
|
|
59
|
+
- [Execution Flow](docs/execution_flow.md) - Mermaid diagram of the application's lifecycle.
|
|
60
|
+
- [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions.
|
|
61
|
+
|
|
62
|
+
## Output Review Format
|
|
63
|
+
|
|
64
|
+

|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
Install from PyPI:
|
|
69
|
+
s
|
|
70
|
+
```bash
|
|
71
|
+
pip install code-review-ai-cli
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
After installing the package, generate ready-to-edit configuration files in your working directory:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
ai-review init
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This copies two bundled templates:
|
|
81
|
+
|
|
82
|
+
- **`config.yaml`** — all available options with inline documentation
|
|
83
|
+
- **`review_prompt.md`** — default review style rules, injected into every LLM prompt
|
|
84
|
+
|
|
85
|
+
The tool looks for `config.yaml` in the **current working directory** at runtime. You can also pass a different path with `--config`:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ai-review pr-review --config ~/configs/ai-review.yaml
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If you plan to run the test suite locally, also install development dependencies:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install "code-review-ai-cli[dev]"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Minimal Example
|
|
98
|
+
|
|
99
|
+
Example `config.yaml`:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
llm:
|
|
103
|
+
provider: openai
|
|
104
|
+
model: gpt-4o
|
|
105
|
+
|
|
106
|
+
openai:
|
|
107
|
+
api_key: sk-xxxx
|
|
108
|
+
|
|
109
|
+
tfs:
|
|
110
|
+
base_url: https://dev.azure.com/your-organization
|
|
111
|
+
project: ProjectName
|
|
112
|
+
pat: xxxxxxxxx
|
|
113
|
+
verify_ssl: true
|
|
114
|
+
# ca_bundle: C:/certs/corporate-root-ca.pem
|
|
115
|
+
|
|
116
|
+
review:
|
|
117
|
+
verbosity: detailed
|
|
118
|
+
scope: diff_only
|
|
119
|
+
custom_prompt_file: review_prompt.md
|
|
120
|
+
# file limit sent to the LLM
|
|
121
|
+
max_diff_files: 50
|
|
122
|
+
# per-file limit
|
|
123
|
+
max_diff_lines: 2000
|
|
124
|
+
# extension allowlist (empty list = all files)
|
|
125
|
+
file_extensions_filter: [".cs", ".ts", ".py"]
|
|
126
|
+
# exclude path prefixes from the diff (applied before file_extensions_filter)
|
|
127
|
+
# leading slash is optional; add trailing slash for exact folder boundary
|
|
128
|
+
excluded_paths: ["libs/generated"]
|
|
129
|
+
|
|
130
|
+
pr:
|
|
131
|
+
auto_post_comments: false
|
|
132
|
+
dry_run: false
|
|
133
|
+
comment_mode: structured
|
|
134
|
+
|
|
135
|
+
output:
|
|
136
|
+
format: terminal
|
|
137
|
+
file: ""
|
|
138
|
+
color: true
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Available VS Code Tasks
|
|
142
|
+
|
|
143
|
+
- `AI Review: Pull Request (Interactive)`
|
|
144
|
+
- `AI Review: PR (Dry-Run)`
|
|
145
|
+
- `AI Review: List Active PRs`
|
|
146
|
+
- `AI Review: Interactive Mode`
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# AI Code Review
|
|
2
|
+
|
|
3
|
+
AI Code Review is an automated AI-powered code review CLI, compatible with various LLM providers, designed for integration with Azure DevOps, whether in the cloud or on-premises. It allows you to run a review on demand or as part of a pipeline triggered before a commit or when a pull request is created.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- AI Pull Request review (`pr-review`)
|
|
8
|
+
- Structured PR comments (inline + general summary)
|
|
9
|
+
- `dry-run` mode to validate without posting
|
|
10
|
+
- PR listing with filters (`list-prs`)
|
|
11
|
+
- Configuration exclusively via `config.yaml`
|
|
12
|
+
- Providers LLM: OpenAI, Azure OpenAI, Gemini, Claude, Ollama, GitHub Copilot, AWS Bedrock
|
|
13
|
+
- Diff filtering by **excluded path prefixes** (`excluded_paths`) and/or **file extensions** (`file_extensions_filter`)
|
|
14
|
+
|
|
15
|
+
## Documentation
|
|
16
|
+
|
|
17
|
+
- [Configuration Guide](docs/configuration.md) - Details on YAML parameters and settings.
|
|
18
|
+
- [Commands Reference](docs/commands.md) - Complete list of CLI commands and arguments.
|
|
19
|
+
- [Execution Flow](docs/execution_flow.md) - Mermaid diagram of the application's lifecycle.
|
|
20
|
+
- [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions.
|
|
21
|
+
|
|
22
|
+
## Output Review Format
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
Install from PyPI:
|
|
29
|
+
s
|
|
30
|
+
```bash
|
|
31
|
+
pip install code-review-ai-cli
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
After installing the package, generate ready-to-edit configuration files in your working directory:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ai-review init
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This copies two bundled templates:
|
|
41
|
+
|
|
42
|
+
- **`config.yaml`** — all available options with inline documentation
|
|
43
|
+
- **`review_prompt.md`** — default review style rules, injected into every LLM prompt
|
|
44
|
+
|
|
45
|
+
The tool looks for `config.yaml` in the **current working directory** at runtime. You can also pass a different path with `--config`:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ai-review pr-review --config ~/configs/ai-review.yaml
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
If you plan to run the test suite locally, also install development dependencies:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install "code-review-ai-cli[dev]"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Minimal Example
|
|
58
|
+
|
|
59
|
+
Example `config.yaml`:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
llm:
|
|
63
|
+
provider: openai
|
|
64
|
+
model: gpt-4o
|
|
65
|
+
|
|
66
|
+
openai:
|
|
67
|
+
api_key: sk-xxxx
|
|
68
|
+
|
|
69
|
+
tfs:
|
|
70
|
+
base_url: https://dev.azure.com/your-organization
|
|
71
|
+
project: ProjectName
|
|
72
|
+
pat: xxxxxxxxx
|
|
73
|
+
verify_ssl: true
|
|
74
|
+
# ca_bundle: C:/certs/corporate-root-ca.pem
|
|
75
|
+
|
|
76
|
+
review:
|
|
77
|
+
verbosity: detailed
|
|
78
|
+
scope: diff_only
|
|
79
|
+
custom_prompt_file: review_prompt.md
|
|
80
|
+
# file limit sent to the LLM
|
|
81
|
+
max_diff_files: 50
|
|
82
|
+
# per-file limit
|
|
83
|
+
max_diff_lines: 2000
|
|
84
|
+
# extension allowlist (empty list = all files)
|
|
85
|
+
file_extensions_filter: [".cs", ".ts", ".py"]
|
|
86
|
+
# exclude path prefixes from the diff (applied before file_extensions_filter)
|
|
87
|
+
# leading slash is optional; add trailing slash for exact folder boundary
|
|
88
|
+
excluded_paths: ["libs/generated"]
|
|
89
|
+
|
|
90
|
+
pr:
|
|
91
|
+
auto_post_comments: false
|
|
92
|
+
dry_run: false
|
|
93
|
+
comment_mode: structured
|
|
94
|
+
|
|
95
|
+
output:
|
|
96
|
+
format: terminal
|
|
97
|
+
file: ""
|
|
98
|
+
color: true
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Available VS Code Tasks
|
|
102
|
+
|
|
103
|
+
- `AI Review: Pull Request (Interactive)`
|
|
104
|
+
- `AI Review: PR (Dry-Run)`
|
|
105
|
+
- `AI Review: List Active PRs`
|
|
106
|
+
- `AI Review: Interactive Mode`
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: code-review-ai-cli
|
|
3
|
+
Version: 2.2.1
|
|
4
|
+
Summary: Automated AI-powered code review CLI for Azure DevOps / TFS Pull Requests
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: code-review,ai,azure-devops,tfs,pull-request,llm
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: requests>=2.28.0
|
|
19
|
+
Requires-Dist: PyYAML>=6.0
|
|
20
|
+
Provides-Extra: bedrock
|
|
21
|
+
Requires-Dist: boto3>=1.34.0; extra == "bedrock"
|
|
22
|
+
Provides-Extra: openai
|
|
23
|
+
Requires-Dist: openai>=1.0.0; extra == "openai"
|
|
24
|
+
Provides-Extra: gemini
|
|
25
|
+
Requires-Dist: google-generativeai>=0.3.0; extra == "gemini"
|
|
26
|
+
Provides-Extra: claude
|
|
27
|
+
Requires-Dist: anthropic>=0.18.0; extra == "claude"
|
|
28
|
+
Provides-Extra: tree-sitter
|
|
29
|
+
Requires-Dist: tree-sitter-languages>=1.10.2; extra == "tree-sitter"
|
|
30
|
+
Provides-Extra: all
|
|
31
|
+
Requires-Dist: boto3>=1.34.0; extra == "all"
|
|
32
|
+
Requires-Dist: openai>=1.0.0; extra == "all"
|
|
33
|
+
Requires-Dist: google-generativeai>=0.3.0; extra == "all"
|
|
34
|
+
Requires-Dist: anthropic>=0.18.0; extra == "all"
|
|
35
|
+
Requires-Dist: tree-sitter-languages>=1.10.2; extra == "all"
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=8.3.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
|
|
40
|
+
|
|
41
|
+
# AI Code Review
|
|
42
|
+
|
|
43
|
+
AI Code Review is an automated AI-powered code review CLI, compatible with various LLM providers, designed for integration with Azure DevOps, whether in the cloud or on-premises. It allows you to run a review on demand or as part of a pipeline triggered before a commit or when a pull request is created.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- AI Pull Request review (`pr-review`)
|
|
48
|
+
- Structured PR comments (inline + general summary)
|
|
49
|
+
- `dry-run` mode to validate without posting
|
|
50
|
+
- PR listing with filters (`list-prs`)
|
|
51
|
+
- Configuration exclusively via `config.yaml`
|
|
52
|
+
- Providers LLM: OpenAI, Azure OpenAI, Gemini, Claude, Ollama, GitHub Copilot, AWS Bedrock
|
|
53
|
+
- Diff filtering by **excluded path prefixes** (`excluded_paths`) and/or **file extensions** (`file_extensions_filter`)
|
|
54
|
+
|
|
55
|
+
## Documentation
|
|
56
|
+
|
|
57
|
+
- [Configuration Guide](docs/configuration.md) - Details on YAML parameters and settings.
|
|
58
|
+
- [Commands Reference](docs/commands.md) - Complete list of CLI commands and arguments.
|
|
59
|
+
- [Execution Flow](docs/execution_flow.md) - Mermaid diagram of the application's lifecycle.
|
|
60
|
+
- [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions.
|
|
61
|
+
|
|
62
|
+
## Output Review Format
|
|
63
|
+
|
|
64
|
+

|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
Install from PyPI:
|
|
69
|
+
s
|
|
70
|
+
```bash
|
|
71
|
+
pip install code-review-ai-cli
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
After installing the package, generate ready-to-edit configuration files in your working directory:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
ai-review init
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This copies two bundled templates:
|
|
81
|
+
|
|
82
|
+
- **`config.yaml`** — all available options with inline documentation
|
|
83
|
+
- **`review_prompt.md`** — default review style rules, injected into every LLM prompt
|
|
84
|
+
|
|
85
|
+
The tool looks for `config.yaml` in the **current working directory** at runtime. You can also pass a different path with `--config`:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ai-review pr-review --config ~/configs/ai-review.yaml
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If you plan to run the test suite locally, also install development dependencies:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install "code-review-ai-cli[dev]"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Minimal Example
|
|
98
|
+
|
|
99
|
+
Example `config.yaml`:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
llm:
|
|
103
|
+
provider: openai
|
|
104
|
+
model: gpt-4o
|
|
105
|
+
|
|
106
|
+
openai:
|
|
107
|
+
api_key: sk-xxxx
|
|
108
|
+
|
|
109
|
+
tfs:
|
|
110
|
+
base_url: https://dev.azure.com/your-organization
|
|
111
|
+
project: ProjectName
|
|
112
|
+
pat: xxxxxxxxx
|
|
113
|
+
verify_ssl: true
|
|
114
|
+
# ca_bundle: C:/certs/corporate-root-ca.pem
|
|
115
|
+
|
|
116
|
+
review:
|
|
117
|
+
verbosity: detailed
|
|
118
|
+
scope: diff_only
|
|
119
|
+
custom_prompt_file: review_prompt.md
|
|
120
|
+
# file limit sent to the LLM
|
|
121
|
+
max_diff_files: 50
|
|
122
|
+
# per-file limit
|
|
123
|
+
max_diff_lines: 2000
|
|
124
|
+
# extension allowlist (empty list = all files)
|
|
125
|
+
file_extensions_filter: [".cs", ".ts", ".py"]
|
|
126
|
+
# exclude path prefixes from the diff (applied before file_extensions_filter)
|
|
127
|
+
# leading slash is optional; add trailing slash for exact folder boundary
|
|
128
|
+
excluded_paths: ["libs/generated"]
|
|
129
|
+
|
|
130
|
+
pr:
|
|
131
|
+
auto_post_comments: false
|
|
132
|
+
dry_run: false
|
|
133
|
+
comment_mode: structured
|
|
134
|
+
|
|
135
|
+
output:
|
|
136
|
+
format: terminal
|
|
137
|
+
file: ""
|
|
138
|
+
color: true
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Available VS Code Tasks
|
|
142
|
+
|
|
143
|
+
- `AI Review: Pull Request (Interactive)`
|
|
144
|
+
- `AI Review: PR (Dry-Run)`
|
|
145
|
+
- `AI Review: List Active PRs`
|
|
146
|
+
- `AI Review: Interactive Mode`
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-review-ai-cli"
|
|
7
|
-
version = "2.1
|
|
7
|
+
version = "2.2.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"
|
|
@@ -79,7 +79,7 @@ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
79
79
|
PROJECT_ROOT = _ensure_project_root_on_path(__file__)
|
|
80
80
|
|
|
81
81
|
from src.config import ReviewConfig, VALID_PROVIDERS # noqa: E402
|
|
82
|
-
from src.git_utils import GitUtils
|
|
82
|
+
from src.git_utils import GitUtils # noqa: E402
|
|
83
83
|
from src.llm_client import LLMClient, LLMError # noqa: E402
|
|
84
84
|
from src.formatter import ReviewFormatter, Colors, save_output # noqa: E402
|
|
85
85
|
from src import __version__ as VERSION # noqa: E402
|
|
@@ -426,6 +426,8 @@ def run_pr_review_workflow(args: argparse.Namespace, config: ReviewConfig,
|
|
|
426
426
|
repo_name,
|
|
427
427
|
pr_id,
|
|
428
428
|
review_scope=config.review_scope,
|
|
429
|
+
excluded_paths=config.excluded_paths or None,
|
|
430
|
+
file_extensions_filter=config.file_extensions_filter or None,
|
|
429
431
|
)
|
|
430
432
|
except TFSError as exc:
|
|
431
433
|
print(formatter.format_error(str(exc)))
|
|
@@ -451,17 +453,6 @@ def run_pr_review_workflow(args: argparse.Namespace, config: ReviewConfig,
|
|
|
451
453
|
git_utils = GitUtils.__new__(GitUtils)
|
|
452
454
|
git_utils.repo_path = os.getcwd()
|
|
453
455
|
|
|
454
|
-
# Filter extensions before limiting/truncating the diff sent to the LLM
|
|
455
|
-
if config.file_extensions_filter:
|
|
456
|
-
try:
|
|
457
|
-
diff = git_utils.filter_diff_by_extensions(
|
|
458
|
-
diff,
|
|
459
|
-
config.file_extensions_filter,
|
|
460
|
-
)
|
|
461
|
-
except GitError as exc:
|
|
462
|
-
print(formatter.format_warning(str(exc)))
|
|
463
|
-
return 0
|
|
464
|
-
|
|
465
456
|
# Keep only added lines (+): ignore context and removed lines
|
|
466
457
|
diff = git_utils.filter_diff_additions_only(diff)
|
|
467
458
|
if not diff.strip():
|
|
@@ -93,7 +93,8 @@ class ReviewConfig:
|
|
|
93
93
|
max_scope_lines: int = 250 # Max lines in a single scope block before fallback to file_skeleton
|
|
94
94
|
adaptive_context_lines: int = 10 # Context lines for Adaptive Diff fallback
|
|
95
95
|
custom_prompt_file: str = "review_prompt.md" # Markdown file with extra rules/context
|
|
96
|
-
file_extensions_filter: list = field(default_factory=list)
|
|
96
|
+
file_extensions_filter: list = field(default_factory=list) # File extensions to include (empty = all)
|
|
97
|
+
excluded_paths: list = field(default_factory=list) # Folder path segments to exclude from diff
|
|
97
98
|
|
|
98
99
|
# --- PR Review ----------------------------------------------------
|
|
99
100
|
auto_post_comments: bool = False # Post comments automatically
|
|
@@ -222,6 +223,7 @@ class ReviewConfig:
|
|
|
222
223
|
"adaptive_context_lines": ("review", "adaptive_context_lines"),
|
|
223
224
|
"custom_prompt_file": ("review", "custom_prompt_file"),
|
|
224
225
|
"file_extensions_filter": ("review", "file_extensions_filter"),
|
|
226
|
+
"excluded_paths": ("review", "excluded_paths"),
|
|
225
227
|
# PR
|
|
226
228
|
"auto_post_comments": ("pr", "auto_post_comments"),
|
|
227
229
|
"dry_run": ("pr", "dry_run"),
|
|
@@ -189,44 +189,6 @@ class GitUtils:
|
|
|
189
189
|
)
|
|
190
190
|
return limited, True, omitted_files
|
|
191
191
|
|
|
192
|
-
def filter_diff_by_extensions(self, diff: str, extensions: list[str]) -> str:
|
|
193
|
-
"""
|
|
194
|
-
Filters the diff to include only files with specific extensions.
|
|
195
|
-
|
|
196
|
-
Args:
|
|
197
|
-
diff: The full diff.
|
|
198
|
-
extensions: List of extensions (e.g., ['.py', '.js', '.cs']).
|
|
199
|
-
"""
|
|
200
|
-
if not extensions:
|
|
201
|
-
return diff
|
|
202
|
-
|
|
203
|
-
filtered_sections = []
|
|
204
|
-
current_section: list[str] = []
|
|
205
|
-
include_section = False
|
|
206
|
-
|
|
207
|
-
for line in diff.split("\n"):
|
|
208
|
-
if line.startswith("diff --git"):
|
|
209
|
-
# Save previous section if applicable
|
|
210
|
-
if include_section and current_section:
|
|
211
|
-
filtered_sections.append("\n".join(current_section))
|
|
212
|
-
current_section = [line]
|
|
213
|
-
# Check if file has an allowed extension
|
|
214
|
-
file_path = line.split(" b/")[-1] if " b/" in line else ""
|
|
215
|
-
include_section = any(file_path.endswith(ext) for ext in extensions)
|
|
216
|
-
else:
|
|
217
|
-
current_section.append(line)
|
|
218
|
-
|
|
219
|
-
# Last section
|
|
220
|
-
if include_section and current_section:
|
|
221
|
-
filtered_sections.append("\n".join(current_section))
|
|
222
|
-
|
|
223
|
-
result = "\n".join(filtered_sections)
|
|
224
|
-
if not result.strip():
|
|
225
|
-
raise GitError(
|
|
226
|
-
f"After filtering by extensions {extensions}, no changes remain."
|
|
227
|
-
)
|
|
228
|
-
return result
|
|
229
|
-
|
|
230
192
|
def truncate_diff(self, diff: str, max_lines: int = 2000) -> tuple[str, bool]:
|
|
231
193
|
"""
|
|
232
194
|
Kept for compatibility: applies per-file truncation when
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
llm:
|
|
14
14
|
provider: openai
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
# Model to use (empty = provider default)
|
|
17
17
|
# Examples:
|
|
18
18
|
# openai: gpt-4o, gpt-4-turbo, gpt-4
|
|
19
19
|
# gemini: gemini-1.5-pro, gemini-pro, gemini-2.0-flash
|
|
@@ -91,7 +91,7 @@ review:
|
|
|
91
91
|
max_diff_lines: 4500
|
|
92
92
|
|
|
93
93
|
# Max changed logical blocks for Enclosing Scopes strategy (diff_only mode)
|
|
94
|
-
max_scope_blocks:
|
|
94
|
+
max_scope_blocks: 10
|
|
95
95
|
|
|
96
96
|
# Max lines in a single enclosing scope before falling back to file_skeleton
|
|
97
97
|
# (prevents sending entire large classes to the LLM)
|
|
@@ -100,6 +100,12 @@ review:
|
|
|
100
100
|
# Surrounding lines to keep for Adaptive Diff fallback (diff_only mode)
|
|
101
101
|
adaptive_context_lines: 10
|
|
102
102
|
|
|
103
|
+
# Exclude paths from the diff by prefix (empty list = no exclusions).
|
|
104
|
+
# Files whose path starts with a listed prefix are excluded.
|
|
105
|
+
# Matching is case-insensitive.
|
|
106
|
+
# Example: ["IoT/_input/packages", "libs/generated"]
|
|
107
|
+
excluded_paths: []
|
|
108
|
+
|
|
103
109
|
# Filter by file extensions (empty list = all files)
|
|
104
110
|
# Example: [".cs", ".ts"]
|
|
105
111
|
file_extensions_filter: []
|
|
@@ -290,18 +290,23 @@ class TFSClient:
|
|
|
290
290
|
|
|
291
291
|
files = []
|
|
292
292
|
for change in changes.get("changeEntries", []):
|
|
293
|
-
item
|
|
293
|
+
# `item` can be null for deleted files; use `or {}` as a safe fallback.
|
|
294
|
+
item = change.get("item") or {}
|
|
294
295
|
if item.get("isFolder"):
|
|
295
296
|
continue
|
|
297
|
+
# `path` can be null for deleted files; fall back to `originalPath`.
|
|
298
|
+
path = item.get("path") or change.get("originalPath") or ""
|
|
296
299
|
files.append({
|
|
297
|
-
"path":
|
|
300
|
+
"path": path,
|
|
298
301
|
"change_type": change.get("changeType", "unknown"),
|
|
299
|
-
"original_path": change.get("originalPath"
|
|
302
|
+
"original_path": change.get("originalPath") or path,
|
|
300
303
|
})
|
|
301
304
|
return files
|
|
302
305
|
|
|
303
306
|
def get_pull_request_diff(self, repository: str, pr_id: int,
|
|
304
|
-
review_scope: str = "diff_only"
|
|
307
|
+
review_scope: str = "diff_only",
|
|
308
|
+
excluded_paths: list[str] | None = None,
|
|
309
|
+
file_extensions_filter: list[str] | None = None) -> str:
|
|
305
310
|
"""
|
|
306
311
|
Gets the diff of a specific Pull Request.
|
|
307
312
|
|
|
@@ -317,16 +322,28 @@ class TFSClient:
|
|
|
317
322
|
with ``+``, producing a pseudo-diff that represents the complete file
|
|
318
323
|
as added content.
|
|
319
324
|
|
|
325
|
+
Files are filtered **before** any HTTP content request is made, so
|
|
326
|
+
excluded or extension-mismatched files incur no network cost.
|
|
327
|
+
|
|
320
328
|
Args:
|
|
321
329
|
repository: Repository name.
|
|
322
330
|
pr_id: Pull Request ID.
|
|
323
331
|
review_scope: ``"diff_only"`` (default) or ``"full_code"``.
|
|
332
|
+
excluded_paths: List of path prefixes to skip (case-insensitive,
|
|
333
|
+
leading slash optional). Files whose path starts with any
|
|
334
|
+
prefix are excluded before content is fetched.
|
|
335
|
+
Example: ``["/Libs/", "/IoT/_input/packages"]``.
|
|
336
|
+
file_extensions_filter: Allowlist of file extensions
|
|
337
|
+
(case-insensitive). When non-empty, only files whose path ends
|
|
338
|
+
with one of the listed extensions are processed.
|
|
339
|
+
Example: ``[".cs", ".ts"]``.
|
|
324
340
|
|
|
325
341
|
Returns:
|
|
326
342
|
Diff as text, ready to be passed to the LLM client.
|
|
327
343
|
|
|
328
344
|
Raises:
|
|
329
|
-
TFSError: If the PR has no iterations or contains no file changes
|
|
345
|
+
TFSError: If the PR has no iterations or contains no file changes
|
|
346
|
+
after filtering.
|
|
330
347
|
"""
|
|
331
348
|
# Get PR details
|
|
332
349
|
path = f"git/repositories/{repository}/pullrequests/{pr_id}"
|
|
@@ -352,17 +369,48 @@ class TFSClient:
|
|
|
352
369
|
|
|
353
370
|
review_scope = (review_scope or "diff_only").lower()
|
|
354
371
|
|
|
372
|
+
# Normalise filters once before the loop (forward slashes, lower-case).
|
|
373
|
+
# excluded_paths: strip optional leading slash so "Libs/" == "/Libs/".
|
|
374
|
+
_excl_prefixes = [
|
|
375
|
+
p.replace("\\", "/").lstrip("/").lower()
|
|
376
|
+
for p in (excluded_paths or [])
|
|
377
|
+
]
|
|
378
|
+
_ext_filter = [e.lower() for e in (file_extensions_filter or [])]
|
|
379
|
+
|
|
355
380
|
# Build diff from the changes
|
|
356
381
|
diff_parts = []
|
|
357
382
|
for change in changes.get("changeEntries", []):
|
|
358
|
-
item
|
|
383
|
+
# `item` can be null for deleted files; use `or {}` as a safe fallback.
|
|
384
|
+
item = change.get("item") or {}
|
|
359
385
|
change_type = change.get("changeType", "unknown")
|
|
360
|
-
file_path = item.get("path", "unknown")
|
|
361
|
-
original_path = change.get("originalPath") or file_path
|
|
362
386
|
|
|
363
387
|
if item.get("isFolder"):
|
|
364
388
|
continue
|
|
365
389
|
|
|
390
|
+
# Deleted files are skipped from the LLM diff.
|
|
391
|
+
# They are still reported in the terminal summary via _get_pr_changed_files.
|
|
392
|
+
if change_type == "delete":
|
|
393
|
+
continue
|
|
394
|
+
|
|
395
|
+
# `path` can be null; fall back to `originalPath` (safe for add/edit/rename).
|
|
396
|
+
file_path = item.get("path") or change.get("originalPath") or "unknown"
|
|
397
|
+
original_path = change.get("originalPath") or file_path
|
|
398
|
+
|
|
399
|
+
# --- Early-exit filters (no HTTP request made for skipped files) ---
|
|
400
|
+
# Normalise once: strip leading slash, lower-case, forward slashes.
|
|
401
|
+
norm_path = file_path.replace("\\", "/").lstrip("/").lower()
|
|
402
|
+
|
|
403
|
+
if _excl_prefixes and any(
|
|
404
|
+
norm_path.startswith(excl) for excl in _excl_prefixes
|
|
405
|
+
):
|
|
406
|
+
continue
|
|
407
|
+
|
|
408
|
+
if _ext_filter and not any(
|
|
409
|
+
norm_path.endswith(ext) for ext in _ext_filter
|
|
410
|
+
):
|
|
411
|
+
continue
|
|
412
|
+
# ------------------------------------------------------------------
|
|
413
|
+
|
|
366
414
|
if review_scope == "full_code":
|
|
367
415
|
diff_parts.extend(
|
|
368
416
|
self._build_full_code_diff_part(
|
|
@@ -388,7 +436,7 @@ class TFSClient:
|
|
|
388
436
|
diff_parts.append("")
|
|
389
437
|
|
|
390
438
|
if not diff_parts:
|
|
391
|
-
raise TFSError(f"PR #{pr_id} contains no file changes.")
|
|
439
|
+
raise TFSError(f"PR #{pr_id} contains no file changes after filtering.")
|
|
392
440
|
|
|
393
441
|
return "\n".join(diff_parts)
|
|
394
442
|
|
|
@@ -463,7 +511,8 @@ class TFSClient:
|
|
|
463
511
|
file_path: Server path of the new version of the file.
|
|
464
512
|
original_path: Server path of the old version (differs on renames).
|
|
465
513
|
change_type: TFS change type string (``"edit"``, ``"add"``,
|
|
466
|
-
``"rename"
|
|
514
|
+
``"rename"``). ``"delete"`` entries are filtered out
|
|
515
|
+
by the caller before this method is invoked.
|
|
467
516
|
source_branch: Source branch ref (feature branch — new version).
|
|
468
517
|
target_branch: Target branch ref (base branch — old version).
|
|
469
518
|
|