Skip to content

Commit b439e69

Browse files
committed
Improve review config handling and smart parsing
1 parent 8fb639a commit b439e69

5 files changed

Lines changed: 517 additions & 92 deletions

File tree

src/core/comment.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ pub struct ReviewSummary {
3636
pub recommendations: Vec<String>,
3737
}
3838

39-
#[derive(Debug, Clone, Serialize, Deserialize)]
39+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
4040
pub enum Severity {
4141
Error,
4242
Warning,
4343
Info,
4444
Suggestion,
4545
}
4646

47-
#[derive(Debug, Clone, Serialize, Deserialize)]
47+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
4848
pub enum Category {
4949
Bug,
5050
Security,
@@ -57,7 +57,7 @@ pub enum Category {
5757
Architecture,
5858
}
5959

60-
#[derive(Debug, Clone, Serialize, Deserialize)]
60+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
6161
pub enum FixEffort {
6262
Low, // < 5 minutes
6363
Medium, // 5-30 minutes
@@ -117,11 +117,27 @@ impl CommentSynthesizer {
117117
}
118118

119119
fn process_raw_comment(raw: RawComment) -> Result<Option<Comment>> {
120-
let severity = Self::determine_severity(&raw.content);
121-
let category = Self::determine_category(&raw.content);
122-
let confidence = Self::calculate_confidence(&raw.content, &severity, &category);
123-
let tags = Self::extract_tags(&raw.content, &category);
124-
let fix_effort = Self::determine_fix_effort(&raw.content, &category);
120+
let severity = raw
121+
.severity
122+
.clone()
123+
.unwrap_or_else(|| Self::determine_severity(&raw.content));
124+
let category = raw
125+
.category
126+
.clone()
127+
.unwrap_or_else(|| Self::determine_category(&raw.content));
128+
let confidence = raw.confidence.unwrap_or_else(|| {
129+
Self::calculate_confidence(&raw.content, &severity, &category)
130+
});
131+
let confidence = confidence.max(0.0).min(1.0);
132+
let tags = if raw.tags.is_empty() {
133+
Self::extract_tags(&raw.content, &category)
134+
} else {
135+
raw.tags.clone()
136+
};
137+
let fix_effort = raw
138+
.fix_effort
139+
.clone()
140+
.unwrap_or_else(|| Self::determine_fix_effort(&raw.content, &category));
125141
let code_suggestion = Self::generate_code_suggestion(&raw);
126142

127143
Ok(Some(Comment {
@@ -357,4 +373,9 @@ pub struct RawComment {
357373
pub line_number: usize,
358374
pub content: String,
359375
pub suggestion: Option<String>,
360-
}
376+
pub severity: Option<Severity>,
377+
pub category: Option<Category>,
378+
pub confidence: Option<f32>,
379+
pub fix_effort: Option<FixEffort>,
380+
pub tags: Vec<String>,
381+
}

src/core/context.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use anyhow::Result;
2+
use glob::glob;
23
use serde::{Deserialize, Serialize};
4+
use std::collections::HashSet;
5+
use std::path::Path;
36
use std::path::PathBuf;
47

58
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -33,9 +36,9 @@ impl ContextFetcher {
3336
let full_path = self.repo_path.join(file_path);
3437
if full_path.exists() {
3538
let content = tokio::fs::read_to_string(&full_path).await?;
39+
let file_lines: Vec<&str> = content.lines().collect();
3640

3741
for (start, end) in lines {
38-
let file_lines: Vec<&str> = content.lines().collect();
3942
let start_idx = start.saturating_sub(1);
4043
let end_idx = (*end).min(file_lines.len());
4144

@@ -54,6 +57,53 @@ impl ContextFetcher {
5457
Ok(chunks)
5558
}
5659

60+
pub async fn fetch_additional_context(&self, patterns: &[String]) -> Result<Vec<LLMContextChunk>> {
61+
let mut chunks = Vec::new();
62+
if patterns.is_empty() {
63+
return Ok(chunks);
64+
}
65+
66+
let mut matched_paths = HashSet::new();
67+
for pattern in patterns {
68+
let pattern_path = if Path::new(pattern).is_absolute() {
69+
pattern.clone()
70+
} else {
71+
self.repo_path.join(pattern).to_string_lossy().to_string()
72+
};
73+
74+
if let Ok(entries) = glob(&pattern_path) {
75+
for entry in entries {
76+
if let Ok(path) = entry {
77+
if path.is_file() {
78+
matched_paths.insert(path);
79+
}
80+
}
81+
}
82+
}
83+
}
84+
85+
let max_files = 10usize;
86+
let max_lines = 200usize;
87+
88+
for path in matched_paths.into_iter().take(max_files) {
89+
let relative_path = path.strip_prefix(&self.repo_path).unwrap_or(&path);
90+
let content = tokio::fs::read_to_string(&path).await?;
91+
let snippet = content.lines().take(max_lines).collect::<Vec<_>>().join("\n");
92+
if snippet.trim().is_empty() {
93+
continue;
94+
}
95+
96+
chunks.push(LLMContextChunk {
97+
file_path: relative_path.to_path_buf(),
98+
content: snippet,
99+
context_type: ContextType::Reference,
100+
line_range: None,
101+
});
102+
}
103+
104+
Ok(chunks)
105+
}
106+
57107
pub async fn fetch_related_definitions(&self, file_path: &PathBuf, symbols: &[String]) -> Result<Vec<LLMContextChunk>> {
58108
let mut chunks = Vec::new();
59109

@@ -98,4 +148,4 @@ impl ContextFetcher {
98148

99149
Ok(chunks)
100150
}
101-
}
151+
}

src/core/git.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anyhow::{Context, Result};
2-
use git2::{Repository, DiffOptions, DiffFormat};
3-
use std::path::Path;
2+
use git2::{BranchType, DiffFormat, DiffOptions, Repository};
3+
use std::path::{Path, PathBuf};
44

55
pub struct GitIntegration {
66
repo: Repository,
@@ -108,4 +108,27 @@ impl GitIntegration {
108108

109109
Ok(commits)
110110
}
111-
}
111+
112+
pub fn workdir(&self) -> Option<PathBuf> {
113+
self.repo.workdir().map(|path| path.to_path_buf())
114+
}
115+
116+
pub fn get_default_branch(&self) -> Result<String> {
117+
if let Ok(reference) = self.repo.find_reference("refs/remotes/origin/HEAD") {
118+
if let Some(target) = reference.symbolic_target() {
119+
if let Some(branch) = target.rsplit('/').next() {
120+
return Ok(branch.to_string());
121+
}
122+
}
123+
}
124+
125+
if self.repo.find_branch("main", BranchType::Local).is_ok() {
126+
return Ok("main".to_string());
127+
}
128+
if self.repo.find_branch("master", BranchType::Local).is_ok() {
129+
return Ok("master".to_string());
130+
}
131+
132+
Ok("main".to_string())
133+
}
134+
}

0 commit comments

Comments
 (0)