Skip to content

Commit d9df059

Browse files
committed
refactor: split PR command helpers
Separate PR context loading, summary generation, and review posting flow so the command entrypoint reads as a small dispatcher. Made-with: Cursor
1 parent be568d1 commit d9df059

File tree

5 files changed

+136
-65
lines changed

5 files changed

+136
-65
lines changed

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
- [x] `src/commands/feedback_eval/types.rs`: separate input payload types from report/output types.
8282
- [x] `src/commands/feedback_eval/input/loading.rs`: split format detection from JSON parsing/loading.
8383
- [x] `src/commands/feedback_eval/input/conversion.rs`: split review-session conversion from label normalization helpers.
84-
- [ ] `src/commands/pr.rs`: separate summary-only flow, full review flow, and comment-posting orchestration.
84+
- [x] `src/commands/pr.rs`: separate summary-only flow, full review flow, and comment-posting orchestration.
8585
- [ ] `src/commands/pr/gh.rs`: carve PR resolution, diff fetching, and metadata fetching.
8686
- [ ] `src/commands/git/suggest.rs`: split commit-message prompting from PR-title prompting and response extraction.
8787
- [ ] `src/commands/review/command.rs`: split review/check/compare entrypoints if they keep diverging.

src/commands/pr.rs

Lines changed: 14 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
use anyhow::Result;
2-
use std::path::PathBuf;
32
use tracing::info;
43

54
#[path = "pr/comments.rs"]
65
mod comments;
6+
#[path = "pr/context.rs"]
7+
mod context;
78
#[path = "pr/gh.rs"]
89
mod gh;
10+
#[path = "pr/review_flow.rs"]
11+
mod review_flow;
12+
#[path = "pr/summary_flow.rs"]
13+
mod summary_flow;
914

10-
use crate::adapters;
1115
use crate::config;
12-
use crate::core;
1316
use crate::output::OutputFormat;
14-
use crate::review;
1517

16-
use comments::post_review_comments;
17-
use gh::{fetch_pr_diff, fetch_pr_metadata, resolve_pr_number};
18+
use context::prepare_pr_context;
19+
use review_flow::run_pr_review_flow;
20+
use summary_flow::run_pr_summary_flow;
1821

