fallow_engine/
flag_report.rs1use std::path::Path;
9
10use fallow_config::WorkspaceInfo;
11use fallow_types::flag_retirement::{FlagAgeMode, FlagRetirementReport, RetirementFlagKind};
12use fallow_types::workspace::WorkspaceDiagnosticKind;
13use rustc_hash::FxHashSet;
14
15use crate::clock::AnalysisClock;
16use crate::flag_age::{FlagAgeRequest, PickaxeProgress, apply_flag_ages};
17use crate::flag_retirement::{
18 AGE_GATE_AGE_OFF, AGE_GATE_NO_HISTORY, RetirementOptions, RetirementSiteInput, aggregate_flags,
19 finish_report, max_age_gate,
20};
21use crate::flag_vendor::{VendorExport, VendorMatch, apply_vendor_state};
22
23pub struct RetirementRequest<'a> {
25 pub root: &'a Path,
27 pub workspaces: &'a [WorkspaceInfo],
29 pub sites: Vec<RetirementSiteInput>,
31 pub in_scope: &'a dyn Fn(&Path) -> bool,
33 pub whole_project: bool,
36 pub age_mode: FlagAgeMode,
38 pub cache_dir: Option<&'a Path>,
40 pub progress: Option<&'a (dyn Fn(PickaxeProgress) + Sync)>,
42 pub vendor_export: Option<&'a VendorExport>,
44 pub vendor_key_prefix: Option<&'a str>,
46 pub max_flag_age: Option<u64>,
48 pub options: RetirementOptions,
50}
51
52pub struct RetirementBuild {
54 pub report: FlagRetirementReport,
56 pub diagnostics: Vec<WorkspaceDiagnosticKind>,
58}
59
60#[must_use]
62pub fn build_retirement_report(request: RetirementRequest<'_>) -> RetirementBuild {
63 let root = request.root;
64 let code_flag_names: FxHashSet<String> = request
65 .sites
66 .iter()
67 .map(|site| site.flag_name.clone())
68 .collect();
69 let project_sdk_labels: FxHashSet<String> = request
70 .sites
71 .iter()
72 .filter(|site| site.kind == RetirementFlagKind::SdkCall)
73 .filter_map(|site| site.sdk_name.clone())
74 .collect();
75 let mut rows = aggregate_flags(request.sites, root, request.workspaces, request.in_scope);
76 let age = apply_flag_ages(
77 &mut rows,
78 &FlagAgeRequest {
79 root,
80 mode: request.age_mode,
81 cache_dir: request.cache_dir,
82 progress: request.progress,
83 },
84 );
85 let vendor_state = request.vendor_export.map(|export| {
86 apply_vendor_state(
87 &mut rows,
88 &VendorMatch {
89 export,
90 key_prefix: request.vendor_key_prefix,
91 code_flag_names: &code_flag_names,
92 project_sdk_labels: &project_sdk_labels,
93 add_vendor_only: request.whole_project,
94 clock_epoch_secs: AnalysisClock::for_repo(root).epoch_secs(),
95 },
96 )
97 });
98 let skip_reason = if request.age_mode == FlagAgeMode::Off {
99 Some(AGE_GATE_AGE_OFF)
100 } else if age.generated_at_clock.is_none() {
101 Some(AGE_GATE_NO_HISTORY)
102 } else {
103 None
104 };
105 let max_flag_age = request
106 .max_flag_age
107 .map(|days| max_age_gate(&rows, days, skip_reason));
108 let mut report = finish_report(
109 rows,
110 request.age_mode,
111 age.generated_at_clock,
112 &request.options,
113 );
114 report.vendor_state = vendor_state;
115 report.max_flag_age = max_flag_age;
116 RetirementBuild {
117 report,
118 diagnostics: age.diagnostics,
119 }
120}