Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,23 @@ jobs:
- name: Extract version
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"

- name: Verify release metadata matches tag
env:
TAG_NAME: ${{ steps.get_version.outputs.VERSION }}
run: |
set -euo pipefail
expected_version="${TAG_NAME#v}"
cargo_version="$(python3 -c "import tomllib; from pathlib import Path; print(tomllib.loads(Path('Cargo.toml').read_text())['package']['version'])")"
chart_app_version="$(python3 -c "import re; from pathlib import Path; c=Path('charts/diffscope/Chart.yaml').read_text(); m=re.search(r'^appVersion:\s*\"?(.*?)\"?\s*\$', c, re.MULTILINE); (exit('Chart.yaml missing appVersion') if not m else print(m.group(1)))")"
test "$cargo_version" = "$expected_version" || {
echo "Cargo.toml version ($cargo_version) does not match tag ($expected_version)"
exit 1
}
test "$chart_app_version" = "$expected_version" || {
echo "Chart appVersion ($chart_app_version) does not match tag ($expected_version)"
exit 1
}

- name: Create Release
id: create_release
Expand Down Expand Up @@ -264,4 +281,4 @@ jobs:
- name: Upload SBOM to release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release upload ${{ github.ref_name }} sbom-diffscope.spdx.json --clobber || true
run: gh release upload ${{ github.ref_name }} sbom-diffscope.spdx.json --clobber || true
2 changes: 1 addition & 1 deletion charts/diffscope/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: diffscope
description: AI-powered code review engine with smart analysis and professional reporting
type: application
version: 0.1.0
appVersion: "0.5.3"
appVersion: "0.5.26"
home: https://github.com/evalops/diffscope
sources:
- https://github.com/evalops/diffscope
Expand Down
2 changes: 1 addition & 1 deletion eval/dag-runtime-smoke-or.json
Original file line number Diff line number Diff line change
Expand Up @@ -2195,4 +2195,4 @@
]
}
]
}
}
2 changes: 1 addition & 1 deletion eval/frontier-e2e-or.json
Original file line number Diff line number Diff line change
Expand Up @@ -9981,4 +9981,4 @@
]
}
]
}
}
2 changes: 1 addition & 1 deletion eval/frontier-smoke-or.json
Original file line number Diff line number Diff line change
Expand Up @@ -5904,4 +5904,4 @@
]
}
]
}
}
9 changes: 3 additions & 6 deletions src/adapters/anthropic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,7 @@ mod tests {
let err_msg = format!("{:#}", result.unwrap_err());
assert!(
err_msg.contains("401") || err_msg.contains("Unauthorized"),
"Error should mention 401 or Unauthorized, got: {}",
err_msg
"Error should mention 401 or Unauthorized, got: {err_msg}"
);
mock.assert_async().await;
}
Expand Down Expand Up @@ -502,8 +501,7 @@ mod tests {
let err = result.unwrap_err().to_string();
assert!(
err.contains("Unsupported content type"),
"Error should mention unsupported type, got: {}",
err
"Error should mention unsupported type, got: {err}"
);
}

Expand Down Expand Up @@ -534,8 +532,7 @@ mod tests {
let err = result.unwrap_err().to_string();
assert!(
err.contains("empty content"),
"Error should mention empty content: {}",
err
"Error should mention empty content: {err}"
);
}

Expand Down
20 changes: 9 additions & 11 deletions src/adapters/ollama.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,10 @@ mod tests {
fn chat_response_body(content: &str, model: &str, done: bool) -> String {
format!(
r#"{{
"message": {{"role": "assistant", "content": "{}"}},
"model": "{}",
"done": {}
}}"#,
content, model, done
"message": {{"role": "assistant", "content": "{content}"}},
"model": "{model}",
"done": {done}
}}"#
)
}

Expand All @@ -227,13 +226,12 @@ mod tests {
) -> String {
format!(
r#"{{
"message": {{"role": "assistant", "content": "{}"}},
"model": "{}",
"message": {{"role": "assistant", "content": "{content}"}},
"model": "{model}",
"done": true,
"prompt_eval_count": {},
"eval_count": {}
}}"#,
content, model, prompt_eval, eval
"prompt_eval_count": {prompt_eval},
"eval_count": {eval}
}}"#
)
}

