Skip to content

Commit ab12622

Browse files
committed
refactor: split eval command helpers
Separate fixture execution, threshold option preparation, and report emission so the eval command flow stays small and easier to extend. Made-with: Cursor
1 parent 05c4944 commit ab12622

File tree

5 files changed

+104
-47
lines changed

5 files changed

+104
-47
lines changed

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
- [ ] `src/commands/misc/discussion/command.rs`: separate the interactive loop from single-shot execution.
9191
- [ ] `src/commands/misc/discussion/selection.rs`: split file loading/ID repair from selection rules.
9292
- [ ] `src/commands/misc/changelog.rs`: evaluate splitting changelog collection from output formatting.
93-
- [ ] `src/commands/eval/command.rs`: separate CLI option prep, fixture execution, and report lifecycle.
93+
- [x] `src/commands/eval/command.rs`: separate CLI option prep, fixture execution, and report lifecycle.
9494
- [x] `src/commands/feedback_eval/command.rs`: separate input loading from report/output orchestration.
9595

9696
### Review pipeline backlog

src/commands/eval/command.rs

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,27 @@
1+
#[path = "command/fixtures.rs"]
2+
mod fixtures;
3+
#[path = "command/options.rs"]
4+
mod options;
5+
#[path = "command/report.rs"]
6+
mod report;
7+
18
use anyhow::Result;
29
use std::path::PathBuf;
310

411
use crate::config;
512

6-
use super::fixtures::{collect_eval_fixtures, load_eval_report};
7-
use super::report::{
8-
build_eval_report, evaluation_failure_message, print_eval_report, write_eval_report,
9-
};
10-
use super::runner::run_eval_fixture;
11-
use super::thresholds::{parse_rule_threshold_args, EvalThresholdOptions};
1213
use super::EvalRunOptions;
14+
use fixtures::run_eval_fixtures;
15+
use options::prepare_eval_options;
16+
use report::emit_eval_report;
1317

1418
pub async fn eval_command(
1519
config: config::Config,
1620
fixtures_dir: PathBuf,
1721
output_path: Option<PathBuf>,
1822
options: EvalRunOptions,
1923
) -> Result<()> {
20-
let fixtures = collect_eval_fixtures(&fixtures_dir)?;
21-
if fixtures.is_empty() {
22-
anyhow::bail!(
23-
"No fixture files found in {} (expected .json/.yml/.yaml)",
24-
fixtures_dir.display()
25-
);
26-
}
27-
28-
let mut results = Vec::new();
29-
for fixture in fixtures {
30-
results.push(run_eval_fixture(&config, fixture).await?);
31-
}
32-
33-
let baseline = match options.baseline_report.as_deref() {
34-
Some(path) => Some(load_eval_report(path)?),
35-
None => None,
36-
};
37-
let min_rule_thresholds = parse_rule_threshold_args(&options.min_rule_f1, "min-rule-f1")?;
38-
let max_rule_drop_thresholds =
39-
parse_rule_threshold_args(&options.max_rule_f1_drop, "max-rule-f1-drop")?;
40-
let threshold_options = EvalThresholdOptions {
41-
max_micro_f1_drop: options.max_micro_f1_drop,
42-
min_micro_f1: options.min_micro_f1,
43-
min_macro_f1: options.min_macro_f1,
44-
min_rule_f1: min_rule_thresholds,
45-
max_rule_f1_drop: max_rule_drop_thresholds,
46-
};
47-
48-
let report = build_eval_report(results, baseline.as_ref(), &threshold_options);
49-
print_eval_report(&report);
50-
51-
if let Some(path) = output_path.as_deref() {
52-
write_eval_report(&report, path).await?;
53-
}
54-
55-
if let Some(message) = evaluation_failure_message(&report) {
56-
anyhow::bail!("{}", message);
57-
}
58-
59-
Ok(())
24+
let results = run_eval_fixtures(&config, &fixtures_dir).await?;
25+
let prepared_options = prepare_eval_options(&options)?;
26+
emit_eval_report(results, output_path.as_deref(), prepared_options).await
6027
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use anyhow::Result;
2+
use std::path::Path;
3+
4+
use crate::config;
5+
6+
use super::super::fixtures::collect_eval_fixtures;
7+
use super::super::runner::run_eval_fixture;
8+
use super::super::EvalFixtureResult;
9+
10+
pub(super) async fn run_eval_fixtures(
11+
config: &config::Config,
12+
fixtures_dir: &Path,
13+
) -> Result<Vec<EvalFixtureResult>> {
14+
let fixtures = collect_eval_fixtures(fixtures_dir)?;
15+
if fixtures.is_empty() {
16+
anyhow::bail!(
17+
"No fixture files found in {} (expected .json/.yml/.yaml)",
18+
fixtures_dir.display()
19+
);
20+
}
21+
22+
let mut results = Vec::new();
23+
for fixture in fixtures {
24+
results.push(run_eval_fixture(config, fixture).await?);
25+
}
26+
27+
Ok(results)
28+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use anyhow::Result;
2+
3+
use super::super::fixtures::load_eval_report;
4+
use super::super::thresholds::{parse_rule_threshold_args, EvalThresholdOptions};
5+
use super::super::{EvalReport, EvalRunOptions};
6+
7+
pub(super) struct PreparedEvalOptions {
8+
pub(super) baseline: Option<EvalReport>,
9+
pub(super) threshold_options: EvalThresholdOptions,
10+
}
11+
12+
pub(super) fn prepare_eval_options(options: &EvalRunOptions) -> Result<PreparedEvalOptions> {
13+
let baseline = match options.baseline_report.as_deref() {
14+
Some(path) => Some(load_eval_report(path)?),
15+
None => None,
16+
};
17+
let min_rule_thresholds = parse_rule_threshold_args(&options.min_rule_f1, "min-rule-f1")?;
18+
let max_rule_drop_thresholds =
19+
parse_rule_threshold_args(&options.max_rule_f1_drop, "max-rule-f1-drop")?;
20+
21+
Ok(PreparedEvalOptions {
22+
baseline,
23+
threshold_options: EvalThresholdOptions {
24+
max_micro_f1_drop: options.max_micro_f1_drop,
25+
min_micro_f1: options.min_micro_f1,
26+
min_macro_f1: options.min_macro_f1,
27+
min_rule_f1: min_rule_thresholds,
28+
max_rule_f1_drop: max_rule_drop_thresholds,
29+
},
30+
})
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use anyhow::Result;
2+
use std::path::Path;
3+
4+
use super::super::report::{
5+
build_eval_report, evaluation_failure_message, print_eval_report, write_eval_report,
6+
};
7+
use super::super::EvalFixtureResult;
8+
use super::options::PreparedEvalOptions;
9+
10+
pub(super) async fn emit_eval_report(
11+
results: Vec<EvalFixtureResult>,
12+
output_path: Option<&Path>,
13+
prepared_options: PreparedEvalOptions,
14+
) -> Result<()> {
15+
let report = build_eval_report(
16+
results,
17+
prepared_options.baseline.as_ref(),
18+
&prepared_options.threshold_options,
19+
);
20+
print_eval_report(&report);
21+
22+
if let Some(path) = output_path {
23+
write_eval_report(&report, path).await?;
24+
}
25+
26+
if let Some(message) = evaluation_failure_message(&report) {
27+
anyhow::bail!("{}", message);
28+
}
29+
30+
Ok(())
31+
}

0 commit comments

Comments
 (0)