1922
pub async fn pr_command(
2023
number: Option<u32>,
@@ -24,72 +27,19 @@ pub async fn pr_command(
2427
config: config::Config,
2528
format: OutputFormat,
2629
) -> Result<()> {
27-
let pr_number = resolve_pr_number(number, repo.as_deref())?;
30+
let context = prepare_pr_context(number, repo.as_deref())?;
2831

29-
info!("Reviewing PR #{}", pr_number);
32+
info!("Reviewing PR #{}", context.pr_number);
3033

31-
let git = core::GitIntegration::new(".")?;
32-
let repo_root = git.workdir().unwrap_or_else(|| PathBuf::from("."));
33-
if let Ok(branch) = git.get_current_branch() {
34-
info!("Current branch: {}", branch);
35-
}
36-
if let Ok(Some(remote)) = git.get_remote_url() {
37-
info!("Remote URL: {}", remote);
38-
}
39-
40-
let diff_content = fetch_pr_diff(&pr_number, repo.as_deref())?;
41-
42-
if diff_content.is_empty() {
34+
if context.diff_content.is_empty() {
4335
println!("No changes in PR");
4436
return Ok(());
4537
}
4638

4739
if summary {
48-
let diffs = core::DiffParser::parse_unified_diff(&diff_content)?;
49-
let git = core::GitIntegration::new(".")?;
50-
51-
let fast_config = config.to_model_config_for_role(config::ModelRole::Fast);
52-
let adapter = adapters::llm::create_adapter(&fast_config)?;
53-
let options = core::SummaryOptions {
54-
include_diagram: config.smart_review_diagram,
55-
};
56-
let pr_summary = core::PRSummaryGenerator::generate_summary_with_options(
57-
&diffs,
58-
&git,
59-
adapter.as_ref(),
60-
options,
61-
)
62-
.await?;
63-
64-
println!("{}", pr_summary.to_markdown());
40+
run_pr_summary_flow(&config, &context.diff_content).await?;
6541
return Ok(());
6642
}
6743

68-
let review_result =
69-
review::review_diff_content_raw(&diff_content, config.clone(), &repo_root).await?;
70-
let comments = review_result.comments;
71-
72-
if post_comments {
73-
info!("Posting {} comments to PR", comments.len());
74-
let metadata = fetch_pr_metadata(&pr_number, repo.as_deref())?;
75-
let stats = post_review_comments(
76-
&pr_number,
77-
repo.as_deref(),
78-
&metadata,
79-
&comments,
80-
&config.rule_priority,
81-
)?;
82-
83-
println!(
84-
"Posted {} comments to PR #{} (inline: {}, fallback: {}, summary: updated)",
85-
comments.len(),
86-
pr_number,
87-
stats.inline_posted,
88-
stats.fallback_posted
89-
);
90-
} else {
91-
crate::output::output_comments(&comments, None, format, &config.rule_priority).await?;
92-
}
93-
94-
Ok(())
44+
run_pr_review_flow(&context, repo.as_deref(), post_comments, &config, format).await
9545
}

src/commands/pr/context.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use anyhow::Result;
2+
use std::path::PathBuf;
3+
use tracing::info;
4+
5+
use crate::core;
6+
7+
use super::gh::{fetch_pr_diff, resolve_pr_number};
8+
9+
pub(super) struct PrCommandContext {
10+
pub(super) pr_number: String,
11+
pub(super) repo_root: PathBuf,
12+
pub(super) diff_content: String,
13+
}
14+
15+
pub(super) fn prepare_pr_context(
16+
number: Option<u32>,
17+
repo: Option<&str>,
18+
) -> Result<PrCommandContext> {
19+
let pr_number = resolve_pr_number(number, repo)?;
20+
let git = core::GitIntegration::new(".")?;
21+
let repo_root = git.workdir().unwrap_or_else(|| PathBuf::from("."));
22+
23+
if let Ok(branch) = git.get_current_branch() {
24+
info!("Current branch: {}", branch);
25+
}
26+
if let Ok(Some(remote)) = git.get_remote_url() {
27+
info!("Remote URL: {}", remote);
28+
}
29+
30+
let diff_content = fetch_pr_diff(&pr_number, repo)?;
31+
32+
Ok(PrCommandContext {
33+
pr_number,
34+
repo_root,
35+
diff_content,
36+
})
37+
}

src/commands/pr/review_flow.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use anyhow::Result;
2+
use tracing::info;
3+
4+
use crate::config;
5+
use crate::output::OutputFormat;
6+
use crate::review;
7+
8+
use super::comments::post_review_comments;
9+
use super::context::PrCommandContext;
10+
use super::gh::fetch_pr_metadata;
11+
12+
pub(super) async fn run_pr_review_flow(
13+
context: &PrCommandContext,
14+
repo: Option<&str>,
15+
post_comments: bool,
16+
config: &config::Config,
17+
format: OutputFormat,
18+
) -> Result<()> {
19+
let review_result =
20+
review::review_diff_content_raw(&context.diff_content, config.clone(), &context.repo_root)
21+
.await?;
22+
let comments = review_result.comments;
23+
24+
if post_comments {
25+
post_pr_review_comments(context, repo, &comments, config)?;
26+
} else {
27+
crate::output::output_comments(&comments, None, format, &config.rule_priority).await?;
28+
}
29+
30+
Ok(())
31+
}
32+
33+
fn post_pr_review_comments(
34+
context: &PrCommandContext,
35+
repo: Option<&str>,
36+
comments: &[crate::core::Comment],
37+
config: &config::Config,
38+
) -> Result<()> {
39+
info!("Posting {} comments to PR", comments.len());
40+
let metadata = fetch_pr_metadata(&context.pr_number, repo)?;
41+
let stats = post_review_comments(
42+
&context.pr_number,
43+
repo,
44+
&metadata,
45+
comments,
46+
&config.rule_priority,
47+
)?;
48+
49+
println!(
50+
"Posted {} comments to PR #{} (inline: {}, fallback: {}, summary: updated)",
51+
comments.len(),
52+
context.pr_number,
53+
stats.inline_posted,
54+
stats.fallback_posted
55+
);
56+
57+
Ok(())
58+
}

src/commands/pr/summary_flow.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use anyhow::Result;
2+
3+
use crate::adapters;
4+
use crate::config;
5+
use crate::core;
6+
7+
pub(super) async fn run_pr_summary_flow(config: &config::Config, diff_content: &str) -> Result<()> {
8+
let diffs = core::DiffParser::parse_unified_diff(diff_content)?;
9+
let git = core::GitIntegration::new(".")?;
10+
11+
let fast_config = config.to_model_config_for_role(config::ModelRole::Fast);
12+
let adapter = adapters::llm::create_adapter(&fast_config)?;
13+
let options = core::SummaryOptions {
14+
include_diagram: config.smart_review_diagram,
15+
};
16+
let pr_summary = core::PRSummaryGenerator::generate_summary_with_options(
17+
&diffs,
18+
&git,
19+
adapter.as_ref(),
20+
options,
21+
)
22+
.await?;
23+
24+
println!("{}", pr_summary.to_markdown());
25+
Ok(())
26+
}

0 commit comments

Comments
 (0)