Skip to content

Commit ce20615

Browse files
committed
refactor: split feedback eval input helpers
Separate input format loading from comment conversion so feedback eval changes stay easier to isolate and verify. Made-with: Cursor
1 parent 6b2221b commit ce20615

File tree

3 files changed

+163
-144
lines changed

3 files changed

+163
-144
lines changed

src/commands/feedback_eval/input.rs

Lines changed: 10 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,19 @@
1-
use anyhow::Result;
2-
use std::collections::HashMap;
3-
use std::path::Path;
1+
#[path = "input/conversion.rs"]
2+
mod conversion;
3+
#[path = "input/loading.rs"]
4+
mod loading;
45

5-
use crate::core;
6-
use crate::review;
7-
use crate::server::state::ReviewSession;
6+
pub(super) use loading::load_feedback_eval_input;
87

9-
use super::{FeedbackEvalComment, LoadedFeedbackEvalInput};
10-
11-
pub(super) async fn load_feedback_eval_input(path: &Path) -> Result<LoadedFeedbackEvalInput> {
12-
let content = tokio::fs::read_to_string(path).await?;
13-
load_feedback_eval_input_from_str(&content)
14-
}
15-
16-
pub(super) fn load_feedback_eval_input_from_str(content: &str) -> Result<LoadedFeedbackEvalInput> {
17-
if let Ok(review_map) = serde_json::from_str::<HashMap<String, ReviewSession>>(content) {
18-
let mut loaded = LoadedFeedbackEvalInput::default();
19-
for (review_id, session) in review_map {
20-
extend_from_review_session(&mut loaded, Some(review_id), session);
21-
}
22-
return Ok(loaded);
23-
}
24-
25-
if let Ok(review_list) = serde_json::from_str::<Vec<ReviewSession>>(content) {
26-
let mut loaded = LoadedFeedbackEvalInput::default();
27-
for session in review_list {
28-
let review_id = session.id.clone();
29-
extend_from_review_session(&mut loaded, Some(review_id), session);
30-
}
31-
return Ok(loaded);
32-
}
33-
34-
if let Ok(store) = serde_json::from_str::<core::SemanticFeedbackStore>(content) {
35-
let total_comments_seen = store.examples.len();
36-
let comments = store
37-
.examples
38-
.into_iter()
39-
.map(|example| FeedbackEvalComment {
40-
source_kind: "semantic-feedback".to_string(),
41-
review_id: None,
42-
repo: None,
43-
pr_number: None,
44-
title: None,
45-
file_path: None,
46-
line_number: None,
47-
file_patterns: example.file_patterns,
48-
content: example.content,
49-
category: example.category,
50-
severity: None,
51-
confidence: None,
52-
accepted: example.accepted,
53-
})
54-
.collect();
55-
return Ok(LoadedFeedbackEvalInput {
56-
total_comments_seen,
57-
total_reviews_seen: 0,
58-
comments,
59-
});
60-
}
61-
62-
if let Ok(comments) = serde_json::from_str::<Vec<core::Comment>>(content) {
63-
let total_comments_seen = comments.len();
64-
let comments = comments
65-
.into_iter()
66-
.filter_map(|comment| {
67-
feedback_comment_from_comment("comments-json", None, None, None, None, comment)
68-
})
69-
.collect();
70-
return Ok(LoadedFeedbackEvalInput {
71-
total_comments_seen,
72-
total_reviews_seen: 0,
73-
comments,
74-
});
75-
}
76-
77-
anyhow::bail!(
78-
"Unsupported feedback eval input format: expected reviews.json, a comments array, or semantic feedback store JSON"
79-
)
80-
}
81-
82-
fn extend_from_review_session(
83-
loaded: &mut LoadedFeedbackEvalInput,
84-
review_id: Option<String>,
85-
session: ReviewSession,
86-
) {
87-
let repo = session
88-
.event
89-
.as_ref()
90-
.and_then(|event| event.github_repo.clone());
91-
let pr_number = session.event.as_ref().and_then(|event| event.github_pr);
92-
let title = session.event.as_ref().and_then(|event| event.title.clone());
93-
94-
loaded.total_reviews_seen += 1;
95-
loaded.total_comments_seen += session.comments.len();
96-
loaded
97-
.comments
98-
.extend(session.comments.into_iter().filter_map(|comment| {
99-
feedback_comment_from_comment(
100-
"review-session",
101-
review_id.clone(),
102-
repo.clone(),
103-
pr_number,
104-
title.clone(),
105-
comment,
106-
)
107-
}));
108-
}
109-
110-
fn feedback_comment_from_comment(
111-
source_kind: &str,
112-
review_id: Option<String>,
113-
repo: Option<String>,
114-
pr_number: Option<u32>,
115-
title: Option<String>,
116-
comment: core::Comment,
117-
) -> Option<FeedbackEvalComment> {
118-
let accepted = normalize_feedback_label(comment.feedback.as_deref()?)?;
119-
let file_patterns = review::derive_file_patterns(&comment.file_path);
120-
121-
Some(FeedbackEvalComment {
122-
source_kind: source_kind.to_string(),
123-
review_id,
124-
repo,
125-
pr_number,
126-
title,
127-
file_path: Some(comment.file_path),
128-
line_number: Some(comment.line_number),
129-
file_patterns,
130-
content: comment.content,
131-
category: comment.category.to_string(),
132-
severity: Some(comment.severity.to_string()),
133-
confidence: Some(comment.confidence),
134-
accepted,
135-
})
136-
}
137-
138-
fn normalize_feedback_label(label: &str) -> Option<bool> {
139-
match label.trim().to_ascii_lowercase().as_str() {
140-
"accept" | "accepted" => Some(true),
141-
"reject" | "rejected" => Some(false),
142-
_ => None,
143-
}
144-
}
8+
#[cfg(test)]
9+
use loading::load_feedback_eval_input_from_str;
14510

