xai-review 0.26.0__py3-none-any.whl → 0.28.0__py3-none-any.whl
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.
Potentially problematic release.
This version of xai-review might be problematic. Click here for more details.
- ai_review/cli/commands/run_inline_reply_review.py +7 -0
- ai_review/cli/commands/run_summary_reply_review.py +7 -0
- ai_review/cli/main.py +17 -0
- ai_review/clients/bitbucket/pr/client.py +45 -8
- ai_review/clients/bitbucket/pr/schema/comments.py +21 -2
- ai_review/clients/bitbucket/pr/schema/files.py +8 -3
- ai_review/clients/bitbucket/pr/schema/pull_request.py +1 -5
- ai_review/clients/bitbucket/pr/schema/user.py +7 -0
- ai_review/clients/bitbucket/tools.py +6 -0
- ai_review/clients/github/pr/client.py +98 -13
- ai_review/clients/github/pr/schema/comments.py +23 -1
- ai_review/clients/github/pr/schema/files.py +2 -1
- ai_review/clients/github/pr/schema/pull_request.py +1 -4
- ai_review/clients/github/pr/schema/reviews.py +2 -1
- ai_review/clients/github/pr/schema/user.py +6 -0
- ai_review/clients/github/pr/types.py +11 -1
- ai_review/clients/github/tools.py +6 -0
- ai_review/clients/gitlab/mr/client.py +67 -7
- ai_review/clients/gitlab/mr/schema/changes.py +1 -5
- ai_review/clients/gitlab/mr/schema/discussions.py +19 -8
- ai_review/clients/gitlab/mr/schema/notes.py +5 -1
- ai_review/clients/gitlab/mr/schema/user.py +7 -0
- ai_review/clients/gitlab/mr/types.py +16 -7
- ai_review/clients/gitlab/tools.py +5 -0
- ai_review/libs/config/prompt.py +96 -64
- ai_review/libs/config/review.py +2 -0
- ai_review/libs/config/vcs/base.py +2 -0
- ai_review/libs/config/vcs/pagination.py +6 -0
- ai_review/libs/http/paginate.py +43 -0
- ai_review/libs/llm/output_json_parser.py +60 -0
- ai_review/prompts/default_inline_reply.md +10 -0
- ai_review/prompts/default_summary_reply.md +14 -0
- ai_review/prompts/default_system_inline_reply.md +31 -0
- ai_review/prompts/default_system_summary_reply.md +13 -0
- ai_review/services/artifacts/schema.py +2 -2
- ai_review/services/hook/constants.py +14 -0
- ai_review/services/hook/service.py +95 -4
- ai_review/services/hook/types.py +18 -2
- ai_review/services/prompt/adapter.py +1 -1
- ai_review/services/prompt/service.py +49 -3
- ai_review/services/prompt/tools.py +21 -0
- ai_review/services/prompt/types.py +23 -0
- ai_review/services/review/gateway/comment.py +45 -6
- ai_review/services/review/gateway/llm.py +2 -1
- ai_review/services/review/gateway/types.py +50 -0
- ai_review/services/review/internal/inline/service.py +40 -0
- ai_review/services/review/internal/inline/types.py +8 -0
- ai_review/services/review/internal/inline_reply/schema.py +23 -0
- ai_review/services/review/internal/inline_reply/service.py +20 -0
- ai_review/services/review/internal/inline_reply/types.py +8 -0
- ai_review/services/review/{policy → internal/policy}/service.py +2 -1
- ai_review/services/review/internal/policy/types.py +15 -0
- ai_review/services/review/{summary → internal/summary}/service.py +2 -2
- ai_review/services/review/{summary → internal/summary}/types.py +1 -1
- ai_review/services/review/internal/summary_reply/__init__.py +0 -0
- ai_review/services/review/internal/summary_reply/schema.py +8 -0
- ai_review/services/review/internal/summary_reply/service.py +15 -0
- ai_review/services/review/internal/summary_reply/types.py +8 -0
- ai_review/services/review/runner/__init__.py +0 -0
- ai_review/services/review/runner/context.py +72 -0
- ai_review/services/review/runner/inline.py +80 -0
- ai_review/services/review/runner/inline_reply.py +80 -0
- ai_review/services/review/runner/summary.py +71 -0
- ai_review/services/review/runner/summary_reply.py +79 -0
- ai_review/services/review/runner/types.py +6 -0
- ai_review/services/review/service.py +78 -110
- ai_review/services/vcs/bitbucket/adapter.py +24 -0
- ai_review/services/vcs/bitbucket/client.py +107 -42
- ai_review/services/vcs/github/adapter.py +35 -0
- ai_review/services/vcs/github/client.py +105 -44
- ai_review/services/vcs/gitlab/adapter.py +26 -0
- ai_review/services/vcs/gitlab/client.py +91 -38
- ai_review/services/vcs/types.py +34 -0
- ai_review/tests/fixtures/clients/bitbucket.py +2 -2
- ai_review/tests/fixtures/clients/github.py +35 -6
- ai_review/tests/fixtures/clients/gitlab.py +42 -3
- ai_review/tests/fixtures/libs/__init__.py +0 -0
- ai_review/tests/fixtures/libs/llm/__init__.py +0 -0
- ai_review/tests/fixtures/libs/llm/output_json_parser.py +13 -0
- ai_review/tests/fixtures/services/hook.py +8 -0
- ai_review/tests/fixtures/services/llm.py +8 -5
- ai_review/tests/fixtures/services/prompt.py +70 -0
- ai_review/tests/fixtures/services/review/base.py +41 -0
- ai_review/tests/fixtures/services/review/gateway/__init__.py +0 -0
- ai_review/tests/fixtures/services/review/gateway/comment.py +98 -0
- ai_review/tests/fixtures/services/review/gateway/llm.py +17 -0
- ai_review/tests/fixtures/services/review/internal/__init__.py +0 -0
- ai_review/tests/fixtures/services/review/{inline.py → internal/inline.py} +8 -6
- ai_review/tests/fixtures/services/review/internal/inline_reply.py +25 -0
- ai_review/tests/fixtures/services/review/internal/policy.py +28 -0
- ai_review/tests/fixtures/services/review/internal/summary.py +21 -0
- ai_review/tests/fixtures/services/review/internal/summary_reply.py +19 -0
- ai_review/tests/fixtures/services/review/runner/__init__.py +0 -0
- ai_review/tests/fixtures/services/review/runner/context.py +50 -0
- ai_review/tests/fixtures/services/review/runner/inline.py +50 -0
- ai_review/tests/fixtures/services/review/runner/inline_reply.py +50 -0
- ai_review/tests/fixtures/services/review/runner/summary.py +50 -0
- ai_review/tests/fixtures/services/review/runner/summary_reply.py +50 -0
- ai_review/tests/fixtures/services/vcs.py +23 -0
- ai_review/tests/suites/cli/__init__.py +0 -0
- ai_review/tests/suites/cli/test_main.py +54 -0
- ai_review/tests/suites/clients/bitbucket/__init__.py +0 -0
- ai_review/tests/suites/clients/bitbucket/test_client.py +14 -0
- ai_review/tests/suites/clients/bitbucket/test_tools.py +31 -0
- ai_review/tests/suites/clients/github/test_tools.py +31 -0
- ai_review/tests/suites/clients/gitlab/test_tools.py +26 -0
- ai_review/tests/suites/libs/config/test_prompt.py +108 -28
- ai_review/tests/suites/libs/http/__init__.py +0 -0
- ai_review/tests/suites/libs/http/test_paginate.py +95 -0
- ai_review/tests/suites/libs/llm/__init__.py +0 -0
- ai_review/tests/suites/libs/llm/test_output_json_parser.py +155 -0
- ai_review/tests/suites/services/hook/test_service.py +88 -4
- ai_review/tests/suites/services/prompt/test_adapter.py +3 -3
- ai_review/tests/suites/services/prompt/test_service.py +102 -58
- ai_review/tests/suites/services/prompt/test_tools.py +86 -1
- ai_review/tests/suites/services/review/gateway/__init__.py +0 -0
- ai_review/tests/suites/services/review/gateway/test_comment.py +253 -0
- ai_review/tests/suites/services/review/gateway/test_llm.py +82 -0
- ai_review/tests/suites/services/review/internal/__init__.py +0 -0
- ai_review/tests/suites/services/review/internal/inline/__init__.py +0 -0
- ai_review/tests/suites/services/review/{inline → internal/inline}/test_schema.py +1 -1
- ai_review/tests/suites/services/review/internal/inline/test_service.py +81 -0
- ai_review/tests/suites/services/review/internal/inline_reply/__init__.py +0 -0
- ai_review/tests/suites/services/review/internal/inline_reply/test_schema.py +57 -0
- ai_review/tests/suites/services/review/internal/inline_reply/test_service.py +72 -0
- ai_review/tests/suites/services/review/internal/policy/__init__.py +0 -0
- ai_review/tests/suites/services/review/{policy → internal/policy}/test_service.py +1 -1
- ai_review/tests/suites/services/review/internal/summary/__init__.py +0 -0
- ai_review/tests/suites/services/review/{summary → internal/summary}/test_schema.py +1 -1
- ai_review/tests/suites/services/review/{summary → internal/summary}/test_service.py +2 -2
- ai_review/tests/suites/services/review/internal/summary_reply/__init__.py +0 -0
- ai_review/tests/suites/services/review/internal/summary_reply/test_schema.py +19 -0
- ai_review/tests/suites/services/review/internal/summary_reply/test_service.py +21 -0
- ai_review/tests/suites/services/review/runner/__init__.py +0 -0
- ai_review/tests/suites/services/review/runner/test_context.py +89 -0
- ai_review/tests/suites/services/review/runner/test_inline.py +100 -0
- ai_review/tests/suites/services/review/runner/test_inline_reply.py +109 -0
- ai_review/tests/suites/services/review/runner/test_summary.py +87 -0
- ai_review/tests/suites/services/review/runner/test_summary_reply.py +97 -0
- ai_review/tests/suites/services/review/test_service.py +64 -97
- ai_review/tests/suites/services/vcs/bitbucket/test_adapter.py +109 -0
- ai_review/tests/suites/services/vcs/bitbucket/{test_service.py → test_client.py} +88 -1
- ai_review/tests/suites/services/vcs/github/test_adapter.py +162 -0
- ai_review/tests/suites/services/vcs/github/{test_service.py → test_client.py} +102 -2
- ai_review/tests/suites/services/vcs/gitlab/test_adapter.py +105 -0
- ai_review/tests/suites/services/vcs/gitlab/{test_service.py → test_client.py} +99 -1
- {xai_review-0.26.0.dist-info → xai_review-0.28.0.dist-info}/METADATA +8 -5
- {xai_review-0.26.0.dist-info → xai_review-0.28.0.dist-info}/RECORD +160 -75
- ai_review/services/review/inline/service.py +0 -54
- ai_review/services/review/inline/types.py +0 -11
- ai_review/tests/fixtures/services/review/summary.py +0 -19
- ai_review/tests/suites/services/review/inline/test_service.py +0 -107
- /ai_review/{services/review/inline → libs/llm}/__init__.py +0 -0
- /ai_review/services/review/{policy → internal}/__init__.py +0 -0
- /ai_review/services/review/{summary → internal/inline}/__init__.py +0 -0
- /ai_review/services/review/{inline → internal/inline}/schema.py +0 -0
- /ai_review/{tests/suites/services/review/inline → services/review/internal/inline_reply}/__init__.py +0 -0
- /ai_review/{tests/suites/services/review → services/review/internal}/policy/__init__.py +0 -0
- /ai_review/{tests/suites/services/review → services/review/internal}/summary/__init__.py +0 -0
- /ai_review/services/review/{summary → internal/summary}/schema.py +0 -0
- {xai_review-0.26.0.dist-info → xai_review-0.28.0.dist-info}/WHEEL +0 -0
- {xai_review-0.26.0.dist-info → xai_review-0.28.0.dist-info}/entry_points.txt +0 -0
- {xai_review-0.26.0.dist-info → xai_review-0.28.0.dist-info}/licenses/LICENSE +0 -0
- {xai_review-0.26.0.dist-info → xai_review-0.28.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from ai_review.clients.gitlab.mr.schema.discussions import (
|
|
2
|
+
GitLabDiscussionSchema,
|
|
3
|
+
GitLabDiscussionPositionSchema,
|
|
4
|
+
)
|
|
5
|
+
from ai_review.clients.gitlab.mr.schema.notes import GitLabNoteSchema
|
|
6
|
+
from ai_review.clients.gitlab.mr.schema.user import GitLabUserSchema
|
|
7
|
+
from ai_review.services.vcs.gitlab.adapter import get_review_comment_from_gitlab_note
|
|
8
|
+
from ai_review.services.vcs.types import ReviewCommentSchema, UserSchema
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_maps_all_fields_correctly():
|
|
12
|
+
"""Should map GitLab note and discussion into ReviewCommentSchema."""
|
|
13
|
+
note = GitLabNoteSchema(
|
|
14
|
+
id=123,
|
|
15
|
+
body="Looks good!",
|
|
16
|
+
author=GitLabUserSchema(id=10, name="Alice", username="alice"),
|
|
17
|
+
)
|
|
18
|
+
discussion = GitLabDiscussionSchema(
|
|
19
|
+
id="42",
|
|
20
|
+
notes=[note],
|
|
21
|
+
position=GitLabDiscussionPositionSchema(
|
|
22
|
+
base_sha="AAA000",
|
|
23
|
+
head_sha="BBB111",
|
|
24
|
+
start_sha="CCC222",
|
|
25
|
+
new_path="src/app.py",
|
|
26
|
+
new_line=15,
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
result = get_review_comment_from_gitlab_note(note, discussion)
|
|
31
|
+
|
|
32
|
+
assert isinstance(result, ReviewCommentSchema)
|
|
33
|
+
assert result.id == 123
|
|
34
|
+
assert result.body == "Looks good!"
|
|
35
|
+
assert result.file == "src/app.py"
|
|
36
|
+
assert result.line == 15
|
|
37
|
+
assert result.thread_id == "42"
|
|
38
|
+
|
|
39
|
+
assert isinstance(result.author, UserSchema)
|
|
40
|
+
assert result.author.id == 10
|
|
41
|
+
assert result.author.name == "Alice"
|
|
42
|
+
assert result.author.username == "alice"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_maps_with_missing_author():
|
|
46
|
+
"""Should handle note without author gracefully (default empty UserSchema)."""
|
|
47
|
+
note = GitLabNoteSchema(id=1, body="Anonymous comment", author=None)
|
|
48
|
+
discussion = GitLabDiscussionSchema(
|
|
49
|
+
id="7",
|
|
50
|
+
notes=[note],
|
|
51
|
+
position=GitLabDiscussionPositionSchema(
|
|
52
|
+
base_sha="AAA000",
|
|
53
|
+
head_sha="BBB111",
|
|
54
|
+
start_sha="CCC222",
|
|
55
|
+
new_path="main.py",
|
|
56
|
+
new_line=3,
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
result = get_review_comment_from_gitlab_note(note, discussion)
|
|
61
|
+
|
|
62
|
+
assert isinstance(result.author, UserSchema)
|
|
63
|
+
assert result.author.id is None
|
|
64
|
+
assert result.author.name == ""
|
|
65
|
+
assert result.author.username == ""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_maps_with_missing_position():
|
|
69
|
+
"""Should handle discussion without position gracefully (file/line become None)."""
|
|
70
|
+
note = GitLabNoteSchema(
|
|
71
|
+
id=55,
|
|
72
|
+
body="General comment",
|
|
73
|
+
author=GitLabUserSchema(id=9, name="Bob", username="bob"),
|
|
74
|
+
)
|
|
75
|
+
discussion = GitLabDiscussionSchema(
|
|
76
|
+
id="999",
|
|
77
|
+
notes=[note],
|
|
78
|
+
position=None,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
result = get_review_comment_from_gitlab_note(note, discussion)
|
|
82
|
+
|
|
83
|
+
assert isinstance(result, ReviewCommentSchema)
|
|
84
|
+
assert result.file is None
|
|
85
|
+
assert result.line is None
|
|
86
|
+
assert result.thread_id == "999"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_maps_with_empty_body_and_defaults():
|
|
90
|
+
"""Should default body to empty string when note.body is empty string."""
|
|
91
|
+
note = GitLabNoteSchema(id=12, body="", author=None)
|
|
92
|
+
discussion = GitLabDiscussionSchema(
|
|
93
|
+
id="100",
|
|
94
|
+
notes=[note],
|
|
95
|
+
position=None,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
result = get_review_comment_from_gitlab_note(note, discussion)
|
|
99
|
+
|
|
100
|
+
assert isinstance(result, ReviewCommentSchema)
|
|
101
|
+
assert result.body == ""
|
|
102
|
+
assert result.file is None
|
|
103
|
+
assert result.line is None
|
|
104
|
+
assert result.thread_id == "100"
|
|
105
|
+
assert isinstance(result.author, UserSchema)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
3
|
from ai_review.services.vcs.gitlab.client import GitLabVCSClient
|
|
4
|
-
from ai_review.services.vcs.types import ReviewInfoSchema, ReviewCommentSchema
|
|
4
|
+
from ai_review.services.vcs.types import ReviewInfoSchema, ReviewCommentSchema, ReviewThreadSchema, ThreadKind
|
|
5
5
|
from ai_review.tests.fixtures.clients.gitlab import FakeGitLabMergeRequestsHTTPClient
|
|
6
6
|
|
|
7
7
|
|
|
@@ -52,6 +52,15 @@ async def test_get_general_comments_returns_expected_list(
|
|
|
52
52
|
assert "General comment" in bodies
|
|
53
53
|
assert "Another note" in bodies
|
|
54
54
|
|
|
55
|
+
authors = {comment.author.username for comment in comments}
|
|
56
|
+
assert authors == {"charlie", "diana"}
|
|
57
|
+
|
|
58
|
+
for comment in comments:
|
|
59
|
+
assert comment.thread_id == comment.id
|
|
60
|
+
assert comment.author.id is not None
|
|
61
|
+
assert comment.author.name != ""
|
|
62
|
+
assert comment.author.username != ""
|
|
63
|
+
|
|
55
64
|
called_methods = [name for name, _ in fake_gitlab_merge_requests_http_client.calls]
|
|
56
65
|
assert called_methods == ["get_notes"]
|
|
57
66
|
|
|
@@ -121,3 +130,92 @@ async def test_create_inline_comment_posts_comment(
|
|
|
121
130
|
assert call_args["body"] == "Looks good!"
|
|
122
131
|
assert call_args["project_id"] == "project-id"
|
|
123
132
|
assert call_args["merge_request_id"] == "merge-request-id"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@pytest.mark.asyncio
|
|
136
|
+
@pytest.mark.usefixtures("gitlab_http_client_config")
|
|
137
|
+
async def test_create_inline_reply_posts_comment(
|
|
138
|
+
gitlab_vcs_client: GitLabVCSClient,
|
|
139
|
+
fake_gitlab_merge_requests_http_client: FakeGitLabMergeRequestsHTTPClient,
|
|
140
|
+
):
|
|
141
|
+
"""Should reply to an existing inline discussion."""
|
|
142
|
+
thread_id = "discussion-1"
|
|
143
|
+
message = "I agree with this point."
|
|
144
|
+
|
|
145
|
+
await gitlab_vcs_client.create_inline_reply(thread_id, message)
|
|
146
|
+
|
|
147
|
+
call = next(
|
|
148
|
+
args for name, args in fake_gitlab_merge_requests_http_client.calls
|
|
149
|
+
if name == "create_discussion_reply"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
assert call["discussion_id"] == thread_id
|
|
153
|
+
assert call["body"] == message
|
|
154
|
+
assert call["project_id"] == "project-id"
|
|
155
|
+
assert call["merge_request_id"] == "merge-request-id"
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@pytest.mark.asyncio
|
|
159
|
+
@pytest.mark.usefixtures("gitlab_http_client_config")
|
|
160
|
+
async def test_create_summary_reply_uses_general_comment_method(
|
|
161
|
+
gitlab_vcs_client: GitLabVCSClient,
|
|
162
|
+
fake_gitlab_merge_requests_http_client: FakeGitLabMergeRequestsHTTPClient,
|
|
163
|
+
):
|
|
164
|
+
"""Should reuse create_general_comment when replying to summary thread."""
|
|
165
|
+
thread_id = "summary-1"
|
|
166
|
+
message = "Thanks for clarifying."
|
|
167
|
+
|
|
168
|
+
await gitlab_vcs_client.create_summary_reply(thread_id, message)
|
|
169
|
+
|
|
170
|
+
call = next(
|
|
171
|
+
args for name, args in fake_gitlab_merge_requests_http_client.calls
|
|
172
|
+
if name == "create_note"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
assert call["body"] == message
|
|
176
|
+
assert call["project_id"] == "project-id"
|
|
177
|
+
assert call["merge_request_id"] == "merge-request-id"
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@pytest.mark.asyncio
|
|
181
|
+
@pytest.mark.usefixtures("gitlab_http_client_config")
|
|
182
|
+
async def test_get_inline_threads_returns_valid_schema(
|
|
183
|
+
gitlab_vcs_client: GitLabVCSClient,
|
|
184
|
+
fake_gitlab_merge_requests_http_client: FakeGitLabMergeRequestsHTTPClient,
|
|
185
|
+
):
|
|
186
|
+
"""Should transform GitLab discussions into inline threads with proper fields."""
|
|
187
|
+
threads = await gitlab_vcs_client.get_inline_threads()
|
|
188
|
+
|
|
189
|
+
assert all(isinstance(t, ReviewThreadSchema) for t in threads)
|
|
190
|
+
assert len(threads) == 1
|
|
191
|
+
|
|
192
|
+
thread = threads[0]
|
|
193
|
+
assert thread.id == "discussion-1"
|
|
194
|
+
assert thread.kind == ThreadKind.INLINE
|
|
195
|
+
assert thread.file == "src/app.py"
|
|
196
|
+
assert thread.line == 12
|
|
197
|
+
assert len(thread.comments) == 2
|
|
198
|
+
assert isinstance(thread.comments[0], ReviewCommentSchema)
|
|
199
|
+
|
|
200
|
+
called = [name for name, _ in fake_gitlab_merge_requests_http_client.calls]
|
|
201
|
+
assert "get_discussions" in called
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@pytest.mark.asyncio
|
|
205
|
+
@pytest.mark.usefixtures("gitlab_http_client_config")
|
|
206
|
+
async def test_get_general_threads_wraps_comments_in_threads(
|
|
207
|
+
gitlab_vcs_client: GitLabVCSClient,
|
|
208
|
+
fake_gitlab_merge_requests_http_client: FakeGitLabMergeRequestsHTTPClient,
|
|
209
|
+
):
|
|
210
|
+
"""Should wrap each general MR note into its own SUMMARY thread."""
|
|
211
|
+
threads = await gitlab_vcs_client.get_general_threads()
|
|
212
|
+
|
|
213
|
+
assert len(threads) == 2
|
|
214
|
+
for thread in threads:
|
|
215
|
+
assert isinstance(thread, ReviewThreadSchema)
|
|
216
|
+
assert thread.kind == ThreadKind.SUMMARY
|
|
217
|
+
assert len(thread.comments) == 1
|
|
218
|
+
assert isinstance(thread.comments[0], ReviewCommentSchema)
|
|
219
|
+
|
|
220
|
+
called = [name for name, _ in fake_gitlab_merge_requests_http_client.calls]
|
|
221
|
+
assert "get_notes" in called
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xai-review
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.28.0
|
|
4
4
|
Summary: AI-powered code review tool
|
|
5
5
|
Author-email: Nikita Filonov <nikita.filonov@example.com>
|
|
6
6
|
Maintainer-email: Nikita Filonov <nikita.filonov@example.com>
|
|
@@ -69,12 +69,14 @@ improve code quality, enforce consistency, and speed up the review process.
|
|
|
69
69
|
- **Multiple LLM providers** — choose between **OpenAI**, **Claude**, **Gemini**, or **Ollama**, and switch anytime.
|
|
70
70
|
- **VCS integration** — works out of the box with **GitLab**, **GitHub**, and **Bitbucket**.
|
|
71
71
|
- **Customizable prompts** — adapt inline, context, and summary reviews to match your team’s coding guidelines.
|
|
72
|
+
- **Reply modes** — AI can now **participate in existing review threads**, adding follow-up replies in both inline and
|
|
73
|
+
summary discussions.
|
|
72
74
|
- **Flexible configuration** — supports `YAML`, `JSON`, and `ENV`, with seamless overrides in CI/CD pipelines.
|
|
73
75
|
- **AI Review runs fully client-side** — it never proxies or inspects your requests.
|
|
74
76
|
|
|
75
|
-
AI Review runs automatically in your CI/CD pipeline and posts both **inline comments
|
|
76
|
-
inside your merge requests. This makes reviews faster, more
|
|
77
|
-
|
|
77
|
+
AI Review runs automatically in your CI/CD pipeline and posts both **inline comments**, **summary reviews**, and now *
|
|
78
|
+
*AI-generated replies** directly inside your merge requests. This makes reviews faster, more conversational, and still
|
|
79
|
+
fully under human control.
|
|
78
80
|
|
|
79
81
|
---
|
|
80
82
|
|
|
@@ -209,7 +211,7 @@ jobs:
|
|
|
209
211
|
runs-on: ubuntu-latest
|
|
210
212
|
steps:
|
|
211
213
|
- uses: actions/checkout@v4
|
|
212
|
-
- uses: Nikita-Filonov/ai-review@v0.
|
|
214
|
+
- uses: Nikita-Filonov/ai-review@v0.28.0
|
|
213
215
|
with:
|
|
214
216
|
review-command: ${{ inputs.review-command }}
|
|
215
217
|
env:
|
|
@@ -274,6 +276,7 @@ ai-review:
|
|
|
274
276
|
See these folders for reference templates and full configuration options:
|
|
275
277
|
|
|
276
278
|
- [./docs/ci](./docs/ci) — CI/CD integration templates (GitHub Actions, GitLab CI)
|
|
279
|
+
- [./docs/cli](./docs/cli) — CLI command reference and usage examples
|
|
277
280
|
- [./docs/hooks](./docs/hooks) — hook reference and lifecycle events
|
|
278
281
|
- [./docs/configs](./docs/configs) — full configuration examples (`.yaml`, `.json`, `.env`)
|
|
279
282
|
- [./docs/prompts](./docs/prompts) — prompt templates for Python/Go (light & strict modes)
|