Expand Down
9 changes: 3 additions & 6 deletions src/adapters/openai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,8 +771,7 @@ mod tests {
let err_msg = format!("{:#}", result.unwrap_err());
assert!(
err_msg.contains("401") || err_msg.contains("Unauthorized"),
"Error should mention 401 or Unauthorized, got: {}",
err_msg
"Error should mention 401 or Unauthorized, got: {err_msg}"
);
mock.assert_async().await;
}
Expand Down Expand Up @@ -814,8 +813,7 @@ mod tests {
let err_msg = format!("{:#}", result.unwrap_err());
assert!(
err_msg.contains("429") || err_msg.contains("Rate limited"),
"Error should mention rate limiting, got: {}",
err_msg
"Error should mention rate limiting, got: {err_msg}"
);
mock.assert_async().await;
}
Expand Down Expand Up @@ -866,8 +864,7 @@ mod tests {
let err = result.unwrap_err().to_string();
assert!(
err.contains("empty choices"),
"Error should mention empty choices: {}",
err
"Error should mention empty choices: {err}"
);
}

Expand Down
7 changes: 2 additions & 5 deletions src/commands/doctor/command/display/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,14 @@ pub(in super::super) fn print_configuration(config: &Config) {
}
);
if let Some(cw) = config.context_window {
println!(" Context: {} tokens", cw);
println!(" Context: {cw} tokens");
}
println!();
}

