diff --git a/Cargo.lock b/Cargo.lock index 1e2cf3db5b..21c7d6c3ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1503,6 +1503,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "peg" version = "0.8.1" @@ -1979,6 +1985,7 @@ dependencies = [ "num-traits", "once_cell", "path-absolutize", + "pathdiff", "regex", "result-like", "ruff_cache", diff --git a/crates/ruff/Cargo.toml b/crates/ruff/Cargo.toml index c8fe963caa..21565d2eb4 100644 --- a/crates/ruff/Cargo.toml +++ b/crates/ruff/Cargo.toml @@ -46,6 +46,7 @@ path-absolutize = { workspace = true, features = [ "once_cell_cache", "use_unix_paths_on_wasm", ] } +pathdiff = { version = "0.2.1" } regex = { workspace = true } result-like = { version = "0.4.6" } rustc-hash = { workspace = true } diff --git a/crates/ruff/src/fs.rs b/crates/ruff/src/fs.rs index b7f3a4e86e..8e8dd2acc1 100644 --- a/crates/ruff/src/fs.rs +++ b/crates/ruff/src/fs.rs @@ -74,10 +74,20 @@ pub fn normalize_path_to, R: AsRef>(path: P, project_root: } /// Convert an absolute path to be relative to the current working directory. -pub fn relativize_path(path: impl AsRef) -> String { +pub fn relativize_path>(path: P) -> String { let path = path.as_ref(); if let Ok(path) = path.strip_prefix(&*path_dedot::CWD) { return format!("{}", path.display()); } format!("{}", path.display()) } + +/// Convert an absolute path to be relative to the specified project root. +pub fn relativize_path_to, R: AsRef>(path: P, project_root: R) -> String { + format!( + "{}", + pathdiff::diff_paths(&path, project_root) + .expect("Could not diff paths") + .display() + ) +} diff --git a/crates/ruff_cli/src/printer.rs b/crates/ruff_cli/src/printer.rs index d5d5c624a8..66dbb1e0e9 100644 --- a/crates/ruff_cli/src/printer.rs +++ b/crates/ruff_cli/src/printer.rs @@ -3,9 +3,9 @@ use std::collections::hash_map::DefaultHasher; use std::collections::BTreeMap; use std::fmt::Display; use std::hash::{Hash, Hasher}; -use std::io; use std::io::{BufWriter, Write}; use std::path::Path; +use std::{env, io}; use annotate_snippets::display_list::{DisplayList, FormatOptions}; use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; @@ -18,7 +18,7 @@ use rustc_hash::FxHashMap; use serde::Serialize; use serde_json::json; -use ruff::fs::relativize_path; +use ruff::fs::{relativize_path, relativize_path_to}; use ruff::linter::FixTable; use ruff::logging::LogLevel; use ruff::message::{Location, Message}; @@ -341,7 +341,8 @@ impl Printer { } SerializationFormat::Gitlab => { // Generate JSON with violations in GitLab CI format - // https://docs.gitlab.com/ee/ci/testing/code_quality.html#implementing-a-custom-tool + // https://docs.gitlab.com/ee/ci/testing/code_quality.html#implement-a-custom-tool + let project_dir = env::var("CI_PROJECT_DIR").ok(); writeln!(stdout, "{}", serde_json::to_string_pretty( @@ -354,7 +355,10 @@ impl Printer { "severity": "major", "fingerprint": fingerprint(message), "location": { - "path": message.filename, + "path": project_dir.as_ref().map_or_else( + || relativize_path(Path::new(&message.filename)), + |project_dir| relativize_path_to(&message.filename, project_dir), + ), "lines": { "begin": message.location.row(), "end": message.end_location.row()