codeguardian-cli 1.0.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.
- CODEGUARDIAN/__init__.py +0 -0
- CODEGUARDIAN/analyzers/__init__.py +0 -0
- CODEGUARDIAN/analyzers/circular_dependency_analyzer.py +101 -0
- CODEGUARDIAN/analyzers/db_access_analyzer.py +55 -0
- CODEGUARDIAN/analyzers/dependency_analyzer.py +259 -0
- CODEGUARDIAN/analyzers/file_analyzer.py +96 -0
- CODEGUARDIAN/analyzers/function_analyzer.py +199 -0
- CODEGUARDIAN/analyzers/source_code_analyzer.py +169 -0
- CODEGUARDIAN/cli/__init__.py +0 -0
- CODEGUARDIAN/cli/commands.py +619 -0
- CODEGUARDIAN/config/__init__.py +0 -0
- CODEGUARDIAN/config/config_loader.py +76 -0
- CODEGUARDIAN/config/settings.py +2 -0
- CODEGUARDIAN/main.py +4 -0
- CODEGUARDIAN/reports/__init__.py +0 -0
- CODEGUARDIAN/reports/architecture_score.py +68 -0
- CODEGUARDIAN/reports/console_reporter.py +487 -0
- CODEGUARDIAN/reports/html_reporter.py +293 -0
- CODEGUARDIAN/reports/json_reporter.py +69 -0
- CODEGUARDIAN/reports/markdown_reporter.py +130 -0
- CODEGUARDIAN/reports/severity.py +15 -0
- CODEGUARDIAN/reports/statistics_reporter.py +183 -0
- CODEGUARDIAN/rules/__init__.py +0 -0
- CODEGUARDIAN/rules/architecture_rules.py +5 -0
- CODEGUARDIAN/rules/architecture_validator.py +69 -0
- CODEGUARDIAN/rules/controllers/user_controller.py +16 -0
- CODEGUARDIAN/src/__init__.py +0 -0
- CODEGUARDIAN/src/discovery/__init__.py +0 -0
- CODEGUARDIAN/src/discovery/finder.py +39 -0
- CODEGUARDIAN/src/extractor/__init__.py +0 -0
- CODEGUARDIAN/src/extractor/class_extractor.py +32 -0
- CODEGUARDIAN/src/extractor/function_extractor.py +17 -0
- CODEGUARDIAN/src/extractor/import_extractor.py +23 -0
- CODEGUARDIAN/src/extractor/python_class_extractor.py +13 -0
- CODEGUARDIAN/src/extractor/python_function_extractor.py +16 -0
- CODEGUARDIAN/src/extractor/python_imports_extractor.py +24 -0
- CODEGUARDIAN/src/main.py +65 -0
- CODEGUARDIAN/src/parser/__init__.py +0 -0
- CODEGUARDIAN/src/parser/ts_parser.py +14 -0
- CODEGUARDIAN/src/tree/Walker.py +10 -0
- CODEGUARDIAN/src/tree/__init__.py +0 -0
- CODEGUARDIAN/utils/__init__.py +0 -0
- CODEGUARDIAN/utils/ast_cache.py +47 -0
- CODEGUARDIAN/utils/file_cache.py +30 -0
- CODEGUARDIAN/utils/layer_utils.py +19 -0
- codeguardian_cli-1.0.0.dist-info/METADATA +43 -0
- codeguardian_cli-1.0.0.dist-info/RECORD +50 -0
- codeguardian_cli-1.0.0.dist-info/WHEEL +5 -0
- codeguardian_cli-1.0.0.dist-info/entry_points.txt +2 -0
- codeguardian_cli-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import typer
|
|
3
|
+
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from rich.progress import Progress
|
|
7
|
+
|
|
8
|
+
from CODEGUARDIAN.analyzers.file_analyzer import FileAnalyzer
|
|
9
|
+
from CODEGUARDIAN.analyzers.function_analyzer import FunctionAnalyzer
|
|
10
|
+
from CODEGUARDIAN.analyzers.dependency_analyzer import (
|
|
11
|
+
DependencyAnalyzer
|
|
12
|
+
)
|
|
13
|
+
from CODEGUARDIAN.analyzers.circular_dependency_analyzer import (
|
|
14
|
+
CircularDependencyAnalyzer
|
|
15
|
+
)
|
|
16
|
+
from CODEGUARDIAN.analyzers.source_code_analyzer import (
|
|
17
|
+
SourceCodeAnalyzer
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from CODEGUARDIAN.rules.architecture_validator import (
|
|
21
|
+
ArchitectureValidator
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from CODEGUARDIAN.reports.console_reporter import (
|
|
25
|
+
ConsoleReporter
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from CODEGUARDIAN.reports.json_reporter import (
|
|
29
|
+
JsonReporter
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
from CODEGUARDIAN.reports.architecture_score import (
|
|
33
|
+
ArchitectureScoreCalculator
|
|
34
|
+
)
|
|
35
|
+
from CODEGUARDIAN.reports.html_reporter import (
|
|
36
|
+
HtmlReporter
|
|
37
|
+
)
|
|
38
|
+
from CODEGUARDIAN.reports.markdown_reporter import (
|
|
39
|
+
MarkdownReporter
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
from CODEGUARDIAN.analyzers.db_access_analyzer import (
|
|
43
|
+
DBAccessAnalyzer
|
|
44
|
+
)
|
|
45
|
+
from CODEGUARDIAN.reports.statistics_reporter import (
|
|
46
|
+
StatisticsReporter
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
app = typer.Typer(
|
|
51
|
+
help="""
|
|
52
|
+
CodeGuardian
|
|
53
|
+
|
|
54
|
+
Analyze your project's architecture and code quality.
|
|
55
|
+
|
|
56
|
+
Supported languages:
|
|
57
|
+
• Python (.py)
|
|
58
|
+
• TypeScript (.ts)
|
|
59
|
+
• JavaScript (.js)
|
|
60
|
+
|
|
61
|
+
Generate reports in Console, JSON, HTML and Markdown.
|
|
62
|
+
"""
|
|
63
|
+
)
|
|
64
|
+
console = Console()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_score_color(score):
|
|
68
|
+
|
|
69
|
+
if score >= 90:
|
|
70
|
+
return "green"
|
|
71
|
+
|
|
72
|
+
elif score >= 70:
|
|
73
|
+
return "yellow"
|
|
74
|
+
|
|
75
|
+
return "red"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def calculate_project_score(
|
|
79
|
+
path,
|
|
80
|
+
max_file_lines=None,
|
|
81
|
+
max_function_lines=None
|
|
82
|
+
):
|
|
83
|
+
file_violations = (
|
|
84
|
+
FileAnalyzer(
|
|
85
|
+
max_file_lines
|
|
86
|
+
).analyze(path)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
function_violations = (
|
|
90
|
+
FunctionAnalyzer(
|
|
91
|
+
max_function_lines
|
|
92
|
+
).analyze_project(path)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
dependencies = (
|
|
96
|
+
DependencyAnalyzer()
|
|
97
|
+
.analyze_project(path)
|
|
98
|
+
)
|
|
99
|
+
db_access_violations = (
|
|
100
|
+
DBAccessAnalyzer()
|
|
101
|
+
.analyze(dependencies)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
architecture_violations = (
|
|
107
|
+
ArchitectureValidator()
|
|
108
|
+
.validate(dependencies)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
circular_violations = (
|
|
112
|
+
CircularDependencyAnalyzer()
|
|
113
|
+
.detect(dependencies)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
ArchitectureScoreCalculator()
|
|
118
|
+
.calculate(
|
|
119
|
+
file_violations,
|
|
120
|
+
function_violations,
|
|
121
|
+
architecture_violations,
|
|
122
|
+
circular_violations,
|
|
123
|
+
db_access_violations
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def count_python_files(path):
|
|
129
|
+
|
|
130
|
+
count = 0
|
|
131
|
+
|
|
132
|
+
ignore_dirs = {
|
|
133
|
+
"venv",
|
|
134
|
+
".git",
|
|
135
|
+
"__pycache__",
|
|
136
|
+
".pytest_cache"
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for root, dirs, files in os.walk(path):
|
|
140
|
+
|
|
141
|
+
dirs[:] = [
|
|
142
|
+
d for d in dirs
|
|
143
|
+
if d not in ignore_dirs
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
for file in files:
|
|
147
|
+
|
|
148
|
+
if file.endswith(".py"):
|
|
149
|
+
|
|
150
|
+
count += 1
|
|
151
|
+
|
|
152
|
+
return count
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@app.command(
|
|
156
|
+
help="""
|
|
157
|
+
Run a complete architecture scan.
|
|
158
|
+
|
|
159
|
+
Examples:
|
|
160
|
+
|
|
161
|
+
python main.py scan
|
|
162
|
+
|
|
163
|
+
python main.py scan --json
|
|
164
|
+
|
|
165
|
+
python main.py scan --html
|
|
166
|
+
|
|
167
|
+
python main.py scan --markdown
|
|
168
|
+
|
|
169
|
+
python main.py scan --score
|
|
170
|
+
|
|
171
|
+
python main.py scan --details
|
|
172
|
+
"""
|
|
173
|
+
)
|
|
174
|
+
def scan(
|
|
175
|
+
|
|
176
|
+
path: str = ".",
|
|
177
|
+
max_file_lines: int | None = typer.Option(
|
|
178
|
+
None,
|
|
179
|
+
"--max-file-lines",
|
|
180
|
+
help="Maximum allowed lines per file."
|
|
181
|
+
),
|
|
182
|
+
|
|
183
|
+
max_function_lines: int | None = typer.Option(
|
|
184
|
+
None,
|
|
185
|
+
"--max-function-lines",
|
|
186
|
+
help="Maximum allowed lines per function."
|
|
187
|
+
),
|
|
188
|
+
json_output: bool = typer.Option(
|
|
189
|
+
False,
|
|
190
|
+
"--json",
|
|
191
|
+
"-j",
|
|
192
|
+
help="Generate a JSON report."
|
|
193
|
+
),
|
|
194
|
+
|
|
195
|
+
html_output: bool = typer.Option(
|
|
196
|
+
False,
|
|
197
|
+
"--html",
|
|
198
|
+
help="Generate an HTML report."
|
|
199
|
+
),
|
|
200
|
+
|
|
201
|
+
score_only: bool = typer.Option(
|
|
202
|
+
False,
|
|
203
|
+
"--score",
|
|
204
|
+
help="Display only the architecture score."
|
|
205
|
+
),
|
|
206
|
+
details: bool = typer.Option(
|
|
207
|
+
False,
|
|
208
|
+
"--details",
|
|
209
|
+
help="Show detailed classes, functions and imports."
|
|
210
|
+
),
|
|
211
|
+
markdown_output: bool = typer.Option(
|
|
212
|
+
False,
|
|
213
|
+
"--markdown",
|
|
214
|
+
help="Generate a Markdown report."
|
|
215
|
+
),
|
|
216
|
+
statistics: bool = typer.Option(
|
|
217
|
+
False,
|
|
218
|
+
"--statistics",
|
|
219
|
+
"-s",
|
|
220
|
+
help="Display project scan statistics."
|
|
221
|
+
),
|
|
222
|
+
|
|
223
|
+
):
|
|
224
|
+
if not (
|
|
225
|
+
json_output
|
|
226
|
+
or html_output
|
|
227
|
+
or score_only
|
|
228
|
+
):
|
|
229
|
+
|
|
230
|
+
console.print(
|
|
231
|
+
Panel.fit(
|
|
232
|
+
f"Scanning project: "
|
|
233
|
+
f"[bold cyan]{path}[/bold cyan]",
|
|
234
|
+
title="CodeGuardian"
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
reporter = ConsoleReporter()
|
|
239
|
+
|
|
240
|
+
with Progress(
|
|
241
|
+
disable=(
|
|
242
|
+
json_output
|
|
243
|
+
or html_output
|
|
244
|
+
or markdown_output
|
|
245
|
+
or score_only
|
|
246
|
+
)
|
|
247
|
+
) as progress:
|
|
248
|
+
|
|
249
|
+
file_task = progress.add_task(
|
|
250
|
+
"[cyan]Analyzing files...",
|
|
251
|
+
total=1
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
file_violations = (
|
|
255
|
+
FileAnalyzer(
|
|
256
|
+
max_file_lines
|
|
257
|
+
).analyze(path)
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
progress.update(
|
|
261
|
+
file_task,
|
|
262
|
+
advance=1
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
function_task = progress.add_task(
|
|
266
|
+
"[green]Analyzing functions...",
|
|
267
|
+
total=1
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
function_violations = (
|
|
271
|
+
FunctionAnalyzer(
|
|
272
|
+
max_function_lines
|
|
273
|
+
).analyze_project(path)
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
progress.update(
|
|
277
|
+
function_task,
|
|
278
|
+
advance=1
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
dependency_task = progress.add_task(
|
|
282
|
+
"[yellow]Analyzing dependencies...",
|
|
283
|
+
total=1
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
dependencies = (
|
|
287
|
+
DependencyAnalyzer()
|
|
288
|
+
.analyze_project(path)
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
db_access_violations = (
|
|
292
|
+
DBAccessAnalyzer()
|
|
293
|
+
.analyze(dependencies)
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
progress.update(
|
|
297
|
+
dependency_task,
|
|
298
|
+
advance=1
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
architecture_task = progress.add_task(
|
|
302
|
+
"[red]Validating architecture...",
|
|
303
|
+
total=1
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
architecture_violations = (
|
|
307
|
+
ArchitectureValidator()
|
|
308
|
+
.validate(dependencies)
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
progress.update(
|
|
312
|
+
architecture_task,
|
|
313
|
+
advance=1
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
circular_task = progress.add_task(
|
|
317
|
+
"[magenta]Checking circular dependencies...",
|
|
318
|
+
total=1
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
circular_violations = (
|
|
322
|
+
CircularDependencyAnalyzer()
|
|
323
|
+
.detect(dependencies)
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
progress.update(
|
|
327
|
+
circular_task,
|
|
328
|
+
advance=1
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
source_task = progress.add_task(
|
|
332
|
+
"[blue]Analyzing JS/TS files...",
|
|
333
|
+
total=1
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
source_analysis = (
|
|
337
|
+
SourceCodeAnalyzer()
|
|
338
|
+
.analyze(path)
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
progress.update(
|
|
342
|
+
source_task,
|
|
343
|
+
advance=1
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
score_task = progress.add_task(
|
|
347
|
+
"[white]Calculating score...",
|
|
348
|
+
total=1
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
score = (
|
|
352
|
+
ArchitectureScoreCalculator()
|
|
353
|
+
.calculate(file_violations,function_violations,architecture_violations,circular_violations,db_access_violations
|
|
354
|
+
)
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
progress.update(
|
|
358
|
+
score_task,
|
|
359
|
+
advance=1
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
if json_output:
|
|
363
|
+
|
|
364
|
+
output = (
|
|
365
|
+
JsonReporter()
|
|
366
|
+
.generate(
|
|
367
|
+
|
|
368
|
+
file_violations,
|
|
369
|
+
function_violations,
|
|
370
|
+
architecture_violations,
|
|
371
|
+
circular_violations,
|
|
372
|
+
db_access_violations,
|
|
373
|
+
source_analysis,
|
|
374
|
+
score
|
|
375
|
+
)
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
print(output)
|
|
379
|
+
|
|
380
|
+
return
|
|
381
|
+
|
|
382
|
+
if html_output:
|
|
383
|
+
|
|
384
|
+
HtmlReporter().generate(
|
|
385
|
+
|
|
386
|
+
file_violations,
|
|
387
|
+
function_violations,
|
|
388
|
+
architecture_violations,
|
|
389
|
+
circular_violations,
|
|
390
|
+
db_access_violations,
|
|
391
|
+
source_analysis,
|
|
392
|
+
score
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
console.print(
|
|
396
|
+
"[green]✓ report.html generated[/green]"
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
return
|
|
400
|
+
|
|
401
|
+
if markdown_output:
|
|
402
|
+
|
|
403
|
+
MarkdownReporter().generate(
|
|
404
|
+
|
|
405
|
+
file_violations,
|
|
406
|
+
function_violations,
|
|
407
|
+
architecture_violations,
|
|
408
|
+
circular_violations,
|
|
409
|
+
db_access_violations,
|
|
410
|
+
source_analysis,
|
|
411
|
+
score
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
console.print(
|
|
415
|
+
"[green]✓ report.md generated[/green]"
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
return
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
if score_only:
|
|
422
|
+
|
|
423
|
+
score_color = get_score_color(
|
|
424
|
+
score
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
console.print(
|
|
428
|
+
f"[bold {score_color}]"
|
|
429
|
+
f"{score}/100"
|
|
430
|
+
f"[/bold {score_color}]"
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
return
|
|
434
|
+
if statistics:
|
|
435
|
+
|
|
436
|
+
StatisticsReporter().show_statistics(
|
|
437
|
+
source_analysis,
|
|
438
|
+
file_violations,
|
|
439
|
+
function_violations,
|
|
440
|
+
architecture_violations,
|
|
441
|
+
circular_violations,
|
|
442
|
+
db_access_violations,
|
|
443
|
+
score
|
|
444
|
+
)
|
|
445
|
+
return
|
|
446
|
+
|
|
447
|
+
reporter.show_dashboard(
|
|
448
|
+
source_analysis,
|
|
449
|
+
file_violations,
|
|
450
|
+
function_violations,
|
|
451
|
+
architecture_violations,
|
|
452
|
+
circular_violations,
|
|
453
|
+
db_access_violations,
|
|
454
|
+
score
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
console.print()
|
|
458
|
+
|
|
459
|
+
if file_violations:
|
|
460
|
+
|
|
461
|
+
reporter.show_file_violations(
|
|
462
|
+
file_violations
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
else:
|
|
466
|
+
|
|
467
|
+
console.print(
|
|
468
|
+
"[green]✓ No oversized files found[/green]"
|
|
469
|
+
)
|
|
470
|
+
if function_violations:
|
|
471
|
+
|
|
472
|
+
reporter.show_function_violations(
|
|
473
|
+
function_violations
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
else:
|
|
477
|
+
|
|
478
|
+
console.print(
|
|
479
|
+
"[green]✓ No oversized functions found[/green]"
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
if architecture_violations:
|
|
483
|
+
|
|
484
|
+
reporter.show_architecture_violations(
|
|
485
|
+
architecture_violations
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
else:
|
|
489
|
+
|
|
490
|
+
console.print(
|
|
491
|
+
"[green]✓ No architecture violations found[/green]"
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
if circular_violations:
|
|
495
|
+
|
|
496
|
+
reporter.show_circular_dependencies(
|
|
497
|
+
circular_violations
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
else:
|
|
501
|
+
|
|
502
|
+
console.print(
|
|
503
|
+
"[green]✓ No circular dependencies found[/green]"
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
if db_access_violations:
|
|
509
|
+
|
|
510
|
+
reporter.show_db_access_violations(
|
|
511
|
+
db_access_violations
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
else:
|
|
515
|
+
|
|
516
|
+
console.print(
|
|
517
|
+
"[green]✓ No direct database access found[/green]"
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
if source_analysis:
|
|
521
|
+
|
|
522
|
+
reporter.show_source_analysis(
|
|
523
|
+
source_analysis,
|
|
524
|
+
details
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
score_color = get_score_color(score)
|
|
528
|
+
|
|
529
|
+
console.print()
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
console.print(
|
|
534
|
+
Panel.fit(
|
|
535
|
+
f"[bold {score_color}]"
|
|
536
|
+
f"Architecture Score: "
|
|
537
|
+
f"{score}/100"
|
|
538
|
+
f"[/bold {score_color}]",
|
|
539
|
+
title="Health Report"
|
|
540
|
+
)
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
critical_found = (
|
|
544
|
+
len(architecture_violations) > 0
|
|
545
|
+
or len(circular_violations) > 0
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
if critical_found:
|
|
549
|
+
raise typer.Exit(code=1)
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
console.print(
|
|
553
|
+
"[bold green]✓ Scan completed successfully[/bold green]"
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
@app.command()
|
|
561
|
+
def report(
|
|
562
|
+
|
|
563
|
+
path: str = ".",
|
|
564
|
+
|
|
565
|
+
max_file_lines: int | None = typer.Option(
|
|
566
|
+
None,
|
|
567
|
+
"--max-file-lines"
|
|
568
|
+
),
|
|
569
|
+
|
|
570
|
+
max_function_lines: int | None = typer.Option(
|
|
571
|
+
None,
|
|
572
|
+
"--max-function-lines"
|
|
573
|
+
)
|
|
574
|
+
):
|
|
575
|
+
|
|
576
|
+
reporter = ConsoleReporter()
|
|
577
|
+
|
|
578
|
+
file_violations = (
|
|
579
|
+
FileAnalyzer(
|
|
580
|
+
max_file_lines
|
|
581
|
+
).analyze(path)
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
function_violations = (
|
|
585
|
+
FunctionAnalyzer(
|
|
586
|
+
max_function_lines
|
|
587
|
+
).analyze_project(path)
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
dependencies = (
|
|
591
|
+
DependencyAnalyzer()
|
|
592
|
+
.analyze_project(path)
|
|
593
|
+
)
|
|
594
|
+
db_access_violations = (
|
|
595
|
+
DBAccessAnalyzer()
|
|
596
|
+
.analyze(dependencies)
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
architecture_violations = (
|
|
600
|
+
ArchitectureValidator()
|
|
601
|
+
.validate(dependencies)
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
circular_violations = (
|
|
605
|
+
CircularDependencyAnalyzer()
|
|
606
|
+
.detect(dependencies)
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
score = (
|
|
611
|
+
ArchitectureScoreCalculator()
|
|
612
|
+
.calculate(file_violations,function_violations,architecture_violations,circular_violations,db_access_violations
|
|
613
|
+
)
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
total_files = count_python_files(path)
|
|
617
|
+
|
|
618
|
+
reporter.show_summary(total_files,file_violations,function_violations,architecture_violations,circular_violations,db_access_violations,score
|
|
619
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ConfigLoader:
|
|
6
|
+
|
|
7
|
+
DEFAULT_CONFIG = {
|
|
8
|
+
|
|
9
|
+
"max_file_lines": 300,
|
|
10
|
+
|
|
11
|
+
"max_function_lines": 50,
|
|
12
|
+
"supported_extensions": [
|
|
13
|
+
".py",
|
|
14
|
+
".ts",
|
|
15
|
+
".js"
|
|
16
|
+
],
|
|
17
|
+
|
|
18
|
+
"ignored_directories": [
|
|
19
|
+
"venv",
|
|
20
|
+
".git",
|
|
21
|
+
"__pycache__",
|
|
22
|
+
".pytest_cache"
|
|
23
|
+
],
|
|
24
|
+
|
|
25
|
+
"forbidden_dependencies": [
|
|
26
|
+
[
|
|
27
|
+
"controllers",
|
|
28
|
+
"repositories"
|
|
29
|
+
]
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
"enable_circular_dependency_check": True,
|
|
33
|
+
|
|
34
|
+
"architecture_score": {
|
|
35
|
+
|
|
36
|
+
"file_penalty": 10,
|
|
37
|
+
|
|
38
|
+
"function_penalty": 5,
|
|
39
|
+
|
|
40
|
+
"architecture_penalty": 20,
|
|
41
|
+
|
|
42
|
+
"circular_dependency_penalty": 30
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def load(
|
|
48
|
+
cls,
|
|
49
|
+
config_path="codeguardian.json"
|
|
50
|
+
):
|
|
51
|
+
|
|
52
|
+
if not os.path.exists(config_path):
|
|
53
|
+
|
|
54
|
+
print(
|
|
55
|
+
"⚠ codeguardian.json not found."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
print(
|
|
59
|
+
"Using default configuration."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return cls.DEFAULT_CONFIG
|
|
63
|
+
|
|
64
|
+
with open(
|
|
65
|
+
config_path,
|
|
66
|
+
"r",
|
|
67
|
+
encoding="utf-8"
|
|
68
|
+
) as file:
|
|
69
|
+
|
|
70
|
+
user_config = json.load(file)
|
|
71
|
+
|
|
72
|
+
config = cls.DEFAULT_CONFIG.copy()
|
|
73
|
+
|
|
74
|
+
config.update(user_config)
|
|
75
|
+
|
|
76
|
+
return config
|
CODEGUARDIAN/main.py
ADDED
|
File without changes
|