diff --git a/docs/images/tutorial-web-ui-project-form-repo-health-result.png b/docs/images/tutorial-web-ui-project-form-repo-health-result.png index 209a07fa13..874242c246 100644 Binary files a/docs/images/tutorial-web-ui-project-form-repo-health-result.png and b/docs/images/tutorial-web-ui-project-form-repo-health-result.png differ diff --git a/scanpipe/pipes/repo_health.py b/scanpipe/pipes/repo_health.py index 5b66c7ad36..b33dcfc176 100644 --- a/scanpipe/pipes/repo_health.py +++ b/scanpipe/pipes/repo_health.py @@ -129,24 +129,49 @@ def format_metrics_output(project, metrics_output_path): raise ValueError("Invalid metrics JSON: 'packages' contains no data.") target_package = packages[0] - repository = target_package.get("repository") - score = target_package.get("score") - metrics = target_package.get("metrics") + vcs_url = target_package.get("repository") + if not vcs_url: + raise ValueError("Invalid vcs_url: value cannot be empty") + + score_data = target_package.get("score") + score_meta = score_data.get("metadata") or {} + score = score_data.get("value") or 0.0 - if repository is None or score is None or metrics is None: + if 0 >= score <= 1: raise ValueError( - f"Invalid metrics JSON. missing or null field(s): " - f"repository: {repository}, score: {score}, metrics: {metrics}" + f"Invalid score value it should be between 0 and 1, score: {score}" ) + score = round(score, 2) + score = 1.0 - score + + score_ecosystem = score_meta.get("ecosystem") or "" + score_model = score_meta.get("model") or "" + score_version = score_meta.get("version") or "" + + scoring_model = f"{score_ecosystem}-{score_model}-{score_version}" + metrics = target_package.get("metrics") + + commit_range = target_package.get("metadata") + commit_range = dict(sorted(commit_range.items())) + + metrics = dict(sorted(metrics.items())) + metadata = data.get("metadata") + run_start_date = metadata.get("started_at") + run_end_date = metadata.get("finished_at") + result = { - "repository": repository, + "vcs_url": vcs_url, + "scoring_model": scoring_model, "score": score, + "commit_range": commit_range, + "run_start_date": run_start_date, + "run_end_date": run_end_date, "metrics": metrics, } with open(metrics_output_path, "w") as f: - json.dump(result, f) + json.dump(result, f, indent=2) project.update_extra_data(result) diff --git a/scanpipe/tests/data/grimorielab/expected-metrics.json b/scanpipe/tests/data/grimorielab/expected-metrics.json index f8b13b93d7..50ef724e9e 100644 --- a/scanpipe/tests/data/grimorielab/expected-metrics.json +++ b/scanpipe/tests/data/grimorielab/expected-metrics.json @@ -1,45 +1,47 @@ { - "repository": "https://github.com/baidu/san.git", - "score": { - "value": 0.027432660614030716, - "metadata": { - "ecosystem": "npm", - "model": "health", - "version": "0.1" - } + "vcs_url": "https://github.com/baidu/san.git", + "scoring_model": "npm-health-0.1", + "score": 0.97, + "commit_range": { + "first_commit": "82375f63b0404bd41bf27cdae26bed9a90aaaae2", + "first_commit_date": "2025-09-24T19:02:16+00:00", + "last_commit": "7818ad38bda7c48cd4a296ce8568f23ec1b1d400", + "last_commit_date": "2026-07-15T19:58:51+08:00" }, + "run_start_date": "2026-09-08T08:22:00.631055+00:00", + "run_end_date": "2026-09-08T08:22:02.586554+00:00", "metrics": { - "total_commits": 21, - "total_contributors": 5, - "total_organizations": 4, - "pony_factor": 1, - "elephant_factor": 1, - "recent_organizations": 4, - "recent_contributors": 5, - "recent_commits": 21, - "contributor_growth": -2, - "contributor_growth_rate": -0.5, "active_branches": 4, - "days_since_last_commit": 54, "casual_regular_contributors_rate": 0.6666666666666666, - "returning_contributors": 0, - "commits_over_periods_rate": 1.0, "coefficient_of_variation": 1.5459698172140883, - "file_types_code": 29, - "file_types_binary": 0, - "file_types_other": 14, "commit_size_added_lines": 7197, "commit_size_removed_lines": 4963, - "message_size_total": 2212, - "message_size_mean": 105.33333333333333, - "message_size_median": 21, - "developer_categories_core": 2, - "developer_categories_regular": 1, - "developer_categories_casual": 2, - "commits_per_week": 0.4027397260273972, + "commits_over_periods_rate": 1.0, "commits_per_month": 1.726027397260274, + "commits_per_week": 0.4027397260273972, "commits_per_year": 21.0, + "contributor_growth": -2, + "contributor_growth_rate": -0.5, + "days_since_last_commit": 54, + "developer_categories_casual": 2, + "developer_categories_core": 2, + "developer_categories_regular": 1, + "elephant_factor": 1, + "file_types_binary": 0, + "file_types_code": 29, + "file_types_other": 14, + "found_file_adopters": 0, "found_file_license": 1, - "found_file_adopters": 0 + "message_size_mean": 105.33333333333333, + "message_size_median": 21, + "message_size_total": 2212, + "pony_factor": 1, + "recent_commits": 21, + "recent_contributors": 5, + "recent_organizations": 4, + "returning_contributors": 0, + "total_commits": 21, + "total_contributors": 5, + "total_organizations": 4 } } \ No newline at end of file