coding-client 1.21.2__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.
- coding_client/__init__.py +1 -0
- coding_client/api/__init__.py +19 -0
- coding_client/api/exception_handlers.py +158 -0
- coding_client/api/logging_setup.py +44 -0
- coding_client/api/metrics.py +40 -0
- coding_client/api/openapi_config.py +124 -0
- coding_client/api/request_logging.py +60 -0
- coding_client/api/validation.py +150 -0
- coding_client/auth/__init__.py +78 -0
- coding_client/auth/_default_tenant.py +132 -0
- coding_client/auth/_header_trust.py +98 -0
- coding_client/auth/_onbehalf.py +315 -0
- coding_client/auth/_trusted_networks.py +94 -0
- coding_client/auth/dependencies.py +61 -0
- coding_client/auth/middleware.py +445 -0
- coding_client/auth/models.py +83 -0
- coding_client/auth/outbound.py +137 -0
- coding_client/auth/rbac.py +21 -0
- coding_client/auth/rbac_coding.py +5 -0
- coding_client/auth/tenant.py +650 -0
- coding_client/auth/websocket.py +148 -0
- coding_client/clients/__init__.py +24 -0
- coding_client/clients/base.py +131 -0
- coding_client/clients/coding_ai.py +33 -0
- coding_client/clients/coding_analysis.py +36 -0
- coding_client/clients/coding_containers.py +45 -0
- coding_client/clients/coding_github.py +127 -0
- coding_client/clients/coding_realtime.py +127 -0
- coding_client/clients/coding_security.py +51 -0
- coding_client/clients/coding_testing.py +31 -0
- coding_client/clients/coding_workspaces.py +265 -0
- coding_client/config/__init__.py +12 -0
- coding_client/config/base_settings.py +61 -0
- coding_client/config/yaml_config_loader.py +172 -0
- coding_client/db/__init__.py +42 -0
- coding_client/db/db_types.py +122 -0
- coding_client/db/exceptions.py +59 -0
- coding_client/db/postgres_connection.py +572 -0
- coding_client/db/tenant_query_helper.py +417 -0
- coding_client/db_init.py +49 -0
- coding_client/exceptions/__init__.py +67 -0
- coding_client/exceptions/api_exceptions.py +395 -0
- coding_client/exceptions/pydantic_ai_exceptions.py +533 -0
- coding_client/interfaces/__init__.py +22 -0
- coding_client/interfaces/cache_interface.py +179 -0
- coding_client/interfaces/container_interface.py +49 -0
- coding_client/interfaces/docker_interface.py +283 -0
- coding_client/interfaces/graph_interface.py +28 -0
- coding_client/interfaces/security_interface.py +72 -0
- coding_client/interfaces/webhook_interface.py +67 -0
- coding_client/llm/__init__.py +54 -0
- coding_client/llm/base_agent.py +195 -0
- coding_client/llm/context.py +121 -0
- coding_client/llm/responses.py +102 -0
- coding_client/llm/routing.py +82 -0
- coding_client/llm/settings.py +102 -0
- coding_client/models/__init__.py +62 -0
- coding_client/models/agent.py +38 -0
- coding_client/models/ai_test_failure.py +745 -0
- coding_client/models/analysis.py +330 -0
- coding_client/models/architecture.py +685 -0
- coding_client/models/bug.py +128 -0
- coding_client/models/code_graph.py +317 -0
- coding_client/models/container.py +241 -0
- coding_client/models/core.py +878 -0
- coding_client/models/docker_container.py +104 -0
- coding_client/models/github.py +293 -0
- coding_client/models/logging.py +29 -0
- coding_client/models/package_manager.py +257 -0
- coding_client/models/pr_validation.py +440 -0
- coding_client/models/pydantic_ai.py +395 -0
- coding_client/models/repo_scanner.py +249 -0
- coding_client/models/responses.py +431 -0
- coding_client/models/security.py +185 -0
- coding_client/models/static_analysis.py +508 -0
- coding_client/models/system.py +48 -0
- coding_client/models/test_executor.py +204 -0
- coding_client/models/testing.py +673 -0
- coding_client/models/testing_config.py +200 -0
- coding_client/models/validation.py +127 -0
- coding_client/models_init.py +272 -0
- coding_client/telemetry.py +195 -0
- coding_client/testing.py +180 -0
- coding_client/types/__init__.py +130 -0
- coding_client/types/constraint_types.py +276 -0
- coding_client/types/core_types.py +112 -0
- coding_client/types/state_machine.py +443 -0
- coding_client/utils/__init__.py +86 -0
- coding_client/utils/archive_utils.py +387 -0
- coding_client/utils/ast_debug.py +45 -0
- coding_client/utils/async_timeout.py +364 -0
- coding_client/utils/constants.py +518 -0
- coding_client/utils/content_processing.py +326 -0
- coding_client/utils/database.py +916 -0
- coding_client/utils/encoding_helper.py +222 -0
- coding_client/utils/enum_helpers.py +166 -0
- coding_client/utils/file_operations.py +177 -0
- coding_client/utils/filesystem_ops.py +528 -0
- coding_client/utils/http_client.py +562 -0
- coding_client/utils/path_utils.py +471 -0
- coding_client/utils/profiling.py +421 -0
- coding_client/utils/response_builder.py +240 -0
- coding_client/utils/retry_helper.py +712 -0
- coding_client/utils/security_validation.py +423 -0
- coding_client-1.21.2.dist-info/METADATA +234 -0
- coding_client-1.21.2.dist-info/RECORD +109 -0
- coding_client-1.21.2.dist-info/WHEEL +5 -0
- coding_client-1.21.2.dist-info/licenses/LICENSE +201 -0
- coding_client-1.21.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
"""Pull request validation models for comprehensive change analysis.
|
|
2
|
+
|
|
3
|
+
This module provides sophisticated data models for analyzing pull request changes,
|
|
4
|
+
validating their impact, and generating actionable recommendations. The models
|
|
5
|
+
support detailed diff analysis, semantic change detection, and risk assessment
|
|
6
|
+
for code modifications.
|
|
7
|
+
|
|
8
|
+
The PR validation system enables:
|
|
9
|
+
- Comprehensive diff analysis with file-level change tracking
|
|
10
|
+
- Semantic analysis of code modifications using AST comparison
|
|
11
|
+
- Breaking change detection across API surfaces
|
|
12
|
+
- Impact assessment on tests, documentation, and dependencies
|
|
13
|
+
- Risk-based validation with automated recommendations
|
|
14
|
+
- Context-aware validation based on codebase patterns
|
|
15
|
+
|
|
16
|
+
Key Model Categories:
|
|
17
|
+
Change Models: FileChange, PRDiff for representing file modifications
|
|
18
|
+
Analysis Models: DiffAnalysisResult, SemanticAnalysisResult for change analysis
|
|
19
|
+
Validation Models: ValidationResult, ValidationIssue for validation outcomes
|
|
20
|
+
Impact Models: ChangeImpact, TestImpact, DocumentationImpact for scope analysis
|
|
21
|
+
Context Models: CodebaseContext, PRAnalysisContext for analysis environment
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
```python
|
|
25
|
+
from pr_validation_models import (
|
|
26
|
+
FileChange, PRDiff, ValidationResult,
|
|
27
|
+
ChangeType, RiskLevel, ChangeSeverity
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Create file change
|
|
31
|
+
file_change = FileChange(
|
|
32
|
+
filename="src/api/handlers.py",
|
|
33
|
+
file_type=FileType.PYTHON,
|
|
34
|
+
change_type=ChangeType.MODIFIED,
|
|
35
|
+
additions=15,
|
|
36
|
+
deletions=8,
|
|
37
|
+
patch="@@ -42,7 +42,10 @@ def process_request(request):",
|
|
38
|
+
before_content="def process_request(request):\n return handle(request)",
|
|
39
|
+
after_content="def process_request(request: Request) -> Response:\n return handle(request)"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Create PR diff
|
|
43
|
+
pr_diff = PRDiff(
|
|
44
|
+
base_sha="abc123",
|
|
45
|
+
head_sha="def456",
|
|
46
|
+
files_changed=[file_change],
|
|
47
|
+
stats=DiffStats.from_files([file_change]),
|
|
48
|
+
metadata={"pr_number": 123, "author": "developer"}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Validation result
|
|
52
|
+
result = ScriptValidationResult(
|
|
53
|
+
validation_type="type_safety",
|
|
54
|
+
passed=True,
|
|
55
|
+
score=0.95,
|
|
56
|
+
risk_level=RiskLevel.LOW,
|
|
57
|
+
issues=[],
|
|
58
|
+
recommendations=[],
|
|
59
|
+
confidence=0.9
|
|
60
|
+
)
|
|
61
|
+
```
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
from __future__ import annotations
|
|
65
|
+
|
|
66
|
+
import ast
|
|
67
|
+
from dataclasses import dataclass, field
|
|
68
|
+
from datetime import UTC, datetime
|
|
69
|
+
from enum import Enum
|
|
70
|
+
from typing import Any
|
|
71
|
+
|
|
72
|
+
from .static_analysis import StaticAnalysisChangeType
|
|
73
|
+
|
|
74
|
+
# Alias for backward compatibility
|
|
75
|
+
ChangeType = StaticAnalysisChangeType
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class FileType(Enum):
|
|
79
|
+
"""File types for specialized validation."""
|
|
80
|
+
|
|
81
|
+
PYTHON = "python"
|
|
82
|
+
JAVASCRIPT = "javascript"
|
|
83
|
+
TYPESCRIPT = "typescript"
|
|
84
|
+
MARKDOWN = "markdown"
|
|
85
|
+
YAML = "yaml"
|
|
86
|
+
JSON = "json"
|
|
87
|
+
HTML = "html"
|
|
88
|
+
CSS = "css"
|
|
89
|
+
DOCKERFILE = "dockerfile"
|
|
90
|
+
UNKNOWN = "unknown"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class RiskLevel(Enum):
|
|
94
|
+
"""Risk levels for validation results."""
|
|
95
|
+
|
|
96
|
+
LOW = "LOW"
|
|
97
|
+
MEDIUM = "MEDIUM"
|
|
98
|
+
HIGH = "HIGH"
|
|
99
|
+
CRITICAL = "CRITICAL"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class ChangeSeverity(Enum):
|
|
103
|
+
"""Severity levels for file changes."""
|
|
104
|
+
|
|
105
|
+
MINOR = "MINOR"
|
|
106
|
+
MODERATE = "MODERATE"
|
|
107
|
+
MAJOR = "MAJOR"
|
|
108
|
+
COMPLETE_REWRITE = "COMPLETE_REWRITE"
|
|
109
|
+
SECURITY_ISSUE = "SECURITY_ISSUE"
|
|
110
|
+
UNKNOWN = "UNKNOWN"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass
|
|
114
|
+
class DiffStats:
|
|
115
|
+
"""Statistics about a PR diff."""
|
|
116
|
+
|
|
117
|
+
total_files: int
|
|
118
|
+
total_additions: int
|
|
119
|
+
total_deletions: int
|
|
120
|
+
files_added: int
|
|
121
|
+
files_deleted: int
|
|
122
|
+
files_modified: int
|
|
123
|
+
files_renamed: int
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def from_files(cls, files_changed: list[FileChange]) -> DiffStats:
|
|
127
|
+
"""Create DiffStats from a list of file changes."""
|
|
128
|
+
total_additions = sum(f.additions for f in files_changed)
|
|
129
|
+
total_deletions = sum(f.deletions for f in files_changed)
|
|
130
|
+
|
|
131
|
+
files_added = sum(1 for f in files_changed if f.change_type == ChangeType.ADDED)
|
|
132
|
+
files_deleted = sum(1 for f in files_changed if f.change_type == ChangeType.DELETED)
|
|
133
|
+
files_modified = sum(1 for f in files_changed if f.change_type == ChangeType.MODIFIED)
|
|
134
|
+
files_renamed = sum(1 for f in files_changed if f.change_type == ChangeType.RENAMED)
|
|
135
|
+
|
|
136
|
+
return cls(
|
|
137
|
+
total_files=len(files_changed),
|
|
138
|
+
total_additions=total_additions,
|
|
139
|
+
total_deletions=total_deletions,
|
|
140
|
+
files_added=files_added,
|
|
141
|
+
files_deleted=files_deleted,
|
|
142
|
+
files_modified=files_modified,
|
|
143
|
+
files_renamed=files_renamed,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@dataclass
|
|
148
|
+
class ValidationFileChange:
|
|
149
|
+
"""Represents changes to a single file in validation context."""
|
|
150
|
+
|
|
151
|
+
filename: str
|
|
152
|
+
file_type: FileType
|
|
153
|
+
change_type: ChangeType
|
|
154
|
+
additions: int
|
|
155
|
+
deletions: int
|
|
156
|
+
patch: str
|
|
157
|
+
before_content: str | None = None
|
|
158
|
+
after_content: str | None = None
|
|
159
|
+
ast_before: ast.AST | None = None
|
|
160
|
+
ast_after: ast.AST | None = None
|
|
161
|
+
binary: bool = False
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def total_changes(self) -> int:
|
|
165
|
+
"""Total number of line changes."""
|
|
166
|
+
return self.additions + self.deletions
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
# Alias for backward compatibility
|
|
170
|
+
FileChange = ValidationFileChange
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@dataclass
|
|
174
|
+
class PRDiff:
|
|
175
|
+
"""Represents a complete PR diff with all changes."""
|
|
176
|
+
|
|
177
|
+
base_sha: str
|
|
178
|
+
head_sha: str
|
|
179
|
+
files_changed: list[FileChange]
|
|
180
|
+
stats: DiffStats
|
|
181
|
+
metadata: dict[str, Any]
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def change_complexity(self) -> float:
|
|
185
|
+
"""Calculate overall change complexity."""
|
|
186
|
+
if not self.files_changed:
|
|
187
|
+
return 0.0
|
|
188
|
+
|
|
189
|
+
total_changes = sum(f.total_changes for f in self.files_changed)
|
|
190
|
+
return min(total_changes / 100.0, 10.0) # Cap at 10.0
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@dataclass
|
|
194
|
+
class ValidationIssue:
|
|
195
|
+
"""Represents a validation issue found during analysis."""
|
|
196
|
+
|
|
197
|
+
type: str
|
|
198
|
+
severity: str
|
|
199
|
+
message: str
|
|
200
|
+
file: str
|
|
201
|
+
line: int | None = None
|
|
202
|
+
column: int | None = None
|
|
203
|
+
rule: str | None = None
|
|
204
|
+
suggestion: str | None = None
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@dataclass
|
|
208
|
+
class Recommendation:
|
|
209
|
+
"""Represents an actionable recommendation for update."""
|
|
210
|
+
|
|
211
|
+
type: str
|
|
212
|
+
priority: str
|
|
213
|
+
description: str
|
|
214
|
+
action: str
|
|
215
|
+
file: str | None = None
|
|
216
|
+
automated: bool = False
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@dataclass
|
|
220
|
+
class APICompatibility:
|
|
221
|
+
"""Represents API compatibility information."""
|
|
222
|
+
|
|
223
|
+
is_compatible: bool
|
|
224
|
+
breaking_changes: list[str]
|
|
225
|
+
deprecations: list[str]
|
|
226
|
+
version_impact: str # MAJOR, MINOR, PATCH
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@dataclass
|
|
230
|
+
class TestImpact:
|
|
231
|
+
"""Represents impact on tests."""
|
|
232
|
+
|
|
233
|
+
tests_affected: list[str]
|
|
234
|
+
coverage_change: float
|
|
235
|
+
new_tests_needed: list[str]
|
|
236
|
+
obsolete_tests: list[str]
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@dataclass
|
|
240
|
+
class DocumentationImpact:
|
|
241
|
+
"""Represents impact on documentation."""
|
|
242
|
+
|
|
243
|
+
docs_affected: list[str]
|
|
244
|
+
outdated_docs: list[str]
|
|
245
|
+
new_docs_needed: list[str]
|
|
246
|
+
doc_completeness_score: float
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
@dataclass
|
|
250
|
+
class ChangeImpact:
|
|
251
|
+
"""Represents the impact scope of changes."""
|
|
252
|
+
|
|
253
|
+
affected_functions: list[str]
|
|
254
|
+
affected_classes: list[str]
|
|
255
|
+
dependency_impact: list[str]
|
|
256
|
+
test_impact: TestImpact
|
|
257
|
+
documentation_impact: DocumentationImpact
|
|
258
|
+
api_compatibility: APICompatibility
|
|
259
|
+
estimated_effort: str # LOW, MEDIUM, HIGH
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
@dataclass
|
|
263
|
+
class ValidationResult:
|
|
264
|
+
"""Augmented validation result with change context."""
|
|
265
|
+
|
|
266
|
+
validation_type: str
|
|
267
|
+
passed: bool
|
|
268
|
+
score: float
|
|
269
|
+
risk_level: RiskLevel
|
|
270
|
+
issues: list[ValidationIssue]
|
|
271
|
+
recommendations: list[Recommendation]
|
|
272
|
+
change_impact: ChangeImpact | None = None
|
|
273
|
+
confidence: float = 1.0
|
|
274
|
+
execution_time: float = 0.0
|
|
275
|
+
timestamp: datetime = field(default_factory=lambda: datetime.now(UTC))
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
def critical_issues(self) -> list[ValidationIssue]:
|
|
279
|
+
"""Get only critical issues."""
|
|
280
|
+
return [issue for issue in self.issues if issue.severity == "CRITICAL"]
|
|
281
|
+
|
|
282
|
+
@property
|
|
283
|
+
def high_priority_recommendations(self) -> list[Recommendation]:
|
|
284
|
+
"""Get high priority recommendations."""
|
|
285
|
+
return [rec for rec in self.recommendations if rec.priority == "HIGH"]
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
@dataclass
|
|
289
|
+
class FileChangeAnalysis:
|
|
290
|
+
"""Analysis result for a single file change."""
|
|
291
|
+
|
|
292
|
+
filename: str
|
|
293
|
+
change_severity: ChangeSeverity
|
|
294
|
+
change_patterns: list[str]
|
|
295
|
+
risk_indicators: list[str]
|
|
296
|
+
line_change_ratio: float
|
|
297
|
+
content_similarity: float
|
|
298
|
+
file_type: FileType
|
|
299
|
+
|
|
300
|
+
@property
|
|
301
|
+
def is_high_risk(self) -> bool:
|
|
302
|
+
"""Check if this change is high risk."""
|
|
303
|
+
return (
|
|
304
|
+
self.change_severity in [ChangeSeverity.COMPLETE_REWRITE, ChangeSeverity.SECURITY_ISSUE]
|
|
305
|
+
or "DANGEROUS_LOGIC_CHANGES" in self.risk_indicators
|
|
306
|
+
or "SECURITY_SENSITIVE_FILE_MODIFIED" in self.risk_indicators
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
@dataclass
|
|
311
|
+
class DiffAnalysisResult:
|
|
312
|
+
"""Result of diff analysis."""
|
|
313
|
+
|
|
314
|
+
file_analyses: list[FileChangeAnalysis]
|
|
315
|
+
overall_patterns: list[str]
|
|
316
|
+
risk_factors: list[str]
|
|
317
|
+
change_complexity: float
|
|
318
|
+
requires_careful_review: bool
|
|
319
|
+
|
|
320
|
+
@property
|
|
321
|
+
def high_risk_files(self) -> list[FileChangeAnalysis]:
|
|
322
|
+
"""Get files that are high risk."""
|
|
323
|
+
return [analysis for analysis in self.file_analyses if analysis.is_high_risk]
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
@dataclass
|
|
327
|
+
class FunctionSignature:
|
|
328
|
+
"""Represents a function signature for comparison."""
|
|
329
|
+
|
|
330
|
+
name: str
|
|
331
|
+
args: list[str]
|
|
332
|
+
defaults: list[str]
|
|
333
|
+
varargs: str | None
|
|
334
|
+
kwargs: str | None
|
|
335
|
+
return_type: str | None
|
|
336
|
+
decorators: list[str]
|
|
337
|
+
is_public: bool
|
|
338
|
+
lineno: int
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
@dataclass
|
|
342
|
+
class ClassDefinition:
|
|
343
|
+
"""Represents a class definition for comparison."""
|
|
344
|
+
|
|
345
|
+
name: str
|
|
346
|
+
bases: list[str]
|
|
347
|
+
methods: dict[str, FunctionSignature]
|
|
348
|
+
attributes: list[str]
|
|
349
|
+
is_public: bool
|
|
350
|
+
lineno: int
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
@dataclass
|
|
354
|
+
class BreakingChange:
|
|
355
|
+
"""Represents a breaking change in the API."""
|
|
356
|
+
|
|
357
|
+
type: str
|
|
358
|
+
severity: str
|
|
359
|
+
description: str
|
|
360
|
+
file_path: str
|
|
361
|
+
affected_symbol: str
|
|
362
|
+
recommendation: str
|
|
363
|
+
line_number: int | None = None
|
|
364
|
+
confidence: float = 1.0
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
@dataclass
|
|
368
|
+
class SemanticAnalysisResult:
|
|
369
|
+
"""Result of semantic analysis."""
|
|
370
|
+
|
|
371
|
+
breaking_changes: list[BreakingChange]
|
|
372
|
+
logic_safety_issues: list[ValidationIssue]
|
|
373
|
+
api_surface_changes: dict[str, Any]
|
|
374
|
+
complexity_changes: dict[str, float]
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def has_breaking_changes(self) -> bool:
|
|
378
|
+
"""Check if there are any breaking changes."""
|
|
379
|
+
return len(self.breaking_changes) > 0
|
|
380
|
+
|
|
381
|
+
@property
|
|
382
|
+
def has_logic_safety_issues(self) -> bool:
|
|
383
|
+
"""Check if there are logic safety issues."""
|
|
384
|
+
return len(self.logic_safety_issues) > 0
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
@dataclass
|
|
388
|
+
class ImpactAssessment:
|
|
389
|
+
"""Assessment of change impact across the codebase."""
|
|
390
|
+
|
|
391
|
+
dependency_impacts: list[str]
|
|
392
|
+
test_coverage_impact: TestImpact
|
|
393
|
+
documentation_impact: DocumentationImpact
|
|
394
|
+
performance_impact: dict[str, Any]
|
|
395
|
+
security_impact: dict[str, Any]
|
|
396
|
+
|
|
397
|
+
@property
|
|
398
|
+
def overall_impact_score(self) -> float:
|
|
399
|
+
"""Calculate overall impact score."""
|
|
400
|
+
score = 0.0
|
|
401
|
+
if self.dependency_impacts:
|
|
402
|
+
score += len(self.dependency_impacts) * 0.1
|
|
403
|
+
if self.test_coverage_impact.coverage_change < 0:
|
|
404
|
+
score += abs(self.test_coverage_impact.coverage_change) * 2.0
|
|
405
|
+
if self.documentation_impact.outdated_docs:
|
|
406
|
+
score += len(self.documentation_impact.outdated_docs) * 0.05
|
|
407
|
+
return min(score, 10.0)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@dataclass
|
|
411
|
+
class CodebaseContext:
|
|
412
|
+
"""Context about the codebase for analysis."""
|
|
413
|
+
|
|
414
|
+
total_files: int
|
|
415
|
+
total_lines: int
|
|
416
|
+
main_languages: list[str]
|
|
417
|
+
test_framework: str | None
|
|
418
|
+
documentation_format: str | None
|
|
419
|
+
dependencies: list[str]
|
|
420
|
+
architecture_patterns: list[str]
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
@dataclass
|
|
424
|
+
class PRAnalysisContext:
|
|
425
|
+
"""Context for running analysis."""
|
|
426
|
+
|
|
427
|
+
pr_diff: PRDiff
|
|
428
|
+
codebase_context: CodebaseContext
|
|
429
|
+
diff_analysis: DiffAnalysisResult | None = None
|
|
430
|
+
semantic_analysis: SemanticAnalysisResult | None = None
|
|
431
|
+
impact_assessment: ImpactAssessment | None = None
|
|
432
|
+
validation_config: dict[str, Any] = field(default_factory=dict)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
# Rebuild models to ensure proper forward reference resolution
|
|
436
|
+
# For Pydantic v2, use model_rebuild if available, otherwise skip
|
|
437
|
+
if hasattr(FunctionSignature, "model_rebuild"):
|
|
438
|
+
FunctionSignature.model_rebuild()
|
|
439
|
+
if hasattr(FileChange, "model_rebuild"):
|
|
440
|
+
FileChange.model_rebuild()
|