|
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; |
4 | 5 |
|
5 | | -use crate::core; |
6 | | -use crate::review; |
7 | | -use crate::server::state::ReviewSession; |
| 6 | +pub(super) use loading::load_feedback_eval_input; |
8 | 7 |
|
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; |
145 | 10 |
|
146 | 11 | #[cfg(test)] |
147 | 12 | mod tests { |
148 | | - use super::*; |
| 13 | + use super::load_feedback_eval_input_from_str; |
| 14 | + use crate::core; |
149 | 15 | use crate::core::comment::{Category, FixEffort, ReviewSummary, Severity}; |
150 | | - use crate::server::state::ReviewStatus; |
| 16 | + use crate::server::state::{ReviewSession, ReviewStatus}; |
151 | 17 | use std::collections::HashMap; |
152 | 18 | use std::path::PathBuf; |
153 | 19 |
|
|
0 commit comments