codeboarding 0.14.3__tar.gz → 0.14.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.
- {codeboarding-0.14.3/codeboarding.egg-info → codeboarding-0.14.4}/PKG-INFO +1 -1
- {codeboarding-0.14.3 → codeboarding-0.14.4/codeboarding.egg-info}/PKG-INFO +1 -1
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/SOURCES.txt +1 -0
- codeboarding-0.14.4/health_main.py +152 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/pyproject.toml +1 -1
- codeboarding-0.14.4/static_analyzer/dotnet_solution.py +62 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/csharp_adapter.py +50 -13
- codeboarding-0.14.3/static_analyzer/dotnet_solution.py +0 -29
- {codeboarding-0.14.3 → codeboarding-0.14.4}/LICENSE +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/PYPI.md +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/README.md +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/agent_responses.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/change_status.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/component_ownership.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/constants.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/content_hash.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/file_index_models.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/incremental_results.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_config.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_errors.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_renderers/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_renderers/call_graph.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/llm_renderers/scope.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/model_capabilities.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/planner_agent.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/prompts/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/prompts/profiles.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/prompts/shared.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/relation_edges.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/retry.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/scope_analysis_agent.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/scope_ids.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tools/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tools/base.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tools/get_method_calls.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tools/read_file.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/agents/tree_planner_agent.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/clustering_ids.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/dependency_links.txt +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/entry_points.txt +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/requires.txt +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding.egg-info/top_level.txt +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/bootstrap.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/full_analysis.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/incremental_analysis.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/partial_analysis.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/render.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/view_instructions.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/analysis.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/orchestration.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/sources/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/sources/local.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_workflows/sources/remote.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/constants.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/core/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/core/plugin_loader.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/core/protocols.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/core/registry.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/analysis_json.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/diagram_generator.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/exceptions.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/file_coverage.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/file_index.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/incremental_changes.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/incremental_update.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/io_utils.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/run_context.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/run_mode.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/scope_assembly.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/scope_plan.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/diagram_analysis/tree_shape.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/github_action.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/health/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/health/checks/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/health/checks/circular_deps.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/health/checks/function_size.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/health/checks/unused_code_diagnostics.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/health/config.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/health/models.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/health/runner.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/install.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/logging_config.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/main.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/callbacks.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/context.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/mixin.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/paths.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/stats.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/monitoring/writers.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/html.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/html_template.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/markdown.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/mdx.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/rendering.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/output_generators/sphinx.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/change_detector.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/errors.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/fingerprint_diff.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/git_ops.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/ignore.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/repo_utils/path_utils.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/setup.cfg +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/analysis_cache.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/analysis_result.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cfg/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cfg/call_graph.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cfg/edge.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cfg/location_key.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/cluster_relations.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/exceptions.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/models.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/draft.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/frontier.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/inventory.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/replay.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/spec.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/names/tokens.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/clustering/service.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/config.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/csharp_config_scanner.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/dotnet_sdk.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/go_adapter.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/java_adapter.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/php_adapter.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/python_adapter.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/rust_adapter.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/typescript_adapter.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/call_graph_builder.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/edge_build_context.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/edge_builder.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/hierarchy_builder.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/language_adapter.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/lsp_client.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/lsp_constants.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/lsp_recycler.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/models.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/process_memory.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/progress.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/protocols.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/result_converter.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/source_inspector.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/symbol_table.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/utils.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/exceptions.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/external_calls.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/graph_definitions.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/incremental_orchestrator.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/internal_references.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/java_config_scanner.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/java_utils.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/language_results.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/lsp_client/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/lsp_client/diagnostics.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/node.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/programming_language.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/reference_resolver.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/scanner.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/typescript_config_scanner.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/device_id.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/events.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/schemas.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/telemetry/service.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_cli_parser.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_github_action.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_install.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_logging_config.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_main.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_persisted_analysis_artifacts.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_pyproject_packages.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_registry_coverage.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_telemetry_events.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_telemetry_service.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_tool_registry.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_user_config.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_view_instructions.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_vscode_constants.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_windows_compatibility.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tests/test_windows_encoding.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/__init__.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/installers.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/manifest.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/paths.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/tool_registry/registry.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/user_config.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/utils.py +0 -0
- {codeboarding-0.14.3 → codeboarding-0.14.4}/vscode_constants.py +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Standalone entry point for running health checks on a repository.
|
|
2
|
+
|
|
3
|
+
Runs static analysis and health checks only — no LLM agents or diagram generation.
|
|
4
|
+
Useful for testing health checks in isolation and for CI/CD health gates.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
# Local repository (output written to <repo>/.codeboarding/health/)
|
|
8
|
+
python health_main.py --local /path/to/repo
|
|
9
|
+
|
|
10
|
+
# Remote repository (cloned to cwd/repos/, output to cwd/<repo_name>/.codeboarding/health/)
|
|
11
|
+
python health_main.py https://github.com/user/repo
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import logging
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from health.runner import run_health_checks
|
|
19
|
+
from health.config import initialize_health_dir, load_health_config
|
|
20
|
+
from logging_config import setup_logging
|
|
21
|
+
from repo_utils import clone_repository, get_repo_name
|
|
22
|
+
from static_analyzer import get_static_analysis
|
|
23
|
+
from utils import CODEBOARDING_DIR_NAME, get_artifact_dir
|
|
24
|
+
from vscode_constants import update_config
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def run_health_check_local(
|
|
30
|
+
repo_path: Path,
|
|
31
|
+
project_name: str | None = None,
|
|
32
|
+
) -> None:
|
|
33
|
+
"""Run health checks on a local repository.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
repo_path: Path to a local repository
|
|
37
|
+
project_name: Optional project name (default: repo directory name)
|
|
38
|
+
"""
|
|
39
|
+
resolved_repo_path = repo_path.resolve()
|
|
40
|
+
if not resolved_repo_path.is_dir():
|
|
41
|
+
raise ValueError(f"Repository path does not exist: {resolved_repo_path}")
|
|
42
|
+
|
|
43
|
+
resolved_project_name = project_name or resolved_repo_path.name
|
|
44
|
+
output_dir = resolved_repo_path / CODEBOARDING_DIR_NAME
|
|
45
|
+
|
|
46
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
setup_logging(log_dir=output_dir)
|
|
48
|
+
|
|
49
|
+
_run_health_checks(resolved_repo_path, resolved_project_name, output_dir)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def run_health_check_remote(
|
|
53
|
+
repo_url: str,
|
|
54
|
+
project_name: str | None = None,
|
|
55
|
+
) -> None:
|
|
56
|
+
"""Run health checks on a remote repository.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
repo_url: URL of a remote Git repository
|
|
60
|
+
project_name: Optional project name (default: extracted from URL)
|
|
61
|
+
"""
|
|
62
|
+
repo_root = Path("repos")
|
|
63
|
+
repo_name = clone_repository(repo_url, repo_root)
|
|
64
|
+
resolved_repo_path = repo_root / repo_name
|
|
65
|
+
resolved_project_name = project_name or get_repo_name(repo_url)
|
|
66
|
+
output_dir = Path.cwd() / repo_name / CODEBOARDING_DIR_NAME
|
|
67
|
+
|
|
68
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
69
|
+
setup_logging(log_dir=output_dir)
|
|
70
|
+
|
|
71
|
+
_run_health_checks(resolved_repo_path, resolved_project_name, output_dir)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _run_health_checks(repo_path: Path, project_name: str, output_dir: Path) -> None:
|
|
75
|
+
"""Core health check logic shared by local and remote paths."""
|
|
76
|
+
logger.info(f"Running health checks on '{project_name}' at {repo_path}")
|
|
77
|
+
|
|
78
|
+
static_analysis = get_static_analysis(repo_path, cache_dir=get_artifact_dir(repo_path))
|
|
79
|
+
|
|
80
|
+
# Load health check configuration and initialize health config dir
|
|
81
|
+
health_config_dir = output_dir / "health"
|
|
82
|
+
initialize_health_dir(health_config_dir)
|
|
83
|
+
health_config = load_health_config(health_config_dir)
|
|
84
|
+
|
|
85
|
+
report = run_health_checks(static_analysis, project_name, config=health_config, repo_path=repo_path)
|
|
86
|
+
|
|
87
|
+
if report is None:
|
|
88
|
+
logger.warning("Health checks skipped: no languages found in static analysis results")
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
report_path = health_config_dir / "health_report.json"
|
|
92
|
+
report_path.write_text(report.model_dump_json(indent=2, exclude_none=True))
|
|
93
|
+
|
|
94
|
+
logger.info(f"Health report written to {report_path} (overall score: {report.overall_score:.3f})")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def main():
|
|
98
|
+
"""Main entry point that parses CLI arguments and routes to subcommands."""
|
|
99
|
+
parser = argparse.ArgumentParser(
|
|
100
|
+
description="Run static analysis health checks on a repository (local or remote)",
|
|
101
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
102
|
+
epilog="""
|
|
103
|
+
Examples:
|
|
104
|
+
# Local repository (output written to <repo>/.codeboarding/health/)
|
|
105
|
+
python health_main.py --local /path/to/repo
|
|
106
|
+
|
|
107
|
+
# Remote repository (cloned to cwd/repos/, output to cwd/<repo_name>/.codeboarding/health/)
|
|
108
|
+
python health_main.py https://github.com/user/repo
|
|
109
|
+
|
|
110
|
+
""",
|
|
111
|
+
)
|
|
112
|
+
parser.add_argument(
|
|
113
|
+
"repositories",
|
|
114
|
+
nargs="*",
|
|
115
|
+
help="One or more remote Git repository URLs to run health checks on",
|
|
116
|
+
)
|
|
117
|
+
parser.add_argument("--local", type=Path, help="Path to a local repository")
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"--project-name",
|
|
120
|
+
type=str,
|
|
121
|
+
default=None,
|
|
122
|
+
help="Name of the project (default: extracted from repo path or URL)",
|
|
123
|
+
)
|
|
124
|
+
parser.add_argument(
|
|
125
|
+
"--binary-location", type=Path, help="Path to the binary directory for language servers and tools"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
args = parser.parse_args()
|
|
129
|
+
|
|
130
|
+
# Validate: must provide either remote repos or --local, not both
|
|
131
|
+
has_remote = bool(args.repositories)
|
|
132
|
+
has_local = args.local is not None
|
|
133
|
+
|
|
134
|
+
if has_remote == has_local:
|
|
135
|
+
parser.error("Provide either one or more remote repositories or --local, but not both.")
|
|
136
|
+
|
|
137
|
+
# Resolve binary paths for tools (tokei, LSP servers, etc.)
|
|
138
|
+
if args.binary_location:
|
|
139
|
+
update_config(args.binary_location)
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
if has_local:
|
|
143
|
+
run_health_check_local(args.local, args.project_name)
|
|
144
|
+
else:
|
|
145
|
+
for repo_url in args.repositories:
|
|
146
|
+
run_health_check_remote(repo_url, args.project_name)
|
|
147
|
+
except ValueError as e:
|
|
148
|
+
parser.error(str(e))
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
main()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""The projects a .NET solution file lists."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
import xml.etree.ElementTree as ElementTree
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
PROJECT_SUFFIXES = (".csproj", ".fsproj")
|
|
10
|
+
# ``Project("{type guid}") = "Name", "relative\path.csproj", "{project guid}"``
|
|
11
|
+
_SLN_PROJECT_LINE = re.compile(r'^Project\("\{[^}]*\}"\)\s*=\s*"[^"]*",\s*"([^"]+)"', re.MULTILINE)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def solution_projects(solution: Path) -> list[Path]:
|
|
15
|
+
"""The project files a ``.sln`` or ``.slnx`` lists, absolute, in listing order.
|
|
16
|
+
|
|
17
|
+
Solution folders and files that do not exist are left out; a ``.sln`` names
|
|
18
|
+
its solution folders with the same ``Project(...)`` syntax as its projects.
|
|
19
|
+
"""
|
|
20
|
+
if solution.suffix.lower() == ".slnx":
|
|
21
|
+
listed = [element.get("Path") or "" for element in ElementTree.parse(solution).iter("Project")]
|
|
22
|
+
else:
|
|
23
|
+
listed = _SLN_PROJECT_LINE.findall(solution.read_text(encoding="utf-8-sig", errors="replace"))
|
|
24
|
+
projects: list[Path] = []
|
|
25
|
+
for raw in listed:
|
|
26
|
+
path = _project_file(solution.parent, raw)
|
|
27
|
+
if path is not None and path not in projects:
|
|
28
|
+
projects.append(path)
|
|
29
|
+
return projects
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def analyzer_project_references(projects: list[Path]) -> list[Path]:
|
|
33
|
+
"""The projects referenced with ``OutputItemType="Analyzer"``, absolute, in listing order.
|
|
34
|
+
|
|
35
|
+
Why: an analyzer reference resolves to the referenced project's output assembly, so
|
|
36
|
+
it stays unresolved until that project is built.
|
|
37
|
+
"""
|
|
38
|
+
analyzers: list[Path] = []
|
|
39
|
+
for project in projects:
|
|
40
|
+
try:
|
|
41
|
+
root = ElementTree.parse(project).getroot()
|
|
42
|
+
except (ElementTree.ParseError, OSError):
|
|
43
|
+
continue
|
|
44
|
+
for reference in root.iter():
|
|
45
|
+
# Legacy-format projects namespace every tag, so match on the local name.
|
|
46
|
+
if reference.tag.rpartition("}")[2] != "ProjectReference":
|
|
47
|
+
continue
|
|
48
|
+
if (reference.get("OutputItemType") or "").strip().lower() != "analyzer":
|
|
49
|
+
continue
|
|
50
|
+
raw = reference.get("Include") or ""
|
|
51
|
+
if not raw:
|
|
52
|
+
continue
|
|
53
|
+
path = _project_file(project.parent, raw)
|
|
54
|
+
if path is not None and path not in analyzers:
|
|
55
|
+
analyzers.append(path)
|
|
56
|
+
return analyzers
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _project_file(base: Path, raw: str) -> Path | None:
|
|
60
|
+
"""The project ``raw`` names relative to ``base``, or None if it is not one on disk."""
|
|
61
|
+
path = (base / raw.replace("\\", "/")).resolve()
|
|
62
|
+
return path if path.suffix.lower() in PROJECT_SUFFIXES and path.is_file() else None
|
{codeboarding-0.14.3 → codeboarding-0.14.4}/static_analyzer/engine/adapters/csharp_adapter.py
RENAMED
|
@@ -12,7 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from repo_utils.ignore import RepoIgnoreManager
|
|
13
13
|
from static_analyzer.config import Language, NodeType
|
|
14
14
|
from static_analyzer.dotnet_sdk import DotnetSdkError, resolve_dotnet_sdk, system_dotnet_env
|
|
15
|
-
from static_analyzer.dotnet_solution import solution_projects
|
|
15
|
+
from static_analyzer.dotnet_solution import analyzer_project_references, solution_projects
|
|
16
16
|
from static_analyzer.engine.language_adapter import LanguageAdapter
|
|
17
17
|
from static_analyzer.engine.lsp_client import LSPClient
|
|
18
18
|
from static_analyzer.engine.source_inspector import SourceInspector
|
|
@@ -29,6 +29,7 @@ from tool_registry import (
|
|
|
29
29
|
logger = logging.getLogger(__name__)
|
|
30
30
|
|
|
31
31
|
_MULTI_TARGET_PROJECT_THRESHOLD = 25
|
|
32
|
+
_DOTNET_TIMEOUT_SECONDS = 600
|
|
32
33
|
_SINGLE_TARGET_FRAMEWORK_TARGETS = r"""<Project>
|
|
33
34
|
<PropertyGroup Condition="'$(CodeBoardingOriginalDirectoryBuildTargetsPath)' == ''">
|
|
34
35
|
<CodeBoardingDirectoryBuildTargetsPath>$([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildProjectDirectory)'))</CodeBoardingDirectoryBuildTargetsPath>
|
|
@@ -47,6 +48,14 @@ _SINGLE_TARGET_FRAMEWORK_TARGETS = r"""<Project>
|
|
|
47
48
|
<TargetFrameworks>$([System.String]::Copy('$(CodeBoardingTargetFrameworks)').Trim(';').Split(';')[0])</TargetFrameworks>
|
|
48
49
|
<TargetFrameworks Condition="'$(CodeBoardingPreferredTargetFramework)' != '' and $(CodeBoardingTargetFrameworks.Contains(';$(CodeBoardingPreferredTargetFramework);'))">$(CodeBoardingPreferredTargetFramework)</TargetFrameworks>
|
|
49
50
|
</PropertyGroup>
|
|
51
|
+
<!-- An analyzer whose assembly is absent cannot run, but Roslyn keeps it as an
|
|
52
|
+
UnresolvedAnalyzerReference whose checksum throws, failing every
|
|
53
|
+
textDocument/implementation request in the solution. -->
|
|
54
|
+
<Target Name="CodeBoardingDropMissingAnalyzers" BeforeTargets="CoreCompile">
|
|
55
|
+
<ItemGroup>
|
|
56
|
+
<Analyzer Remove="@(Analyzer)" Condition="!Exists('%(Analyzer.FullPath)')" />
|
|
57
|
+
</ItemGroup>
|
|
58
|
+
</Target>
|
|
50
59
|
</Project>
|
|
51
60
|
"""
|
|
52
61
|
|
|
@@ -326,14 +335,15 @@ class CSharpAdapter(LanguageAdapter):
|
|
|
326
335
|
client.wait_for_diagnostics_quiesce(idle_seconds=2.0, max_wait=30.0)
|
|
327
336
|
|
|
328
337
|
def prepare_project(self, project_root: Path) -> None:
|
|
329
|
-
"""Run ``dotnet restore
|
|
338
|
+
"""Run ``dotnet restore``, then build any analyzer projects, so csharp-ls can
|
|
339
|
+
resolve framework references and analyzer assemblies.
|
|
330
340
|
|
|
331
341
|
Why: csharp-ls relies on Roslyn / MSBuild to load the project, and
|
|
332
342
|
MSBuild needs ``obj/project.assets.json`` (produced by restore) to
|
|
333
343
|
find the .NET runtime reference assemblies. Without it, csharp-ls
|
|
334
344
|
emits a flood of bogus ``CS0518: Predefined type System.X is not
|
|
335
|
-
defined`` diagnostics for every file. Restore is idempotent and
|
|
336
|
-
|
|
345
|
+
defined`` diagnostics for every file. Restore is idempotent and only writes
|
|
346
|
+
under ``obj/``; building an analyzer project also writes its ``bin/``.
|
|
337
347
|
|
|
338
348
|
Restore runs under the MSBuild environment csharp-ls gets, so the two
|
|
339
349
|
evaluate every path the same way and the server finds what restore wrote.
|
|
@@ -357,7 +367,12 @@ class CSharpAdapter(LanguageAdapter):
|
|
|
357
367
|
|
|
358
368
|
env = os.environ.copy()
|
|
359
369
|
env.update(self.get_lsp_env(project_root))
|
|
360
|
-
if
|
|
370
|
+
if target.suffix not in (".sln", ".slnx"):
|
|
371
|
+
self._dotnet("restore", resolution.dotnet_path, target, project_root, env)
|
|
372
|
+
self._build_analyzers(resolution.dotnet_path, [target], project_root, env)
|
|
373
|
+
return
|
|
374
|
+
if self._dotnet("restore", resolution.dotnet_path, target, project_root, env):
|
|
375
|
+
self._build_analyzers(resolution.dotnet_path, solution_projects(target), project_root, env)
|
|
361
376
|
return
|
|
362
377
|
# A solution restore evaluates every project before writing any assets, so one
|
|
363
378
|
# project it cannot evaluate (a missing workload, a broken import) leaves the
|
|
@@ -365,8 +380,11 @@ class CSharpAdapter(LanguageAdapter):
|
|
|
365
380
|
# or transitive project reference anywhere. Each member on its own only fails
|
|
366
381
|
# for itself.
|
|
367
382
|
projects = solution_projects(target)
|
|
368
|
-
restored = sum(
|
|
383
|
+
restored = sum(
|
|
384
|
+
self._dotnet("restore", resolution.dotnet_path, project, project_root, env) for project in projects
|
|
385
|
+
)
|
|
369
386
|
logger.info("dotnet restore per project: %d of %d restored", restored, len(projects))
|
|
387
|
+
self._build_analyzers(resolution.dotnet_path, projects, project_root, env)
|
|
370
388
|
|
|
371
389
|
def get_lsp_env(self, project_root: Path | None = None) -> dict[str, str]:
|
|
372
390
|
"""Return the .NET environment needed by csharp-ls.
|
|
@@ -411,29 +429,48 @@ class CSharpAdapter(LanguageAdapter):
|
|
|
411
429
|
found.append(sym.get("name", ""))
|
|
412
430
|
return found
|
|
413
431
|
|
|
414
|
-
def
|
|
432
|
+
def _build_analyzers(self, dotnet_path: str, projects: list[Path], project_root: Path, env: dict[str, str]) -> None:
|
|
433
|
+
"""Build the projects referenced as analyzers so Roslyn can resolve them.
|
|
434
|
+
|
|
435
|
+
Why: restore does not produce an output assembly, so Roslyn holds an
|
|
436
|
+
``UnresolvedAnalyzerReference`` whose checksum throws, failing every
|
|
437
|
+
``textDocument/implementation`` request across the whole solution.
|
|
438
|
+
"""
|
|
439
|
+
analyzers = analyzer_project_references(projects)
|
|
440
|
+
if not analyzers:
|
|
441
|
+
return
|
|
442
|
+
built = sum(self._dotnet("build", dotnet_path, analyzer, project_root, env) for analyzer in analyzers)
|
|
443
|
+
if built < len(analyzers):
|
|
444
|
+
# The injected target drops what stays missing, so analysis continues without
|
|
445
|
+
# the symbols that generator would have produced.
|
|
446
|
+
logger.warning("dotnet build analyzer projects: only %d of %d built", built, len(analyzers))
|
|
447
|
+
else:
|
|
448
|
+
logger.info("dotnet build analyzer projects: %d of %d built", built, len(analyzers))
|
|
449
|
+
|
|
450
|
+
def _dotnet(self, verb: str, dotnet_path: str, target: Path, project_root: Path, env: dict[str, str]) -> bool:
|
|
415
451
|
try:
|
|
416
452
|
result = subprocess.run(
|
|
417
|
-
[dotnet_path,
|
|
453
|
+
[dotnet_path, verb, os.path.relpath(target, project_root), "--nologo", "--verbosity", "minimal"],
|
|
418
454
|
cwd=str(project_root),
|
|
419
455
|
env=env,
|
|
420
456
|
capture_output=True,
|
|
421
457
|
text=True,
|
|
422
|
-
timeout=
|
|
458
|
+
timeout=_DOTNET_TIMEOUT_SECONDS,
|
|
423
459
|
)
|
|
424
460
|
except subprocess.TimeoutExpired:
|
|
425
|
-
logger.warning("dotnet
|
|
461
|
+
logger.warning("dotnet %s timed out after %ds for %s", verb, _DOTNET_TIMEOUT_SECONDS, target.name)
|
|
426
462
|
return False
|
|
427
463
|
except OSError as exc:
|
|
428
|
-
logger.warning("dotnet
|
|
464
|
+
logger.warning("dotnet %s could not be invoked: %s", verb, exc)
|
|
429
465
|
return False
|
|
430
466
|
if result.returncode != 0:
|
|
431
467
|
logger.warning(
|
|
432
|
-
"dotnet
|
|
468
|
+
"dotnet %s failed for %s (exit %d): %s",
|
|
469
|
+
verb,
|
|
433
470
|
target.name,
|
|
434
471
|
result.returncode,
|
|
435
472
|
(result.stderr or result.stdout)[-500:],
|
|
436
473
|
)
|
|
437
474
|
return False
|
|
438
|
-
logger.info("dotnet
|
|
475
|
+
logger.info("dotnet %s completed for %s", verb, target.name)
|
|
439
476
|
return True
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"""The projects a .NET solution file lists."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import re
|
|
6
|
-
import xml.etree.ElementTree as ElementTree
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
PROJECT_SUFFIXES = (".csproj", ".fsproj")
|
|
10
|
-
# ``Project("{type guid}") = "Name", "relative\path.csproj", "{project guid}"``
|
|
11
|
-
_SLN_PROJECT_LINE = re.compile(r'^Project\("\{[^}]*\}"\)\s*=\s*"[^"]*",\s*"([^"]+)"', re.MULTILINE)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def solution_projects(solution: Path) -> list[Path]:
|
|
15
|
-
"""The project files a ``.sln`` or ``.slnx`` lists, absolute, in listing order.
|
|
16
|
-
|
|
17
|
-
Solution folders and files that do not exist are left out; a ``.sln`` names
|
|
18
|
-
its solution folders with the same ``Project(...)`` syntax as its projects.
|
|
19
|
-
"""
|
|
20
|
-
if solution.suffix.lower() == ".slnx":
|
|
21
|
-
listed = [element.get("Path") or "" for element in ElementTree.parse(solution).iter("Project")]
|
|
22
|
-
else:
|
|
23
|
-
listed = _SLN_PROJECT_LINE.findall(solution.read_text(encoding="utf-8-sig", errors="replace"))
|
|
24
|
-
projects: list[Path] = []
|
|
25
|
-
for raw in listed:
|
|
26
|
-
path = (solution.parent / raw.replace("\\", "/")).resolve()
|
|
27
|
-
if path.suffix.lower() in PROJECT_SUFFIXES and path.is_file() and path not in projects:
|
|
28
|
-
projects.append(path)
|
|
29
|
-
return projects
|
|
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
|
|
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
|
|
File without changes
|
{codeboarding-0.14.3 → codeboarding-0.14.4}/codeboarding_cli/commands/incremental_analysis.py
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|