pub(in super::super) fn print_unreachable(base_url: &str) -> Result<()> {
println!("UNREACHABLE");
println!(
"\nCannot reach {}. Make sure your LLM server is running.",
base_url
);
println!("\nCannot reach {base_url}. Make sure your LLM server is running.");
println!("\nQuick start:");
println!(" Ollama: ollama serve");
println!(" vLLM: vllm serve <model>");
Expand Down
4 changes: 2 additions & 2 deletions src/commands/doctor/command/display/endpoint.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::core::offline::LocalModel;

pub(in super::super) fn print_endpoint_models(endpoint_type: &str, models: &[LocalModel]) {
println!("\nEndpoint type: {}", endpoint_type);
println!("\nEndpoint type: {endpoint_type}");
println!("\nAvailable models ({}):", models.len());
if models.is_empty() {
println!(" (none found)");
Expand All @@ -25,7 +25,7 @@ fn format_model_size_info(model: &LocalModel) -> String {
+ &model
.quantization
.as_ref()
.map(|quantization| format!(", {}", quantization))
.map(|quantization| format!(", {quantization}"))
.unwrap_or_default()
+ ")"
}
16 changes: 5 additions & 11 deletions src/commands/doctor/command/display/inference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,18 @@ pub(in super::super) fn print_recommended_model_summary(
readiness: &ReadinessCheck,
) {
println!("\nRecommended for code review: {}", recommended.name);
println!(" Estimated RAM: ~{}MB", estimated_ram_mb);
println!(" Estimated RAM: ~{estimated_ram_mb}MB");

if let Some(ctx_size) = detected_context_window {
println!(
" Context window: {} tokens (detected from model)",
ctx_size
);
println!(" Context window: {ctx_size} tokens (detected from model)");
}

if readiness.ready {
println!("\nStatus: READY");
} else {
println!("\nStatus: NOT READY");
for warning in &readiness.warnings {
println!(" Warning: {}", warning);
println!(" Warning: {warning}");
}
}
}
Expand All @@ -41,14 +38,11 @@ pub(in super::super) fn print_inference_success(elapsed: Duration, tokens_per_se

pub(in super::super) fn print_inference_failure(error: &impl std::fmt::Display) {
println!("FAILED");
println!(" Error: {}", error);
println!(" Error: {error}");
println!(" The model may still be loading. Try again in a moment.");
}

pub(in super::super) fn print_usage(base_url: &str, model_flag: &str) {
println!("\nUsage:");
println!(
" git diff | diffscope review --base-url {} --model {}",
base_url, model_flag
);
println!(" git diff | diffscope review --base-url {base_url} --model {model_flag}");
}
6 changes: 3 additions & 3 deletions src/commands/doctor/command/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl EndpointProbe {

pub(super) fn model_flag(&self, model_name: &str) -> String {
if self.is_ollama() {
format!("ollama:{}", model_name)
format!("ollama:{model_name}")
} else {
model_name.to_string()
}
Expand Down Expand Up @@ -49,7 +49,7 @@ pub(super) async fn probe_endpoint(
}

async fn probe_ollama_endpoint(client: &Client, base_url: &str) -> Result<Option<Vec<LocalModel>>> {
let url = format!("{}/api/tags", base_url);
let url = format!("{base_url}/api/tags");
let response = match client.get(&url).send().await {
Ok(response) => response,
Err(_) => return Ok(None),
Expand All @@ -65,7 +65,7 @@ async fn probe_ollama_endpoint(client: &Client, base_url: &str) -> Result<Option
}

async fn probe_openai_endpoint(client: &Client, base_url: &str) -> Result<Option<Vec<LocalModel>>> {
let url = format!("{}/v1/models", base_url);
let url = format!("{base_url}/v1/models");
let response = match client.get(&url).send().await {
Ok(response) => response,
Err(_) => return Ok(None),
Expand Down
2 changes: 1 addition & 1 deletion src/commands/doctor/command/recommend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub(super) async fn inspect_recommended_model(
&readiness,
);

print!("\nTesting model {}... ", recommended_name);
print!("\nTesting model {recommended_name}... ");
let test_client = Client::builder().timeout(Duration::from_secs(10)).build()?;
let started_at = Instant::now();
match test_model_inference(
Expand Down
2 changes: 1 addition & 1 deletion src/commands/doctor/command/run/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub async fn doctor_command(config: Config) -> Result<()> {

let base_url = configured_base_url(&config);

print!("Checking endpoint {}... ", base_url);
print!("Checking endpoint {base_url}... ");
let Some(endpoint) = discover_endpoint(&base_url).await? else {
return print_unreachable(&base_url);
};
Expand Down
4 changes: 2 additions & 2 deletions src/commands/doctor/endpoint/inference/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn build_probe_messages() -> Value {

fn build_ollama_request(base_url: &str, model_name: &str, messages: Value) -> InferenceRequest {
InferenceRequest {
url: format!("{}/api/chat", base_url),
url: format!("{base_url}/api/chat"),
body: json!({
"model": model_name,
"messages": messages,
Expand All @@ -44,7 +44,7 @@ fn build_ollama_request(base_url: &str, model_name: &str, messages: Value) -> In

fn build_openai_request(base_url: &str, model_name: &str, messages: Value) -> InferenceRequest {
InferenceRequest {
url: format!("{}/v1/chat/completions", base_url),
url: format!("{base_url}/v1/chat/completions"),
body: json!({
"model": model_name,
"messages": messages,
Expand Down
9 changes: 3 additions & 6 deletions src/commands/doctor/system/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,19 @@ pub(super) fn print_system_resources_header() {
}

pub(super) fn print_total_ram(total_ram_gb: f64) {
println!(" Total RAM: {:.1} GB", total_ram_gb);
println!(" Total RAM: {total_ram_gb:.1} GB");
}

pub(super) fn print_gpu_lines(gpu_lines: &[String]) {
for line in gpu_lines {
println!(" GPU: {}", line);
println!(" GPU: {line}");
}
}

pub(super) fn print_apple_chip(chip: &str) {
#[cfg(target_os = "macos")]
{
println!(
" Chip: {} (unified memory, GPU acceleration available)",
chip
);
println!(" Chip: {chip} (unified memory, GPU acceleration available)");
}

#[cfg(not(target_os = "macos"))]
Expand Down
4 changes: 2 additions & 2 deletions src/commands/doctor/system/probes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ mod tests {
#[cfg(any(target_os = "macos", target_os = "linux"))]
{
let gb = ram.unwrap();
assert!(gb > 0.5, "RAM should be at least 0.5 GB, got {}", gb);
assert!(gb < 4096.0, "RAM should be under 4 TB, got {}", gb);
assert!(gb > 0.5, "RAM should be at least 0.5 GB, got {gb}");
assert!(gb < 4096.0, "RAM should be under 4 TB, got {gb}");
}

let _ = ram;
Expand Down
13 changes: 7 additions & 6 deletions src/commands/eval/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub async fn eval_command(
output_path: Option<PathBuf>,
mut options: EvalRunOptions,
) -> Result<()> {
config.verification_fail_open = true;
config.verification.fail_open = true;
if options.trend_file.is_none() {
options.trend_file = Some(config.eval_trend_path.clone());
}
Expand Down Expand Up @@ -76,8 +76,8 @@ fn build_eval_run_metadata(
);
let mut verification_judges = Vec::new();
let mut seen_verification_judges = HashSet::new();
for role in std::iter::once(config.verification_model_role)
.chain(config.verification_additional_model_roles.iter().copied())
for role in std::iter::once(config.verification.model_role)
.chain(config.verification.additional_model_roles.iter().copied())
{
let model = config.model_for_role(role).to_string();
if seen_verification_judges.insert(model.clone()) {
Expand All @@ -102,11 +102,12 @@ fn build_eval_run_metadata(
fixture_name_filters: options.fixture_name_filters.clone(),
max_fixtures: options.max_fixtures,
},
verification_fail_open: config.verification_fail_open,
verification_fail_open: config.verification.fail_open,
verification_judges,
verification_consensus_mode: config
.verification_pass
.then(|| config.verification_consensus_mode.as_str().to_string()),
.verification
.enabled
.then(|| config.verification.consensus_mode.as_str().to_string()),
trend_file: options
.trend_file
.as_ref()
Expand Down
Loading
Loading