use std::path::{Path, PathBuf};
use rustc_hash::FxHashSet;
use crate::baseline::{HealthBaselineData, filter_new_runtime_coverage_findings};
pub(super) struct RuntimeCoverageFilterContext<'a> {
pub baseline: Option<&'a HealthBaselineData>,
pub root: &'a Path,
pub top: Option<usize>,
pub changed_files: Option<&'a FxHashSet<PathBuf>>,
pub diff_index: Option<&'a crate::report::ci::diff_filter::DiffIndex>,
}
impl<'a> RuntimeCoverageFilterContext<'a> {
pub(super) fn new(root: &'a Path) -> Self {
Self {
baseline: None,
root,
top: None,
changed_files: None,
diff_index: None,
}
}
pub(super) fn with_baseline(mut self, baseline: Option<&'a HealthBaselineData>) -> Self {
self.baseline = baseline;
self
}
pub(super) fn with_top(mut self, top: Option<usize>) -> Self {
self.top = top;
self
}
pub(super) fn with_changed_files(
mut self,
changed_files: Option<&'a FxHashSet<PathBuf>>,
) -> Self {
self.changed_files = changed_files;
self
}
pub(super) fn with_diff_index(
mut self,
diff_index: Option<&'a crate::report::ci::diff_filter::DiffIndex>,
) -> Self {
self.diff_index = diff_index;
self
}
fn has_change_scope(&self) -> bool {
self.diff_index.is_some() || self.changed_files.is_some()
}
}
pub(super) fn apply_runtime_coverage_filters(
report: &mut crate::health_types::RuntimeCoverageReport,
ctx: &RuntimeCoverageFilterContext<'_>,
) {
if let Some(baseline) = ctx.baseline {
report.findings = filter_new_runtime_coverage_findings(
std::mem::take(&mut report.findings),
baseline,
ctx.root,
);
}
let changed_review = retain_hot_paths_in_change_scope(report, ctx);
refresh_runtime_coverage_verdict(report, changed_review);
if let Some(top) = ctx.top {
report.findings.truncate(top);
report.hot_paths.truncate(top);
}
}
fn retain_hot_paths_in_change_scope(
report: &mut crate::health_types::RuntimeCoverageReport,
ctx: &RuntimeCoverageFilterContext<'_>,
) -> bool {
if !ctx.has_change_scope() {
return false;
}
report.hot_paths.retain(|hot_path| {
if let Some(diff_index) = ctx.diff_index
&& let Some(rel) = relative_to_root(&hot_path.path, ctx.root)
&& diff_index.touches_file(&rel)
{
let Some(added) = diff_index.added_lines_in(&rel) else {
return false;
};
let start = u64::from(hot_path.line);
let end = if hot_path.end_line == 0 {
start
} else {
u64::from(hot_path.end_line)
};
return added.iter().any(|&line| line >= start && line <= end);
}
if let Some(changed_files) = ctx.changed_files {
let absolute = if crate::path_util::is_absolute_path_any_platform(&hot_path.path) {
hot_path.path.clone()
} else {
ctx.root.join(&hot_path.path)
};
return changed_files.contains(&absolute) || changed_files.contains(&hot_path.path);
}
false
});
true
}
pub(super) fn relative_to_root(path: &Path, root: &Path) -> Option<String> {
if let Ok(stripped) = path.strip_prefix(root) {
return Some(stripped.to_string_lossy().replace('\\', "/"));
}
if crate::path_util::is_absolute_path_any_platform(path) {
return None;
}
Some(path.to_string_lossy().replace('\\', "/"))
}
fn refresh_runtime_coverage_verdict(
report: &mut crate::health_types::RuntimeCoverageReport,
pr_context: bool,
) {
let has_cold_signal = report.findings.iter().any(|finding| {
matches!(
finding.verdict,
crate::health_types::RuntimeCoverageVerdict::SafeToDelete
| crate::health_types::RuntimeCoverageVerdict::ReviewRequired
| crate::health_types::RuntimeCoverageVerdict::LowTraffic
)
});
let has_changed_hot_path = pr_context && !report.hot_paths.is_empty();
let has_license_grace = matches!(
report.verdict,
crate::health_types::RuntimeCoverageReportVerdict::LicenseExpiredGrace
) || matches!(
report.watermark,
Some(crate::health_types::RuntimeCoverageWatermark::LicenseExpiredGrace)
);
report.signals =
build_runtime_coverage_signals(has_license_grace, has_cold_signal, has_changed_hot_path);
report.verdict = pick_primary_verdict(
has_license_grace,
has_cold_signal,
has_changed_hot_path,
pr_context,
);
}
fn build_runtime_coverage_signals(
has_license_grace: bool,
has_cold_signal: bool,
has_changed_hot_path: bool,
) -> Vec<crate::health_types::RuntimeCoverageSignal> {
let mut signals = Vec::new();
if has_license_grace {
signals.push(crate::health_types::RuntimeCoverageSignal::LicenseExpiredGrace);
}
if has_cold_signal {
signals.push(crate::health_types::RuntimeCoverageSignal::ColdCodeDetected);
}
if has_changed_hot_path {
signals.push(crate::health_types::RuntimeCoverageSignal::HotPathTouched);
}
signals
}
fn pick_primary_verdict(
has_license_grace: bool,
has_cold_signal: bool,
has_changed_hot_path: bool,
pr_context: bool,
) -> crate::health_types::RuntimeCoverageReportVerdict {
if has_license_grace {
return crate::health_types::RuntimeCoverageReportVerdict::LicenseExpiredGrace;
}
if pr_context {
if has_changed_hot_path {
return crate::health_types::RuntimeCoverageReportVerdict::HotPathTouched;
}
if has_cold_signal {
return crate::health_types::RuntimeCoverageReportVerdict::ColdCodeDetected;
}
} else {
if has_cold_signal {
return crate::health_types::RuntimeCoverageReportVerdict::ColdCodeDetected;
}
if has_changed_hot_path {
return crate::health_types::RuntimeCoverageReportVerdict::HotPathTouched;
}
}
crate::health_types::RuntimeCoverageReportVerdict::Clean
}