14611
#[cfg(test)]
14712
mod tests {
148-
use super::*;
13+
use super::load_feedback_eval_input_from_str;
14+
use crate::core;
14915
use crate::core::comment::{Category, FixEffort, ReviewSummary, Severity};
150-
use crate::server::state::ReviewStatus;
16+
use crate::server::state::{ReviewSession, ReviewStatus};
15117
use std::collections::HashMap;
15218
use std::path::PathBuf;
15319

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use crate::core;
2+
use crate::review;
3+
use crate::server::state::ReviewSession;
4+
5+
use super::super::{FeedbackEvalComment, LoadedFeedbackEvalInput};
6+
7+
pub(super) fn extend_from_review_session(
8+
loaded: &mut LoadedFeedbackEvalInput,
9+
review_id: Option<String>,
10+
session: ReviewSession,
11+
) {
12+
let repo = session
13+
.event
14+
.as_ref()
15+
.and_then(|event| event.github_repo.clone());
16+
let pr_number = session.event.as_ref().and_then(|event| event.github_pr);
17+
let title = session.event.as_ref().and_then(|event| event.title.clone());
18+
19+
loaded.total_reviews_seen += 1;
20+
loaded.total_comments_seen += session.comments.len();
21+
loaded
22+
.comments
23+
.extend(session.comments.into_iter().filter_map(|comment| {
24+
feedback_comment_from_comment(
25+
"review-session",
26+
review_id.clone(),
27+
repo.clone(),
28+
pr_number,
29+
title.clone(),
30+
comment,
31+
)
32+
}));
33+
}
34+
35+
pub(super) fn feedback_comment_from_comment(
36+
source_kind: &str,
37+
review_id: Option<String>,
38+
repo: Option<String>,
39+
pr_number: Option<u32>,
40+
title: Option<String>,
41+
comment: core::Comment,
42+
) -> Option<FeedbackEvalComment> {
43+
let accepted = normalize_feedback_label(comment.feedback.as_deref()?)?;
44+
let file_patterns = review::derive_file_patterns(&comment.file_path);
45+
46+
Some(FeedbackEvalComment {
47+
source_kind: source_kind.to_string(),
48+
review_id,
49+
repo,
50+
pr_number,
51+
title,
52+
file_path: Some(comment.file_path),
53+
line_number: Some(comment.line_number),
54+
file_patterns,
55+
content: comment.content,
56+
category: comment.category.to_string(),
57+
severity: Some(comment.severity.to_string()),
58+
confidence: Some(comment.confidence),
59+
accepted,
60+
})
61+
}
62+
63+
fn normalize_feedback_label(label: &str) -> Option<bool> {
64+
match label.trim().to_ascii_lowercase().as_str() {
65+
"accept" | "accepted" => Some(true),
66+
"reject" | "rejected" => Some(false),
67+
_ => None,
68+
}
69+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use anyhow::Result;
2+
use std::collections::HashMap;
3+
use std::path::Path;
4+
5+
use crate::core;
6+
use crate::server::state::ReviewSession;
7+
8+
use super::super::{FeedbackEvalComment, LoadedFeedbackEvalInput};
9+
use super::conversion::{extend_from_review_session, feedback_comment_from_comment};
10+
11+
pub(in super::super) async fn load_feedback_eval_input(
12+
path: &Path,
13+
) -> Result<LoadedFeedbackEvalInput> {
14+
let content = tokio::fs::read_to_string(path).await?;
15+
load_feedback_eval_input_from_str(&content)
16+
}
17+
18+
pub(in super::super) fn load_feedback_eval_input_from_str(
19+
content: &str,
20+
) -> Result<LoadedFeedbackEvalInput> {
21+
if let Ok(review_map) = serde_json::from_str::<HashMap<String, ReviewSession>>(content) {
22+
let mut loaded = LoadedFeedbackEvalInput::default();
23+
for (review_id, session) in review_map {
24+
extend_from_review_session(&mut loaded, Some(review_id), session);
25+
}
26+
return Ok(loaded);
27+
}
28+
29+
if let Ok(review_list) = serde_json::from_str::<Vec<ReviewSession>>(content) {
30+
let mut loaded = LoadedFeedbackEvalInput::default();
31+
for session in review_list {
32+
let review_id = session.id.clone();
33+
extend_from_review_session(&mut loaded, Some(review_id), session);
34+
}
35+
return Ok(loaded);
36+
}
37+
38+
if let Ok(store) = serde_json::from_str::<core::SemanticFeedbackStore>(content) {
39+
let total_comments_seen = store.examples.len();
40+
let comments = store
41+
.examples
42+
.into_iter()
43+
.map(|example| FeedbackEvalComment {
44+
source_kind: "semantic-feedback".to_string(),
45+
review_id: None,
46+
repo: None,
47+
pr_number: None,
48+
title: None,
49+
file_path: None,
50+
line_number: None,
51+
file_patterns: example.file_patterns,
52+
content: example.content,
53+
category: example.category,
54+
severity: None,
55+
confidence: None,
56+
accepted: example.accepted,
57+
})
58+
.collect();
59+
return Ok(LoadedFeedbackEvalInput {
60+
total_comments_seen,
61+
total_reviews_seen: 0,
62+
comments,
63+
});
64+
}
65+
66+
if let Ok(comments) = serde_json::from_str::<Vec<core::Comment>>(content) {
67+
let total_comments_seen = comments.len();
68+
let comments = comments
69+
.into_iter()
70+
.filter_map(|comment| {
71+
feedback_comment_from_comment("comments-json", None, None, None, None, comment)
72+
})
73+
.collect();
74+
return Ok(LoadedFeedbackEvalInput {
75+
total_comments_seen,
76+
total_reviews_seen: 0,
77+
comments,
78+
});
79+
}
80+
81+
anyhow::bail!(
82+
"Unsupported feedback eval input format: expected reviews.json, a comments array, or semantic feedback store JSON"
83+
)
84+
}

0 commit comments

Comments
 (0)