xai-review 0.27.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/schema/comments.py +14 -0
- ai_review/clients/bitbucket/pr/schema/pull_request.py +1 -5
- ai_review/clients/bitbucket/pr/schema/user.py +7 -0
- ai_review/clients/github/pr/client.py +35 -4
- ai_review/clients/github/pr/schema/comments.py +21 -0
- ai_review/clients/github/pr/schema/pull_request.py +1 -4
- ai_review/clients/github/pr/schema/user.py +6 -0
- ai_review/clients/github/pr/types.py +11 -1
- ai_review/clients/gitlab/mr/client.py +32 -1
- ai_review/clients/gitlab/mr/schema/changes.py +1 -5
- ai_review/clients/gitlab/mr/schema/discussions.py +17 -7
- ai_review/clients/gitlab/mr/schema/notes.py +3 -0
- ai_review/clients/gitlab/mr/schema/user.py +7 -0
- ai_review/clients/gitlab/mr/types.py +16 -7
- ai_review/libs/config/prompt.py +96 -64
- ai_review/libs/config/review.py +2 -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/libs/config/test_prompt.py +108 -28
- 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.27.0.dist-info → xai_review-0.28.0.dist-info}/METADATA +8 -5
- {xai_review-0.27.0.dist-info → xai_review-0.28.0.dist-info}/RECORD +143 -70
- 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.27.0.dist-info → xai_review-0.28.0.dist-info}/WHEEL +0 -0
- {xai_review-0.27.0.dist-info → xai_review-0.28.0.dist-info}/entry_points.txt +0 -0
- {xai_review-0.27.0.dist-info → xai_review-0.28.0.dist-info}/licenses/LICENSE +0 -0
- {xai_review-0.27.0.dist-info → xai_review-0.28.0.dist-info}/top_level.txt +0 -0
|
@@ -12,6 +12,7 @@ from ai_review.clients.gitlab.mr.schema.discussions import (
|
|
|
12
12
|
GitLabGetMRDiscussionsResponseSchema,
|
|
13
13
|
GitLabCreateMRDiscussionRequestSchema,
|
|
14
14
|
GitLabCreateMRDiscussionResponseSchema,
|
|
15
|
+
GitLabCreateMRDiscussionReplyResponseSchema, GitLabDiscussionPositionSchema,
|
|
15
16
|
)
|
|
16
17
|
from ai_review.clients.gitlab.mr.schema.notes import (
|
|
17
18
|
GitLabNoteSchema,
|
|
@@ -60,8 +61,16 @@ class FakeGitLabMergeRequestsHTTPClient(GitLabMergeRequestsHTTPClientProtocol):
|
|
|
60
61
|
self.calls.append(("get_notes", {"project_id": project_id, "merge_request_id": merge_request_id}))
|
|
61
62
|
return GitLabGetMRNotesResponseSchema(
|
|
62
63
|
root=[
|
|
63
|
-
GitLabNoteSchema(
|
|
64
|
-
|
|
64
|
+
GitLabNoteSchema(
|
|
65
|
+
id=1,
|
|
66
|
+
body="General comment",
|
|
67
|
+
author=GitLabUserSchema(id=301, name="Charlie", username="charlie"),
|
|
68
|
+
),
|
|
69
|
+
GitLabNoteSchema(
|
|
70
|
+
id=2,
|
|
71
|
+
body="Another note",
|
|
72
|
+
author=GitLabUserSchema(id=302, name="Diana", username="diana"),
|
|
73
|
+
),
|
|
65
74
|
]
|
|
66
75
|
)
|
|
67
76
|
|
|
@@ -75,6 +84,13 @@ class FakeGitLabMergeRequestsHTTPClient(GitLabMergeRequestsHTTPClientProtocol):
|
|
|
75
84
|
GitLabNoteSchema(id=10, body="Inline comment A"),
|
|
76
85
|
GitLabNoteSchema(id=11, body="Inline comment B"),
|
|
77
86
|
],
|
|
87
|
+
position=GitLabDiscussionPositionSchema(
|
|
88
|
+
base_sha="abc123",
|
|
89
|
+
head_sha="def456",
|
|
90
|
+
start_sha="ghi789",
|
|
91
|
+
new_path="src/app.py",
|
|
92
|
+
new_line=12,
|
|
93
|
+
),
|
|
78
94
|
)
|
|
79
95
|
]
|
|
80
96
|
)
|
|
@@ -100,7 +116,30 @@ class FakeGitLabMergeRequestsHTTPClient(GitLabMergeRequestsHTTPClientProtocol):
|
|
|
100
116
|
{"project_id": project_id, "merge_request_id": merge_request_id, "body": request.body}
|
|
101
117
|
)
|
|
102
118
|
)
|
|
103
|
-
return GitLabCreateMRDiscussionResponseSchema(
|
|
119
|
+
return GitLabCreateMRDiscussionResponseSchema(
|
|
120
|
+
id="discussion-new",
|
|
121
|
+
notes=[GitLabNoteSchema(id=1, body=request.body)]
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
async def create_discussion_reply(
|
|
125
|
+
self,
|
|
126
|
+
project_id: str,
|
|
127
|
+
merge_request_id: str,
|
|
128
|
+
discussion_id: str,
|
|
129
|
+
body: str,
|
|
130
|
+
) -> GitLabCreateMRDiscussionReplyResponseSchema:
|
|
131
|
+
self.calls.append(
|
|
132
|
+
(
|
|
133
|
+
"create_discussion_reply",
|
|
134
|
+
{
|
|
135
|
+
"project_id": project_id,
|
|
136
|
+
"merge_request_id": merge_request_id,
|
|
137
|
+
"discussion_id": discussion_id,
|
|
138
|
+
"body": body,
|
|
139
|
+
},
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
return GitLabCreateMRDiscussionReplyResponseSchema(id=100, body=body)
|
|
104
143
|
|
|
105
144
|
|
|
106
145
|
class FakeGitLabHTTPClient:
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
|
|
4
|
+
from ai_review.libs.llm.output_json_parser import LLMOutputJSONParser
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DummyModel(BaseModel):
|
|
8
|
+
text: str
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def llm_output_json_parser() -> LLMOutputJSONParser:
|
|
13
|
+
return LLMOutputJSONParser(DummyModel)
|
|
@@ -13,11 +13,14 @@ class FakeLLMClient(LLMClientProtocol):
|
|
|
13
13
|
async def chat(self, prompt: str, prompt_system: str) -> ChatResultSchema:
|
|
14
14
|
self.calls.append(("chat", {"prompt": prompt, "prompt_system": prompt_system}))
|
|
15
15
|
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
return self.responses.get(
|
|
17
|
+
"chat",
|
|
18
|
+
ChatResultSchema(
|
|
19
|
+
text="FAKE_RESPONSE",
|
|
20
|
+
total_tokens=42,
|
|
21
|
+
prompt_tokens=21,
|
|
22
|
+
completion_tokens=21,
|
|
23
|
+
)
|
|
21
24
|
)
|
|
22
25
|
|
|
23
26
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
|
+
from ai_review.libs.config.prompt import PromptConfig
|
|
3
4
|
from ai_review.services.diff.schema import DiffFileSchema
|
|
4
5
|
from ai_review.services.prompt.schema import PromptContextSchema
|
|
5
6
|
from ai_review.services.prompt.types import PromptServiceProtocol
|
|
7
|
+
from ai_review.services.vcs.types import ReviewThreadSchema
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class FakePromptService(PromptServiceProtocol):
|
|
@@ -25,6 +27,24 @@ class FakePromptService(PromptServiceProtocol):
|
|
|
25
27
|
self.calls.append(("build_context_request", {"diffs": diffs, "context": context}))
|
|
26
28
|
return "CONTEXT_PROMPT"
|
|
27
29
|
|
|
30
|
+
def build_inline_reply_request(
|
|
31
|
+
self,
|
|
32
|
+
diff: DiffFileSchema,
|
|
33
|
+
thread: ReviewThreadSchema,
|
|
34
|
+
context: PromptContextSchema
|
|
35
|
+
) -> str:
|
|
36
|
+
self.calls.append(("build_inline_reply_request", {"diff": diff, "thread": thread, "context": context}))
|
|
37
|
+
return f"INLINE_REPLY_PROMPT_FOR_{diff.file}"
|
|
38
|
+
|
|
39
|
+
def build_summary_reply_request(
|
|
40
|
+
self,
|
|
41
|
+
diffs: list[DiffFileSchema],
|
|
42
|
+
thread: ReviewThreadSchema,
|
|
43
|
+
context: PromptContextSchema
|
|
44
|
+
) -> str:
|
|
45
|
+
self.calls.append(("build_summary_reply_request", {"diffs": diffs, "thread": thread, "context": context}))
|
|
46
|
+
return "SUMMARY_REPLY_PROMPT"
|
|
47
|
+
|
|
28
48
|
def build_system_inline_request(self, context: PromptContextSchema) -> str:
|
|
29
49
|
self.calls.append(("build_system_inline_request", {"context": context}))
|
|
30
50
|
return "SYSTEM_INLINE_PROMPT"
|
|
@@ -37,7 +57,57 @@ class FakePromptService(PromptServiceProtocol):
|
|
|
37
57
|
self.calls.append(("build_system_summary_request", {"context": context}))
|
|
38
58
|
return "SYSTEM_SUMMARY_PROMPT"
|
|
39
59
|
|
|
60
|
+
def build_system_inline_reply_request(self, context: PromptContextSchema) -> str:
|
|
61
|
+
self.calls.append(("build_system_inline_reply_request", {"context": context}))
|
|
62
|
+
return "SYSTEM_INLINE_REPLY_PROMPT"
|
|
63
|
+
|
|
64
|
+
def build_system_summary_reply_request(self, context: PromptContextSchema) -> str:
|
|
65
|
+
self.calls.append(("build_system_summary_reply_request", {"context": context}))
|
|
66
|
+
return "SYSTEM_SUMMARY_REPLY_PROMPT"
|
|
67
|
+
|
|
40
68
|
|
|
41
69
|
@pytest.fixture
|
|
42
70
|
def fake_prompt_service() -> FakePromptService:
|
|
43
71
|
return FakePromptService()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@pytest.fixture
|
|
75
|
+
def fake_prompts(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
76
|
+
"""Patch methods of settings.prompt to return dummy values."""
|
|
77
|
+
monkeypatch.setattr(PromptConfig, "load_inline", lambda self: ["GLOBAL_INLINE", "INLINE_PROMPT"])
|
|
78
|
+
monkeypatch.setattr(PromptConfig, "load_context", lambda self: ["GLOBAL_CONTEXT", "CONTEXT_PROMPT"])
|
|
79
|
+
monkeypatch.setattr(PromptConfig, "load_summary", lambda self: ["GLOBAL_SUMMARY", "SUMMARY_PROMPT"])
|
|
80
|
+
monkeypatch.setattr(PromptConfig, "load_system_inline", lambda self: ["SYS_INLINE_A", "SYS_INLINE_B"])
|
|
81
|
+
monkeypatch.setattr(PromptConfig, "load_system_context", lambda self: ["SYS_CONTEXT_A", "SYS_CONTEXT_B"])
|
|
82
|
+
monkeypatch.setattr(PromptConfig, "load_system_summary", lambda self: ["SYS_SUMMARY_A", "SYS_SUMMARY_B"])
|
|
83
|
+
monkeypatch.setattr(PromptConfig, "load_inline_reply", lambda self: ["INLINE_REPLY_A", "INLINE_REPLY_B"])
|
|
84
|
+
monkeypatch.setattr(PromptConfig, "load_summary_reply", lambda self: ["SUMMARY_REPLY_A", "SUMMARY_REPLY_B"])
|
|
85
|
+
monkeypatch.setattr(
|
|
86
|
+
PromptConfig,
|
|
87
|
+
"load_system_inline_reply",
|
|
88
|
+
lambda self: ["SYS_INLINE_REPLY_A", "SYS_INLINE_REPLY_B"]
|
|
89
|
+
)
|
|
90
|
+
monkeypatch.setattr(
|
|
91
|
+
PromptConfig,
|
|
92
|
+
"load_system_summary_reply",
|
|
93
|
+
lambda self: ["SYS_SUMMARY_REPLY_A", "SYS_SUMMARY_REPLY_B"]
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@pytest.fixture
|
|
98
|
+
def fake_prompt_context() -> PromptContextSchema:
|
|
99
|
+
"""Builds a context object that reflects the new unified review schema."""
|
|
100
|
+
return PromptContextSchema(
|
|
101
|
+
review_title="Fix login bug",
|
|
102
|
+
review_description="Some description",
|
|
103
|
+
review_author_name="Nikita",
|
|
104
|
+
review_author_username="nikita.filonov",
|
|
105
|
+
review_reviewers=["Alice", "Bob"],
|
|
106
|
+
review_reviewers_usernames=["alice", "bob"],
|
|
107
|
+
review_assignees=["Charlie"],
|
|
108
|
+
review_assignees_usernames=["charlie"],
|
|
109
|
+
source_branch="feature/login-fix",
|
|
110
|
+
target_branch="main",
|
|
111
|
+
labels=["bug", "critical"],
|
|
112
|
+
changed_files=["foo.py", "bar.py"],
|
|
113
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ai_review.services.cost.types import CostServiceProtocol
|
|
4
|
+
from ai_review.services.review.runner.types import ReviewRunnerProtocol
|
|
5
|
+
from ai_review.services.review.service import ReviewService
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.fixture
|
|
9
|
+
def review_service(
|
|
10
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
11
|
+
fake_cost_service: CostServiceProtocol,
|
|
12
|
+
fake_inline_review_runner: ReviewRunnerProtocol,
|
|
13
|
+
fake_context_review_runner: ReviewRunnerProtocol,
|
|
14
|
+
fake_summary_review_runner: ReviewRunnerProtocol,
|
|
15
|
+
fake_inline_reply_review_runner: ReviewRunnerProtocol,
|
|
16
|
+
fake_summary_reply_review_runner: ReviewRunnerProtocol,
|
|
17
|
+
):
|
|
18
|
+
monkeypatch.setattr("ai_review.services.review.service.CostService", lambda: fake_cost_service)
|
|
19
|
+
|
|
20
|
+
monkeypatch.setattr(
|
|
21
|
+
"ai_review.services.review.service.InlineReviewRunner",
|
|
22
|
+
lambda **_: fake_inline_review_runner
|
|
23
|
+
)
|
|
24
|
+
monkeypatch.setattr(
|
|
25
|
+
"ai_review.services.review.service.ContextReviewRunner",
|
|
26
|
+
lambda **_: fake_context_review_runner
|
|
27
|
+
)
|
|
28
|
+
monkeypatch.setattr(
|
|
29
|
+
"ai_review.services.review.service.SummaryReviewRunner",
|
|
30
|
+
lambda **_: fake_summary_review_runner
|
|
31
|
+
)
|
|
32
|
+
monkeypatch.setattr(
|
|
33
|
+
"ai_review.services.review.service.InlineReplyReviewRunner",
|
|
34
|
+
lambda **_: fake_inline_reply_review_runner
|
|
35
|
+
)
|
|
36
|
+
monkeypatch.setattr(
|
|
37
|
+
"ai_review.services.review.service.SummaryReplyReviewRunner",
|
|
38
|
+
lambda **_: fake_summary_reply_review_runner
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return ReviewService()
|
|
File without changes
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ai_review.services.review.gateway.comment import ReviewCommentGateway
|
|
6
|
+
from ai_review.services.review.gateway.types import ReviewCommentGatewayProtocol
|
|
7
|
+
from ai_review.services.review.internal.inline.schema import InlineCommentSchema, InlineCommentListSchema
|
|
8
|
+
from ai_review.services.review.internal.inline_reply.schema import InlineCommentReplySchema
|
|
9
|
+
from ai_review.services.review.internal.summary.schema import SummaryCommentSchema
|
|
10
|
+
from ai_review.services.review.internal.summary_reply.schema import SummaryCommentReplySchema
|
|
11
|
+
from ai_review.services.vcs.types import (
|
|
12
|
+
UserSchema,
|
|
13
|
+
ThreadKind,
|
|
14
|
+
ReviewThreadSchema,
|
|
15
|
+
ReviewCommentSchema,
|
|
16
|
+
VCSClientProtocol
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FakeReviewCommentGateway(ReviewCommentGatewayProtocol):
|
|
21
|
+
def __init__(self, responses: dict[str, Any] | None = None):
|
|
22
|
+
self.calls: list[tuple[str, dict]] = []
|
|
23
|
+
|
|
24
|
+
fake_user = UserSchema(id="u1", username="tester", name="Tester")
|
|
25
|
+
|
|
26
|
+
fake_inline_thread = ReviewThreadSchema(
|
|
27
|
+
id="t1",
|
|
28
|
+
kind=ThreadKind.INLINE,
|
|
29
|
+
file="file.py",
|
|
30
|
+
line=5,
|
|
31
|
+
comments=[
|
|
32
|
+
ReviewCommentSchema(
|
|
33
|
+
id="c1",
|
|
34
|
+
body="AI inline comment <!--AI-->",
|
|
35
|
+
file="file.py",
|
|
36
|
+
line=5,
|
|
37
|
+
author=fake_user
|
|
38
|
+
),
|
|
39
|
+
ReviewCommentSchema(id="c2", body="Developer reply", file="file.py", line=5, author=fake_user),
|
|
40
|
+
],
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
fake_summary_thread = ReviewThreadSchema(
|
|
44
|
+
id="t2",
|
|
45
|
+
kind=ThreadKind.SUMMARY,
|
|
46
|
+
comments=[
|
|
47
|
+
ReviewCommentSchema(id="c3", body="AI summary comment <!--AI-->", author=fake_user),
|
|
48
|
+
ReviewCommentSchema(id="c4", body="Developer reply", author=fake_user),
|
|
49
|
+
],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
self.responses = responses or {
|
|
53
|
+
"get_inline_threads": [fake_inline_thread],
|
|
54
|
+
"get_summary_threads": [fake_summary_thread],
|
|
55
|
+
"has_existing_inline_comments": False,
|
|
56
|
+
"has_existing_summary_comments": False,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async def get_inline_threads(self) -> list[ReviewThreadSchema]:
|
|
60
|
+
self.calls.append(("get_inline_threads", {}))
|
|
61
|
+
return self.responses.get("get_inline_threads", [])
|
|
62
|
+
|
|
63
|
+
async def get_summary_threads(self) -> list[ReviewThreadSchema]:
|
|
64
|
+
self.calls.append(("get_summary_threads", {}))
|
|
65
|
+
return self.responses.get("get_summary_threads", [])
|
|
66
|
+
|
|
67
|
+
async def has_existing_inline_comments(self) -> bool:
|
|
68
|
+
self.calls.append(("has_existing_inline_comments", {}))
|
|
69
|
+
return self.responses.get("has_existing_inline_comments", False)
|
|
70
|
+
|
|
71
|
+
async def has_existing_summary_comments(self) -> bool:
|
|
72
|
+
self.calls.append(("has_existing_summary_comments", {}))
|
|
73
|
+
return self.responses.get("has_existing_summary_comments", False)
|
|
74
|
+
|
|
75
|
+
async def process_inline_reply(self, thread_id: str, reply: InlineCommentReplySchema) -> None:
|
|
76
|
+
self.calls.append(("process_inline_reply", {"thread_id": thread_id, "reply": reply}))
|
|
77
|
+
|
|
78
|
+
async def process_summary_reply(self, thread_id: str, reply: SummaryCommentReplySchema) -> None:
|
|
79
|
+
self.calls.append(("process_summary_reply", {"thread_id": thread_id, "reply": reply}))
|
|
80
|
+
|
|
81
|
+
async def process_inline_comment(self, comment: InlineCommentSchema) -> None:
|
|
82
|
+
self.calls.append(("process_inline_comment", {"comment": comment}))
|
|
83
|
+
|
|
84
|
+
async def process_summary_comment(self, comment: SummaryCommentSchema) -> None:
|
|
85
|
+
self.calls.append(("process_summary_comment", {"comment": comment}))
|
|
86
|
+
|
|
87
|
+
async def process_inline_comments(self, comments: InlineCommentListSchema) -> None:
|
|
88
|
+
self.calls.append(("process_inline_comments", {"comments": comments}))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@pytest.fixture
|
|
92
|
+
def fake_review_comment_gateway() -> FakeReviewCommentGateway:
|
|
93
|
+
return FakeReviewCommentGateway()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@pytest.fixture
|
|
97
|
+
def review_comment_gateway(fake_vcs_client: VCSClientProtocol) -> ReviewCommentGateway:
|
|
98
|
+
return ReviewCommentGateway(vcs=fake_vcs_client)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ai_review.services.review.gateway.types import ReviewLLMGatewayProtocol
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FakeReviewLLMGateway(ReviewLLMGatewayProtocol):
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.calls: list[tuple[str, dict]] = []
|
|
9
|
+
|
|
10
|
+
async def ask(self, prompt: str, prompt_system: str) -> str:
|
|
11
|
+
self.calls.append(("ask", {"prompt": prompt, "prompt_system": prompt_system}))
|
|
12
|
+
return "FAKE_LLM_RESPONSE"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def fake_review_llm_gateway() -> FakeReviewLLMGateway:
|
|
17
|
+
return FakeReviewLLMGateway()
|
|
File without changes
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
|
-
from ai_review.services.review.inline.schema import InlineCommentListSchema, InlineCommentSchema
|
|
4
|
-
from ai_review.services.review.inline.
|
|
3
|
+
from ai_review.services.review.internal.inline.schema import InlineCommentListSchema, InlineCommentSchema
|
|
4
|
+
from ai_review.services.review.internal.inline.service import InlineCommentService
|
|
5
|
+
from ai_review.services.review.internal.inline.types import InlineCommentServiceProtocol
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class FakeInlineCommentService(InlineCommentServiceProtocol):
|
|
@@ -15,11 +16,12 @@ class FakeInlineCommentService(InlineCommentServiceProtocol):
|
|
|
15
16
|
self.calls.append(("parse_model_output", {"output": output}))
|
|
16
17
|
return InlineCommentListSchema(root=self.comments)
|
|
17
18
|
|
|
18
|
-
def try_parse_model_output(self, raw: str) -> InlineCommentListSchema | None:
|
|
19
|
-
self.calls.append(("try_parse_model_output", {"raw": raw}))
|
|
20
|
-
return InlineCommentListSchema(root=self.comments)
|
|
21
|
-
|
|
22
19
|
|
|
23
20
|
@pytest.fixture
|
|
24
21
|
def fake_inline_comment_service() -> FakeInlineCommentService:
|
|
25
22
|
return FakeInlineCommentService()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.fixture
|
|
26
|
+
def inline_comment_service() -> InlineCommentService:
|
|
27
|
+
return InlineCommentService()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ai_review.services.review.internal.inline_reply.schema import InlineCommentReplySchema
|
|
4
|
+
from ai_review.services.review.internal.inline_reply.service import InlineCommentReplyService
|
|
5
|
+
from ai_review.services.review.internal.inline_reply.types import InlineCommentReplyServiceProtocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FakeInlineCommentReplyService(InlineCommentReplyServiceProtocol):
|
|
9
|
+
def __init__(self, reply: InlineCommentReplySchema | None = None):
|
|
10
|
+
self.calls: list[tuple[str, dict]] = []
|
|
11
|
+
self.reply = reply or InlineCommentReplySchema(message="Looks good!", suggestion="use const instead of var")
|
|
12
|
+
|
|
13
|
+
def parse_model_output(self, output: str) -> InlineCommentReplySchema | None:
|
|
14
|
+
self.calls.append(("parse_model_output", {"output": output}))
|
|
15
|
+
return self.reply
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def fake_inline_comment_reply_service() -> FakeInlineCommentReplyService:
|
|
20
|
+
return FakeInlineCommentReplyService()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def inline_comment_reply_service() -> InlineCommentReplyService:
|
|
25
|
+
return InlineCommentReplyService()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ai_review.services.review.internal.policy.types import ReviewPolicyServiceProtocol
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FakeReviewPolicyService(ReviewPolicyServiceProtocol):
|
|
9
|
+
def __init__(self, responses: dict[str, Any] | None = None):
|
|
10
|
+
self.calls: list[tuple[str, dict]] = []
|
|
11
|
+
self.responses = responses or {}
|
|
12
|
+
|
|
13
|
+
def apply_for_files(self, files: list[str]) -> list[str]:
|
|
14
|
+
self.calls.append(("apply_for_files", {"files": files}))
|
|
15
|
+
return self.responses.get("apply_for_files", files)
|
|
16
|
+
|
|
17
|
+
def apply_for_inline_comments(self, comments: list) -> list:
|
|
18
|
+
self.calls.append(("apply_for_inline_comments", {"comments": comments}))
|
|
19
|
+
return self.responses.get("apply_for_inline_comments", comments)
|
|
20
|
+
|
|
21
|
+
def apply_for_context_comments(self, comments: list) -> list:
|
|
22
|
+
self.calls.append(("apply_for_context_comments", {"comments": comments}))
|
|
23
|
+
return self.responses.get("apply_for_context_comments", comments)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def fake_review_policy_service() -> FakeReviewPolicyService:
|
|
28
|
+
return FakeReviewPolicyService()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ai_review.services.review.internal.summary.schema import SummaryCommentSchema
|
|
6
|
+
from ai_review.services.review.internal.summary.types import SummaryCommentServiceProtocol
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FakeSummaryCommentService(SummaryCommentServiceProtocol):
|
|
10
|
+
def __init__(self, responses: dict[str, Any] | None = None):
|
|
11
|
+
self.calls: list[tuple[str, dict]] = []
|
|
12
|
+
self.responses = responses or {}
|
|
13
|
+
|
|
14
|
+
def parse_model_output(self, output: str) -> SummaryCommentSchema:
|
|
15
|
+
self.calls.append(("parse_model_output", {"output": output}))
|
|
16
|
+
return self.responses.get("parse_model_output", SummaryCommentSchema(text="This is a summary comment"))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.fixture
|
|
20
|
+
def fake_summary_comment_service() -> FakeSummaryCommentService:
|
|
21
|
+
return FakeSummaryCommentService()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ai_review.services.review.internal.summary_reply.schema import SummaryCommentReplySchema
|
|
4
|
+
from ai_review.services.review.internal.summary_reply.types import SummaryCommentReplyServiceProtocol
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FakeSummaryCommentReplyService(SummaryCommentReplyServiceProtocol):
|
|
8
|
+
def __init__(self, reply: SummaryCommentReplySchema | None = None):
|
|
9
|
+
self.calls: list[tuple[str, dict]] = []
|
|
10
|
+
self.reply = reply or SummaryCommentReplySchema(text="Overall, the code looks clean and efficient.")
|
|
11
|
+
|
|
12
|
+
def parse_model_output(self, output: str) -> SummaryCommentReplySchema:
|
|
13
|
+
self.calls.append(("parse_model_output", {"output": output}))
|
|
14
|
+
return self.reply
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def fake_summary_comment_reply_service() -> FakeSummaryCommentReplyService:
|
|
19
|
+
return FakeSummaryCommentReplyService()
|
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ai_review.services.cost.types import CostServiceProtocol
|
|
4
|
+
from ai_review.services.diff.types import DiffServiceProtocol
|
|
5
|
+
from ai_review.services.git.types import GitServiceProtocol
|
|
6
|
+
from ai_review.services.prompt.types import PromptServiceProtocol
|
|
7
|
+
from ai_review.services.review.gateway.types import ReviewLLMGatewayProtocol, ReviewCommentGatewayProtocol
|
|
8
|
+
from ai_review.services.review.internal.inline.types import InlineCommentServiceProtocol
|
|
9
|
+
from ai_review.services.review.internal.policy.types import ReviewPolicyServiceProtocol
|
|
10
|
+
from ai_review.services.review.runner.context import ContextReviewRunner
|
|
11
|
+
from ai_review.services.review.runner.types import ReviewRunnerProtocol
|
|
12
|
+
from ai_review.services.vcs.types import VCSClientProtocol
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FakeContextReviewRunner(ReviewRunnerProtocol):
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.calls = []
|
|
18
|
+
|
|
19
|
+
async def run(self) -> None:
|
|
20
|
+
self.calls.append(("run", {}))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def fake_context_review_runner() -> FakeContextReviewRunner:
|
|
25
|
+
return FakeContextReviewRunner()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def context_review_runner(
|
|
30
|
+
fake_vcs_client: VCSClientProtocol,
|
|
31
|
+
fake_git_service: GitServiceProtocol,
|
|
32
|
+
fake_diff_service: DiffServiceProtocol,
|
|
33
|
+
fake_cost_service: CostServiceProtocol,
|
|
34
|
+
fake_prompt_service: PromptServiceProtocol,
|
|
35
|
+
fake_review_llm_gateway: ReviewLLMGatewayProtocol,
|
|
36
|
+
fake_review_policy_service: ReviewPolicyServiceProtocol,
|
|
37
|
+
fake_review_comment_gateway: ReviewCommentGatewayProtocol,
|
|
38
|
+
fake_inline_comment_service: InlineCommentServiceProtocol,
|
|
39
|
+
) -> ContextReviewRunner:
|
|
40
|
+
return ContextReviewRunner(
|
|
41
|
+
vcs=fake_vcs_client,
|
|
42
|
+
git=fake_git_service,
|
|
43
|
+
diff=fake_diff_service,
|
|
44
|
+
cost=fake_cost_service,
|
|
45
|
+
prompt=fake_prompt_service,
|
|
46
|
+
review_policy=fake_review_policy_service,
|
|
47
|
+
inline_comment=fake_inline_comment_service,
|
|
48
|
+
review_llm_gateway=fake_review_llm_gateway,
|
|
49
|
+
review_comment_gateway=fake_review_comment_gateway,
|
|
50
|
+
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ai_review.services.cost.types import CostServiceProtocol
|
|
4
|
+
from ai_review.services.diff.types import DiffServiceProtocol
|
|
5
|
+
from ai_review.services.git.types import GitServiceProtocol
|
|
6
|
+
from ai_review.services.prompt.types import PromptServiceProtocol
|
|
7
|
+
from ai_review.services.review.gateway.types import ReviewLLMGatewayProtocol, ReviewCommentGatewayProtocol
|
|
8
|
+
from ai_review.services.review.internal.inline.types import InlineCommentServiceProtocol
|
|
9
|
+
from ai_review.services.review.internal.policy.types import ReviewPolicyServiceProtocol
|
|
10
|
+
from ai_review.services.review.runner.inline import InlineReviewRunner
|
|
11
|
+
from ai_review.services.review.runner.types import ReviewRunnerProtocol
|
|
12
|
+
from ai_review.services.vcs.types import VCSClientProtocol
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FakeInlineReviewRunner(ReviewRunnerProtocol):
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.calls = []
|
|
18
|
+
|
|
19
|
+
async def run(self) -> None:
|
|
20
|
+
self.calls.append(("run", {}))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def fake_inline_review_runner() -> FakeInlineReviewRunner:
|
|
25
|
+
return FakeInlineReviewRunner()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def inline_review_runner(
|
|
30
|
+
fake_vcs_client: VCSClientProtocol,
|
|
31
|
+
fake_git_service: GitServiceProtocol,
|
|
32
|
+
fake_diff_service: DiffServiceProtocol,
|
|
33
|
+
fake_cost_service: CostServiceProtocol,
|
|
34
|
+
fake_prompt_service: PromptServiceProtocol,
|
|
35
|
+
fake_review_llm_gateway: ReviewLLMGatewayProtocol,
|
|
36
|
+
fake_review_policy_service: ReviewPolicyServiceProtocol,
|
|
37
|
+
fake_review_comment_gateway: ReviewCommentGatewayProtocol,
|
|
38
|
+
fake_inline_comment_service: InlineCommentServiceProtocol,
|
|
39
|
+
) -> InlineReviewRunner:
|
|
40
|
+
return InlineReviewRunner(
|
|
41
|
+
vcs=fake_vcs_client,
|
|
42
|
+
git=fake_git_service,
|
|
43
|
+
diff=fake_diff_service,
|
|
44
|
+
cost=fake_cost_service,
|
|
45
|
+
prompt=fake_prompt_service,
|
|
46
|
+
review_policy=fake_review_policy_service,
|
|
47
|
+
inline_comment=fake_inline_comment_service,
|
|
48
|
+
review_llm_gateway=fake_review_llm_gateway,
|
|
49
|
+
review_comment_gateway=fake_review_comment_gateway,
|
|
50
|
+
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ai_review.services.cost.types import CostServiceProtocol
|
|
4
|
+
from ai_review.services.diff.types import DiffServiceProtocol
|
|
5
|
+
from ai_review.services.git.types import GitServiceProtocol
|
|
6
|
+
from ai_review.services.prompt.types import PromptServiceProtocol
|
|
7
|
+
from ai_review.services.review.gateway.types import ReviewLLMGatewayProtocol, ReviewCommentGatewayProtocol
|
|
8
|
+
from ai_review.services.review.internal.inline_reply.types import InlineCommentReplyServiceProtocol
|
|
9
|
+
from ai_review.services.review.internal.policy.types import ReviewPolicyServiceProtocol
|
|
10
|
+
from ai_review.services.review.runner.inline_reply import InlineReplyReviewRunner
|
|
11
|
+
from ai_review.services.review.runner.types import ReviewRunnerProtocol
|
|
12
|
+
from ai_review.services.vcs.types import VCSClientProtocol
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FakeInlineReplyReviewRunner(ReviewRunnerProtocol):
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.calls = []
|
|
18
|
+
|
|
19
|
+
async def run(self) -> None:
|
|
20
|
+
self.calls.append(("run", {}))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture
|
|
24
|
+
def fake_inline_reply_review_runner() -> FakeInlineReplyReviewRunner:
|
|
25
|
+
return FakeInlineReplyReviewRunner()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def inline_reply_review_runner(
|
|
30
|
+
fake_vcs_client: VCSClientProtocol,
|
|
31
|
+
fake_git_service: GitServiceProtocol,
|
|
32
|
+
fake_diff_service: DiffServiceProtocol,
|
|
33
|
+
fake_cost_service: CostServiceProtocol,
|
|
34
|
+
fake_prompt_service: PromptServiceProtocol,
|
|
35
|
+
fake_review_llm_gateway: ReviewLLMGatewayProtocol,
|
|
36
|
+
fake_review_policy_service: ReviewPolicyServiceProtocol,
|
|
37
|
+
fake_review_comment_gateway: ReviewCommentGatewayProtocol,
|
|
38
|
+
fake_inline_comment_reply_service: InlineCommentReplyServiceProtocol,
|
|
39
|
+
) -> InlineReplyReviewRunner:
|
|
40
|
+
return InlineReplyReviewRunner(
|
|
41
|
+
vcs=fake_vcs_client,
|
|
42
|
+
git=fake_git_service,
|
|
43
|
+
diff=fake_diff_service,
|
|
44
|
+
cost=fake_cost_service,
|
|
45
|
+
prompt=fake_prompt_service,
|
|
46
|
+
review_policy=fake_review_policy_service,
|
|
47
|
+
review_llm_gateway=fake_review_llm_gateway,
|
|
48
|
+
inline_comment_reply=fake_inline_comment_reply_service,
|
|
49
|
+
review_comment_gateway=fake_review_comment_gateway,
|
|
50
|
+
)
|