Skip to content

Commit a875aef

Browse files
committed
refactor: split PR GitHub helpers
Separate PR number resolution, diff fetching, and metadata loading so GitHub CLI integrations can evolve independently. Made-with: Cursor
1 parent d9df059 commit a875aef

File tree

5 files changed

+108
-87
lines changed

5 files changed

+108
-87
lines changed

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
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.
8484
- [x] `src/commands/pr.rs`: separate summary-only flow, full review flow, and comment-posting orchestration.
85-
- [ ] `src/commands/pr/gh.rs`: carve PR resolution, diff fetching, and metadata fetching.
85+
- [x] `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.
8888
- [ ] `src/commands/misc/feedback/command.rs`: separate file loading/ID normalization from store persistence.

src/commands/pr/gh.rs

Lines changed: 10 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,10 @@
1-
use anyhow::Result;
2-
use serde::Deserialize;
3-
use std::process::Command;
4-
5-
#[derive(Debug, Deserialize)]
6-
pub(super) struct GhPrMetadata {
7-
#[serde(rename = "headRefOid")]
8-
pub(super) head_ref_oid: String,
9-
#[serde(rename = "baseRepository")]
10-
pub(super) base_repository: GhBaseRepository,
11-
}
12-
13-
#[derive(Debug, Deserialize)]
14-
pub(super) struct GhBaseRepository {
15-
#[serde(rename = "nameWithOwner")]
16-
pub(super) name_with_owner: String,
17-
}
18-
19-
pub(super) fn resolve_pr_number(number: Option<u32>, repo: Option<&str>) -> Result<String> {
20-
if let Some(num) = number {
21-
return Ok(num.to_string());
22-
}
23-
24-
let mut args = vec![
25-
"pr".to_string(),
26-
"view".to_string(),
27-
"--json".to_string(),
28-
"number".to_string(),
29-
"-q".to_string(),
30-
".number".to_string(),
31-
];
32-
if let Some(repo) = repo {
33-
args.push("--repo".to_string());
34-
args.push(repo.to_string());
35-
}
36-
37-
let output = Command::new("gh").args(&args).output()?;
38-
if !output.status.success() {
39-
let stderr = String::from_utf8_lossy(&output.stderr);
40-
anyhow::bail!("gh pr view failed: {}", stderr.trim());
41-
}
42-
43-
let pr_number = String::from_utf8(output.stdout)?.trim().to_string();
44-
if pr_number.is_empty() {
45-
anyhow::bail!("Unable to determine PR number from gh output");
46-
}
47-
Ok(pr_number)
48-
}
49-
50-
pub(super) fn fetch_pr_diff(pr_number: &str, repo: Option<&str>) -> Result<String> {
51-
let mut diff_args = vec!["pr".to_string(), "diff".to_string(), pr_number.to_string()];
52-
if let Some(repo) = repo {
53-
diff_args.push("--repo".to_string());
54-
diff_args.push(repo.to_string());
55-
}
56-
let diff_output = Command::new("gh").args(&diff_args).output()?;
57-
if !diff_output.status.success() {
58-
let stderr = String::from_utf8_lossy(&diff_output.stderr);
59-
anyhow::bail!("gh pr diff failed: {}", stderr.trim());
60-
}
61-
62-
Ok(String::from_utf8(diff_output.stdout)?)
63-
}
64-
65-
pub(super) fn fetch_pr_metadata(pr_number: &str, repo: Option<&str>) -> Result<GhPrMetadata> {
66-
let mut args = vec![
67-
"pr".to_string(),
68-
"view".to_string(),
69-
pr_number.to_string(),
70-
"--json".to_string(),
71-
"headRefOid,baseRepository".to_string(),
72-
];
73-
if let Some(repo) = repo {
74-
args.push("--repo".to_string());
75-
args.push(repo.to_string());
76-
}
77-
78-
let output = Command::new("gh").args(&args).output()?;
79-
if !output.status.success() {
80-
let stderr = String::from_utf8_lossy(&output.stderr);
81-
anyhow::bail!("gh pr view metadata failed: {}", stderr.trim());
82-
}
83-
84-
let metadata: GhPrMetadata = serde_json::from_slice(&output.stdout)?;
85-
Ok(metadata)
86-
}
1+
#[path = "gh/diff.rs"]
2+
mod diff;
3+
#[path = "gh/metadata.rs"]
4+
mod metadata;
5+
#[path = "gh/resolve.rs"]
6+
mod resolve;
7+
8+
pub(super) use diff::fetch_pr_diff;
9+
pub(super) use metadata::{fetch_pr_metadata, GhPrMetadata};
10+
pub(super) use resolve::resolve_pr_number;

src/commands/pr/gh/diff.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use anyhow::Result;
2+
use std::process::Command;
3+
4+
pub(in super::super) fn fetch_pr_diff(pr_number: &str, repo: Option<&str>) -> Result<String> {
5+
let mut diff_args = vec!["pr".to_string(), "diff".to_string(), pr_number.to_string()];
6+
if let Some(repo) = repo {
7+
diff_args.push("--repo".to_string());
8+
diff_args.push(repo.to_string());
9+
}
10+
11+
let diff_output = Command::new("gh").args(&diff_args).output()?;
12+
if !diff_output.status.success() {
13+
let stderr = String::from_utf8_lossy(&diff_output.stderr);
14+
anyhow::bail!("gh pr diff failed: {}", stderr.trim());
15+
}
16+
17+
Ok(String::from_utf8(diff_output.stdout)?)
18+
}

src/commands/pr/gh/metadata.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use anyhow::Result;
2+
use serde::Deserialize;
3+
use std::process::Command;
4+
5+
#[derive(Debug, Deserialize)]
6+
pub(in super::super) struct GhPrMetadata {
7+
#[serde(rename = "headRefOid")]
8+
pub(in super::super) head_ref_oid: String,
9+
#[serde(rename = "baseRepository")]
10+
pub(in super::super) base_repository: GhBaseRepository,
11+
}
12+
13+
#[derive(Debug, Deserialize)]
14+
pub(in super::super) struct GhBaseRepository {
15+
#[serde(rename = "nameWithOwner")]
16+
pub(in super::super) name_with_owner: String,
17+
}
18+
19+
pub(in super::super) fn fetch_pr_metadata(
20+
pr_number: &str,
21+
repo: Option<&str>,
22+
) -> Result<GhPrMetadata> {
23+
let mut args = vec![
24+
"pr".to_string(),
25+
"view".to_string(),
26+
pr_number.to_string(),
27+
"--json".to_string(),
28+
"headRefOid,baseRepository".to_string(),
29+
];
30+
if let Some(repo) = repo {
31+
args.push("--repo".to_string());
32+
args.push(repo.to_string());
33+
}
34+
35+
let output = Command::new("gh").args(&args).output()?;
36+
if !output.status.success() {
37+
let stderr = String::from_utf8_lossy(&output.stderr);
38+
anyhow::bail!("gh pr view metadata failed: {}", stderr.trim());
39+
}
40+
41+
let metadata: GhPrMetadata = serde_json::from_slice(&output.stdout)?;
42+
Ok(metadata)
43+
}

src/commands/pr/gh/resolve.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use anyhow::Result;
2+
use std::process::Command;
3+
4+
pub(in super::super) fn resolve_pr_number(
5+
number: Option<u32>,
6+
repo: Option<&str>,
7+
) -> Result<String> {
8+
if let Some(num) = number {
9+
return Ok(num.to_string());
10+
}
11+
12+
let mut args = vec![
13+
"pr".to_string(),
14+
"view".to_string(),
15+
"--json".to_string(),
16+
"number".to_string(),
17+
"-q".to_string(),
18+
".number".to_string(),
19+
];
20+
if let Some(repo) = repo {
21+
args.push("--repo".to_string());
22+
args.push(repo.to_string());
23+
}
24+
25+
let output = Command::new("gh").args(&args).output()?;
26+
if !output.status.success() {
27+
let stderr = String::from_utf8_lossy(&output.stderr);
28+
anyhow::bail!("gh pr view failed: {}", stderr.trim());
29+
}
30+
31+
let pr_number = String::from_utf8(output.stdout)?.trim().to_string();
32+
if pr_number.is_empty() {
33+
anyhow::bail!("Unable to determine PR number from gh output");
34+
}
35+
Ok(pr_number)
36+
}

0 commit comments

Comments
 (0)