Skip to content

Commit 99bc404

Browse files
committed
refactor: split smart review helpers
Move PR summary and diagram generation behind a dedicated helper so the smart review command flow stays easier to follow and extend. Made-with: Cursor
1 parent d95aab9 commit 99bc404

3 files changed

Lines changed: 138 additions & 115 deletions

File tree

src/commands/smart_review.rs

Lines changed: 5 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,6 @@
1-
use anyhow::Result;
2-
use std::path::PathBuf;
3-
use tracing::{info, warn};
1+
#[path = "smart_review/command.rs"]
2+
mod command;
3+
#[path = "smart_review/summary.rs"]
4+
mod summary;
45

5-
use crate::adapters;
6-
use crate::config;
7-
use crate::core;
8-
use crate::output::{build_change_walkthrough, format_smart_review_output};
9-
use crate::review;
10-
11-
pub async fn smart_review_command(
12-
config: config::Config,
13-
diff_path: Option<PathBuf>,
14-
output_path: Option<PathBuf>,
15-
) -> Result<()> {
16-
info!(
17-
"Starting smart review analysis with model: {}",
18-
config.model
19-
);
20-
21-
let (repo_root, diff_content) = super::review::load_review_input(diff_path).await?;
22-
if diff_content.trim().is_empty() {
23-
return Ok(());
24-
}
25-
26-
let diffs = core::DiffParser::parse_unified_diff(&diff_content)?;
27-
info!("Parsed {} file diffs", diffs.len());
28-
let walkthrough = build_change_walkthrough(&diffs);
29-
30-
let model_config = config.to_model_config();
31-
32-
let adapter = adapters::llm::create_adapter(&model_config)?;
33-
34-
// Use Fast model for PR summary and diagram generation (lightweight tasks).
35-
// Only create a separate adapter if model_fast differs from the primary model.
36-
let fast_config = config.to_model_config_for_role(config::ModelRole::Fast);
37-
let separate_fast_adapter: Option<Box<dyn adapters::llm::LLMAdapter>> =
38-
if fast_config.model_name != model_config.model_name {
39-
info!(
40-
"Using fast model '{}' for PR summary/diagram",
41-
fast_config.model_name
42-
);
43-
Some(adapters::llm::create_adapter(&fast_config)?)
44-
} else {
45-
None
46-
};
47-
let summary_adapter: &dyn adapters::llm::LLMAdapter =
48-
separate_fast_adapter.as_deref().unwrap_or(adapter.as_ref());
49-
50-
let mut pr_summary = if config.smart_review_summary {
51-
match core::GitIntegration::new(&repo_root) {
52-
Ok(git) => {
53-
let options = core::SummaryOptions {
54-
include_diagram: false,
55-
};
56-
match core::PRSummaryGenerator::generate_summary_with_options(
57-
&diffs,
58-
&git,
59-
summary_adapter,
60-
options,
61-
)
62-
.await
63-
{
64-
Ok(summary) => Some(summary),
65-
Err(err) => {
66-
warn!("PR summary generation failed: {}", err);
67-
None
68-
}
69-
}
70-
}
71-
Err(err) => {
72-
warn!("Skipping PR summary (git unavailable): {}", err);
73-
None
74-
}
75-
}
76-
} else {
77-
None
78-
};
79-
80-
if config.smart_review_diagram {
81-
match core::PRSummaryGenerator::generate_change_diagram(&diffs, summary_adapter).await {
82-
Ok(Some(diagram)) => {
83-
if let Some(summary) = &mut pr_summary {
84-
summary.visual_diff = Some(diagram);
85-
} else {
86-
pr_summary = Some(core::PRSummaryGenerator::build_diagram_only_summary(
87-
&diffs, diagram,
88-
));
89-
}
90-
}
91-
Ok(None) => {}
92-
Err(err) => warn!("Diagram generation failed: {}", err),
93-
}
94-
}
95-
let review_result =
96-
review::review_diff_content_raw(&diff_content, config.clone(), &repo_root).await?;
97-
let processed_comments = review_result.comments;
98-
99-
// Generate summary and output results
100-
let summary = core::CommentSynthesizer::generate_summary(&processed_comments);
101-
let output = format_smart_review_output(
102-
&processed_comments,
103-
&summary,
104-
pr_summary.as_ref(),
105-
&walkthrough,
106-
&config.rule_priority,
107-
);
108-
109-
if let Some(path) = output_path {
110-
tokio::fs::write(path, output).await?;
111-
} else {
112-
println!("{}", output);
113-
}
114-
115-
Ok(())
116-
}
6+
pub use command::smart_review_command;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use anyhow::Result;
2+
use std::path::PathBuf;
3+
use tracing::info;
4+
5+
use crate::adapters;
6+
use crate::config;
7+
use crate::core;
8+
use crate::output::{build_change_walkthrough, format_smart_review_output};
9+
use crate::review;
10+
11+
use super::summary::build_pr_summary;
12+
13+
pub async fn smart_review_command(
14+
config: config::Config,
15+
diff_path: Option<PathBuf>,
16+
output_path: Option<PathBuf>,
17+
) -> Result<()> {
18+
info!(
19+
"Starting smart review analysis with model: {}",
20+
config.model
21+
);
22+
23+
let (repo_root, diff_content) = super::super::review::load_review_input(diff_path).await?;
24+
if diff_content.trim().is_empty() {
25+
return Ok(());
26+
}
27+
28+
let diffs = core::DiffParser::parse_unified_diff(&diff_content)?;
29+
info!("Parsed {} file diffs", diffs.len());
30+
let walkthrough = build_change_walkthrough(&diffs);
31+
32+
let model_config = config.to_model_config();
33+
let adapter = adapters::llm::create_adapter(&model_config)?;
34+
let pr_summary = build_pr_summary(&config, &repo_root, &diffs, adapter.as_ref()).await?;
35+
36+
let review_result =
37+
review::review_diff_content_raw(&diff_content, config.clone(), &repo_root).await?;
38+
let processed_comments = review_result.comments;
39+
40+
let summary = core::CommentSynthesizer::generate_summary(&processed_comments);
41+
let output = format_smart_review_output(
42+
&processed_comments,
43+
&summary,
44+
pr_summary.as_ref(),
45+
&walkthrough,
46+
&config.rule_priority,
47+
);
48+
49+
if let Some(path) = output_path {
50+
tokio::fs::write(path, output).await?;
51+
} else {
52+
println!("{}", output);
53+
}
54+
55+
Ok(())
56+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use anyhow::Result;
2+
use std::path::Path;
3+
use tracing::{info, warn};
4+
5+
use crate::adapters;
6+
use crate::config;
7+
use crate::core;
8+
use crate::core::pr_summary::PRSummary;
9+
10+
pub(super) async fn build_pr_summary(
11+
config: &config::Config,
12+
repo_root: &Path,
13+
diffs: &[core::UnifiedDiff],
14+
primary_adapter: &dyn adapters::llm::LLMAdapter,
15+
) -> Result<Option<PRSummary>> {
16+
let model_config = config.to_model_config();
17+
let fast_config = config.to_model_config_for_role(config::ModelRole::Fast);
18+
let separate_fast_adapter: Option<Box<dyn adapters::llm::LLMAdapter>> =
19+
if fast_config.model_name != model_config.model_name {
20+
info!(
21+
"Using fast model '{}' for PR summary/diagram",
22+
fast_config.model_name
23+
);
24+
Some(adapters::llm::create_adapter(&fast_config)?)
25+
} else {
26+
None
27+
};
28+
let summary_adapter = separate_fast_adapter.as_deref().unwrap_or(primary_adapter);
29+
30+
let mut pr_summary = if config.smart_review_summary {
31+
match core::GitIntegration::new(repo_root) {
32+
Ok(git) => {
33+
let options = core::SummaryOptions {
34+
include_diagram: false,
35+
};
36+
match core::PRSummaryGenerator::generate_summary_with_options(
37+
diffs,
38+
&git,
39+
summary_adapter,
40+
options,
41+
)
42+
.await
43+
{
44+
Ok(summary) => Some(summary),
45+
Err(err) => {
46+
warn!("PR summary generation failed: {}", err);
47+
None
48+
}
49+
}
50+
}
51+
Err(err) => {
52+
warn!("Skipping PR summary (git unavailable): {}", err);
53+
None
54+
}
55+
}
56+
} else {
57+
None
58+
};
59+
60+
if config.smart_review_diagram {
61+
match core::PRSummaryGenerator::generate_change_diagram(diffs, summary_adapter).await {
62+
Ok(Some(diagram)) => {
63+
if let Some(summary) = &mut pr_summary {
64+
summary.visual_diff = Some(diagram);
65+
} else {
66+
pr_summary = Some(core::PRSummaryGenerator::build_diagram_only_summary(
67+
diffs, diagram,
68+
));
69+
}
70+
}
71+
Ok(None) => {}
72+
Err(err) => warn!("Diagram generation failed: {}", err),
73+
}
74+
}
75+
76+
Ok(pr_summary)
77+
}

0 commit comments

Comments
 (0)