codehealthanalyzer 1.2.2__tar.gz → 1.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codehealthanalyzer-1.2.2/codehealthanalyzer.egg-info → codehealthanalyzer-1.2.4}/PKG-INFO +1 -1
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/violations.py +3 -3
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/cli/main.py +165 -2
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/version.py +1 -1
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4/codehealthanalyzer.egg-info}/PKG-INFO +1 -1
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_cli.py +63 -3
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_cli_contract.py +1 -1
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_violations_analyzer.py +12 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/LICENSE +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/MANIFEST.in +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/README.md +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/README_EN.md +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/__init__.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/__main__.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/__init__.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/base.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/errors.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/templates.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/cli/__init__.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/config.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/exceptions.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/i18n.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/reports/__init__.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/reports/formatter.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/reports/generator.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/schemas.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/utils/__init__.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/utils/categorizer.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/utils/helpers.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/utils/validators.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/web/__init__.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/web/server.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/web/static/css/dashboard.css +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/web/static/js/dashboard.js +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/web/templates/dashboard.html +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/SOURCES.txt +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/dependency_links.txt +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/entry_points.txt +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/requires.txt +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/top_level.txt +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/example.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/locale/en/LC_MESSAGES/codehealthanalyzer.po +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/locale/pt_BR/LC_MESSAGES/codehealthanalyzer.po +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/pyproject.toml +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/requirements.txt +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/setup.cfg +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/setup.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_analyzers.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_base_analyzer.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_categorizer.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_config.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_contracts.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_dashboard.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_errors_analyzer.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_exceptions.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_helpers.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_quality_score.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_report_formatter.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_smoke.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_templates_analyzer.py +0 -0
- {codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/tests/test_validators.py +0 -0
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/violations.py
RENAMED
|
@@ -121,7 +121,7 @@ class ViolationsAnalyzer(BaseAnalyzer):
|
|
|
121
121
|
doc_lines = self._python_docstring_lines(tree)
|
|
122
122
|
count = 0
|
|
123
123
|
try:
|
|
124
|
-
with open(file_path, "r", encoding="utf-8") as fh:
|
|
124
|
+
with open(file_path, "r", encoding="utf-8-sig") as fh:
|
|
125
125
|
for idx, raw in enumerate(fh, 1):
|
|
126
126
|
stripped = raw.strip()
|
|
127
127
|
if not stripped or stripped.startswith("#"):
|
|
@@ -150,7 +150,7 @@ class ViolationsAnalyzer(BaseAnalyzer):
|
|
|
150
150
|
|
|
151
151
|
def _count_html_lines(self, file_path: Path) -> int:
|
|
152
152
|
try:
|
|
153
|
-
with open(file_path, "r", encoding="utf-8") as fh:
|
|
153
|
+
with open(file_path, "r", encoding="utf-8-sig") as fh:
|
|
154
154
|
return sum(1 for line in fh if line.strip())
|
|
155
155
|
except OSError as exc:
|
|
156
156
|
logger.warning("Falha ao ler template %s: %s", file_path, exc)
|
|
@@ -192,7 +192,7 @@ class ViolationsAnalyzer(BaseAnalyzer):
|
|
|
192
192
|
if file_path.suffix == ".py":
|
|
193
193
|
result["type"] = "Python"
|
|
194
194
|
try:
|
|
195
|
-
with open(file_path, "r", encoding="utf-8") as fh:
|
|
195
|
+
with open(file_path, "r", encoding="utf-8-sig") as fh:
|
|
196
196
|
source = fh.read()
|
|
197
197
|
tree = ast.parse(source, filename=str(file_path))
|
|
198
198
|
except (OSError, SyntaxError) as exc:
|
|
@@ -129,11 +129,31 @@ def _write_report_files(
|
|
|
129
129
|
base_name: str,
|
|
130
130
|
format_name: str,
|
|
131
131
|
no_json: bool,
|
|
132
|
+
detail: str = "full",
|
|
132
133
|
) -> None:
|
|
133
134
|
formatter = ReportFormatter()
|
|
134
135
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
136
|
+
|
|
135
137
|
if not no_json:
|
|
136
|
-
|
|
138
|
+
summary_report = _build_summary_report(report)
|
|
139
|
+
if detail == "summary":
|
|
140
|
+
formatter.to_json(summary_report, str(output_path / f"{base_name}.json"))
|
|
141
|
+
formatter.to_json(
|
|
142
|
+
summary_report, str(output_path / f"{base_name}.summary.json")
|
|
143
|
+
)
|
|
144
|
+
elif detail == "standard":
|
|
145
|
+
formatter.to_json(
|
|
146
|
+
_build_standard_report(report), str(output_path / f"{base_name}.json")
|
|
147
|
+
)
|
|
148
|
+
formatter.to_json(
|
|
149
|
+
summary_report, str(output_path / f"{base_name}.summary.json")
|
|
150
|
+
)
|
|
151
|
+
else:
|
|
152
|
+
formatter.to_json(report, str(output_path / f"{base_name}.json"))
|
|
153
|
+
formatter.to_json(report, str(output_path / f"{base_name}.full.json"))
|
|
154
|
+
formatter.to_json(
|
|
155
|
+
summary_report, str(output_path / f"{base_name}.summary.json")
|
|
156
|
+
)
|
|
137
157
|
if format_name in ["html", "all"]:
|
|
138
158
|
ReportGenerator().generate_html_report(
|
|
139
159
|
report, str(output_path / f"{base_name}.html")
|
|
@@ -144,6 +164,136 @@ def _write_report_files(
|
|
|
144
164
|
formatter.to_csv(report, str(output_path / f"{base_name}.csv"))
|
|
145
165
|
|
|
146
166
|
|
|
167
|
+
def _write_analyze_json_files(
|
|
168
|
+
report: FullReport,
|
|
169
|
+
output_path: Path,
|
|
170
|
+
detail: str,
|
|
171
|
+
) -> None:
|
|
172
|
+
formatter = ReportFormatter()
|
|
173
|
+
summary_report = _build_summary_report(report)
|
|
174
|
+
|
|
175
|
+
# Arquivos base amigaveis para consumo humano e integracoes simples.
|
|
176
|
+
formatter.to_json(summary_report, str(output_path / "summary_report.json"))
|
|
177
|
+
formatter.to_json(
|
|
178
|
+
report.get("violations", {}), str(output_path / "violations_report.json")
|
|
179
|
+
)
|
|
180
|
+
formatter.to_json(
|
|
181
|
+
report.get("templates", {}), str(output_path / "templates_report.json")
|
|
182
|
+
)
|
|
183
|
+
formatter.to_json(report.get("errors", {}), str(output_path / "errors_report.json"))
|
|
184
|
+
|
|
185
|
+
if detail in ["standard", "full"]:
|
|
186
|
+
formatter.to_json(
|
|
187
|
+
_build_standard_report(report), str(output_path / "analysis_report.json")
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Relatorio completo agora e opcional e so e gerado explicitamente.
|
|
191
|
+
if detail == "full":
|
|
192
|
+
formatter.to_json(report, str(output_path / "full_report.json"))
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _build_summary_report(report: FullReport, top_n: int = 10) -> dict[str, Any]:
|
|
196
|
+
violations = report.get("violations", {})
|
|
197
|
+
templates = report.get("templates", {})
|
|
198
|
+
errors = report.get("errors", {})
|
|
199
|
+
return {
|
|
200
|
+
"metadata": report.get("metadata", {}),
|
|
201
|
+
"summary": report.get("summary", {}),
|
|
202
|
+
"priorities": report.get("priorities", []),
|
|
203
|
+
"top_violations": (violations.get("violations", []) or [])[:top_n],
|
|
204
|
+
"top_warnings": (violations.get("warnings", []) or [])[:top_n],
|
|
205
|
+
"top_templates": (templates.get("templates", []) or [])[:top_n],
|
|
206
|
+
"top_errors": (errors.get("errors", []) or [])[:top_n],
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _standardize_violation_items(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
211
|
+
out: list[dict[str, Any]] = []
|
|
212
|
+
for item in items:
|
|
213
|
+
messages = item.get("violations", []) or []
|
|
214
|
+
out.append(
|
|
215
|
+
{
|
|
216
|
+
"file": item.get("file", ""),
|
|
217
|
+
"type": item.get("type", ""),
|
|
218
|
+
"lines": item.get("lines", 0),
|
|
219
|
+
"priority": item.get("priority", "low"),
|
|
220
|
+
"violation_count": len(messages),
|
|
221
|
+
"sample_violations": messages[:5],
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
return out
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _standardize_templates(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
228
|
+
out: list[dict[str, Any]] = []
|
|
229
|
+
for item in items:
|
|
230
|
+
out.append(
|
|
231
|
+
{
|
|
232
|
+
"file": item.get("file", ""),
|
|
233
|
+
"priority": item.get("priority", "low"),
|
|
234
|
+
"category": item.get("category", ""),
|
|
235
|
+
"total_css_chars": item.get("total_css_chars", item.get("css", 0)),
|
|
236
|
+
"total_js_chars": item.get("total_js_chars", item.get("js", 0)),
|
|
237
|
+
"css_inline_count": len(item.get("css_inline", []) or []),
|
|
238
|
+
"css_style_tags_count": len(item.get("css_style_tags", []) or []),
|
|
239
|
+
"js_inline_count": len(item.get("js_inline", []) or []),
|
|
240
|
+
"js_script_tags_count": len(item.get("js_script_tags", []) or []),
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
return out
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _standardize_errors(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
247
|
+
out: list[dict[str, Any]] = []
|
|
248
|
+
for item in items:
|
|
249
|
+
details = item.get("errors", []) or []
|
|
250
|
+
out.append(
|
|
251
|
+
{
|
|
252
|
+
"file": item.get("file", ""),
|
|
253
|
+
"priority": item.get("priority", "low"),
|
|
254
|
+
"category": item.get("category", ""),
|
|
255
|
+
"error_count": item.get("error_count", len(details)),
|
|
256
|
+
"sample_errors": details[:5],
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
return out
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _build_standard_report(report: FullReport) -> dict[str, Any]:
|
|
263
|
+
violations = report.get("violations", {})
|
|
264
|
+
templates = report.get("templates", {})
|
|
265
|
+
errors = report.get("errors", {})
|
|
266
|
+
|
|
267
|
+
# Compatibilidade com Python 3.8: evitar generics PEP585 em runtime dentro de cast().
|
|
268
|
+
violation_items = cast(list, violations.get("violations", []) or [])
|
|
269
|
+
warning_items = cast(list, violations.get("warnings", []) or [])
|
|
270
|
+
template_items = cast(list, templates.get("templates", []) or [])
|
|
271
|
+
error_items = cast(list, errors.get("errors", []) or [])
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
"metadata": report.get("metadata", {}),
|
|
275
|
+
"summary": report.get("summary", {}),
|
|
276
|
+
"quality_score": report.get("quality_score", 0),
|
|
277
|
+
"priorities": report.get("priorities", []),
|
|
278
|
+
"violations": {
|
|
279
|
+
"metadata": violations.get("metadata", {}),
|
|
280
|
+
"statistics": violations.get("statistics", {}),
|
|
281
|
+
"violations": _standardize_violation_items(violation_items),
|
|
282
|
+
"warnings": _standardize_violation_items(warning_items),
|
|
283
|
+
},
|
|
284
|
+
"templates": {
|
|
285
|
+
"metadata": templates.get("metadata", {}),
|
|
286
|
+
"statistics": templates.get("statistics", {}),
|
|
287
|
+
"templates": _standardize_templates(template_items),
|
|
288
|
+
},
|
|
289
|
+
"errors": {
|
|
290
|
+
"metadata": errors.get("metadata", {}),
|
|
291
|
+
"statistics": errors.get("statistics", {}),
|
|
292
|
+
"errors": _standardize_errors(error_items),
|
|
293
|
+
},
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
147
297
|
@click.group()
|
|
148
298
|
@click.version_option(version=__version__)
|
|
149
299
|
def cli():
|
|
@@ -177,6 +327,13 @@ def cli():
|
|
|
177
327
|
help="Formato do relatório (além do JSON padrão)",
|
|
178
328
|
)
|
|
179
329
|
@click.option("--no-json", is_flag=True, help="Não gerar o relatório JSON padrão")
|
|
330
|
+
@click.option(
|
|
331
|
+
"--detail",
|
|
332
|
+
type=click.Choice(["summary", "standard", "full"]),
|
|
333
|
+
default="standard",
|
|
334
|
+
show_default=True,
|
|
335
|
+
help="Nível de detalhe (full_report.json é gerado apenas em 'full')",
|
|
336
|
+
)
|
|
180
337
|
@click.option(
|
|
181
338
|
"--config", "-c", type=click.Path(exists=True), help="Arquivo de configuração JSON"
|
|
182
339
|
)
|
|
@@ -191,6 +348,7 @@ def analyze(
|
|
|
191
348
|
output: Optional[str],
|
|
192
349
|
format: str,
|
|
193
350
|
no_json: bool,
|
|
351
|
+
detail: str,
|
|
194
352
|
config: Optional[str],
|
|
195
353
|
no_default_excludes: bool,
|
|
196
354
|
verbose: bool,
|
|
@@ -274,7 +432,12 @@ def analyze(
|
|
|
274
432
|
|
|
275
433
|
# Diretório de saída padrão
|
|
276
434
|
output_path = Path(output or "reports")
|
|
277
|
-
|
|
435
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
436
|
+
if not no_json:
|
|
437
|
+
_write_analyze_json_files(report, output_path, detail)
|
|
438
|
+
_write_report_files(
|
|
439
|
+
report, output_path, "analysis_report", format, no_json=True, detail=detail
|
|
440
|
+
)
|
|
278
441
|
|
|
279
442
|
click.echo("\n" + ColorHelper.success("Análise concluída com sucesso!"))
|
|
280
443
|
|
|
@@ -60,7 +60,12 @@ def test_analyze_runs_on_valid_project(runner, project, tmp_path):
|
|
|
60
60
|
["analyze", str(project), "--output", str(out), "--no-default-excludes"],
|
|
61
61
|
)
|
|
62
62
|
assert result.exit_code == 0
|
|
63
|
-
assert (out / "
|
|
63
|
+
assert (out / "summary_report.json").exists()
|
|
64
|
+
assert (out / "analysis_report.json").exists()
|
|
65
|
+
assert (out / "violations_report.json").exists()
|
|
66
|
+
assert (out / "templates_report.json").exists()
|
|
67
|
+
assert (out / "errors_report.json").exists()
|
|
68
|
+
assert not (out / "full_report.json").exists()
|
|
64
69
|
|
|
65
70
|
|
|
66
71
|
def test_analyze_json_report_has_summary(runner, project, tmp_path):
|
|
@@ -70,7 +75,7 @@ def test_analyze_json_report_has_summary(runner, project, tmp_path):
|
|
|
70
75
|
cli,
|
|
71
76
|
["analyze", str(project), "--output", str(out), "--no-default-excludes"],
|
|
72
77
|
)
|
|
73
|
-
report = json.loads((out / "
|
|
78
|
+
report = json.loads((out / "summary_report.json").read_text(encoding="utf-8"))
|
|
74
79
|
assert "summary" in report
|
|
75
80
|
assert "quality_score" in report["summary"]
|
|
76
81
|
|
|
@@ -100,7 +105,7 @@ def test_analyze_markdown_format(runner, project, tmp_path):
|
|
|
100
105
|
"--no-default-excludes",
|
|
101
106
|
],
|
|
102
107
|
)
|
|
103
|
-
assert (out / "
|
|
108
|
+
assert (out / "analysis_report.md").exists()
|
|
104
109
|
|
|
105
110
|
|
|
106
111
|
def test_analyze_no_json_flag(runner, project, tmp_path):
|
|
@@ -117,7 +122,62 @@ def test_analyze_no_json_flag(runner, project, tmp_path):
|
|
|
117
122
|
"--no-default-excludes",
|
|
118
123
|
],
|
|
119
124
|
)
|
|
125
|
+
assert not (out / "summary_report.json").exists()
|
|
126
|
+
assert not (out / "analysis_report.json").exists()
|
|
127
|
+
assert not (out / "violations_report.json").exists()
|
|
128
|
+
assert not (out / "templates_report.json").exists()
|
|
129
|
+
assert not (out / "errors_report.json").exists()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_analyze_detail_summary_generates_summary_files(runner, project, tmp_path):
|
|
133
|
+
out = tmp_path / "out"
|
|
134
|
+
with patch("shutil.which", return_value=None):
|
|
135
|
+
runner.invoke(
|
|
136
|
+
cli,
|
|
137
|
+
[
|
|
138
|
+
"analyze",
|
|
139
|
+
str(project),
|
|
140
|
+
"--output",
|
|
141
|
+
str(out),
|
|
142
|
+
"--detail",
|
|
143
|
+
"summary",
|
|
144
|
+
"--no-default-excludes",
|
|
145
|
+
],
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
assert (out / "summary_report.json").exists()
|
|
149
|
+
assert (out / "violations_report.json").exists()
|
|
150
|
+
assert (out / "templates_report.json").exists()
|
|
151
|
+
assert (out / "errors_report.json").exists()
|
|
152
|
+
assert not (out / "analysis_report.json").exists()
|
|
120
153
|
assert not (out / "full_report.json").exists()
|
|
154
|
+
data = json.loads((out / "summary_report.json").read_text(encoding="utf-8"))
|
|
155
|
+
assert "summary" in data
|
|
156
|
+
assert "top_violations" in data
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_analyze_detail_full_generates_full_alias_file(runner, project, tmp_path):
|
|
160
|
+
out = tmp_path / "out"
|
|
161
|
+
with patch("shutil.which", return_value=None):
|
|
162
|
+
runner.invoke(
|
|
163
|
+
cli,
|
|
164
|
+
[
|
|
165
|
+
"analyze",
|
|
166
|
+
str(project),
|
|
167
|
+
"--output",
|
|
168
|
+
str(out),
|
|
169
|
+
"--detail",
|
|
170
|
+
"full",
|
|
171
|
+
"--no-default-excludes",
|
|
172
|
+
],
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
assert (out / "summary_report.json").exists()
|
|
176
|
+
assert (out / "analysis_report.json").exists()
|
|
177
|
+
assert (out / "violations_report.json").exists()
|
|
178
|
+
assert (out / "templates_report.json").exists()
|
|
179
|
+
assert (out / "errors_report.json").exists()
|
|
180
|
+
assert (out / "full_report.json").exists()
|
|
121
181
|
|
|
122
182
|
|
|
123
183
|
# ---------------------------------------------------------------------------
|
|
@@ -35,7 +35,7 @@ def test_cli_analyze_generates_json_report(tmp_path):
|
|
|
35
35
|
)
|
|
36
36
|
|
|
37
37
|
assert proc.returncode == 0
|
|
38
|
-
report_file = output_dir / "
|
|
38
|
+
report_file = output_dir / "summary_report.json"
|
|
39
39
|
assert report_file.exists()
|
|
40
40
|
report = json.loads(report_file.read_text(encoding="utf-8"))
|
|
41
41
|
assert "summary" in report
|
|
@@ -71,6 +71,18 @@ def test_check_file_python_syntax_error(tmp_path):
|
|
|
71
71
|
assert len(result["violations"]) > 0
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
def test_check_file_python_with_utf8_bom(tmp_path):
|
|
75
|
+
f = tmp_path / "bom_module.py"
|
|
76
|
+
f.write_text("x = 1\n", encoding="utf-8-sig")
|
|
77
|
+
|
|
78
|
+
result = _make(tmp_path, {"no_default_excludes": True}).check_file(f)
|
|
79
|
+
|
|
80
|
+
assert result["violations"] == []
|
|
81
|
+
assert result["priority"] == "low"
|
|
82
|
+
assert result["type"] == "Python"
|
|
83
|
+
assert result["lines"] == 1
|
|
84
|
+
|
|
85
|
+
|
|
74
86
|
# ---------------------------------------------------------------------------
|
|
75
87
|
# check_file — HTML
|
|
76
88
|
# ---------------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/errors.py
RENAMED
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/analyzers/templates.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/reports/__init__.py
RENAMED
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/reports/formatter.py
RENAMED
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/reports/generator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/utils/categorizer.py
RENAMED
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/utils/validators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer/web/static/js/dashboard.js
RENAMED
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/requires.txt
RENAMED
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/codehealthanalyzer.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/locale/en/LC_MESSAGES/codehealthanalyzer.po
RENAMED
|
File without changes
|
{codehealthanalyzer-1.2.2 → codehealthanalyzer-1.2.4}/locale/pt_BR/LC_MESSAGES/codehealthanalyzer.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|