Add JUnit xml output format (#968)

This commit is contained in:
messense 2022-11-30 13:47:41 +08:00 committed by GitHub
parent a0202e8eb2
commit f5466fe720
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 114 additions and 8 deletions

64
Cargo.lock generated
View File

@ -220,13 +220,16 @@ dependencies = [
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.22" version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
dependencies = [ dependencies = [
"iana-time-zone", "iana-time-zone",
"js-sys",
"num-integer", "num-integer",
"num-traits", "num-traits",
"time",
"wasm-bindgen",
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -883,9 +886,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.1" version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -1220,6 +1223,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nextest-workspace-hack"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d906846a98739ed9d73d66e62c2641eef8321f1734b7a1156ab045a0248fb2b3"
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.24.2" version = "0.24.2"
@ -1606,6 +1615,29 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "quick-junit"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b909fe9bf2abb1e3d6a97c9189a37c8105c61d03dca9ce6aace023e7d682bd"
dependencies = [
"chrono",
"indexmap",
"nextest-workspace-hack",
"quick-xml",
"thiserror",
"uuid",
]
[[package]]
name = "quick-xml"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.21" version = "1.0.21"
@ -1835,6 +1867,7 @@ dependencies = [
"num-bigint", "num-bigint",
"once_cell", "once_cell",
"path-absolutize", "path-absolutize",
"quick-junit",
"rayon", "rayon",
"regex", "regex",
"ropey", "ropey",
@ -2263,6 +2296,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "tiny-keccak" name = "tiny-keccak"
version = "2.0.2" version = "2.0.2"
@ -2489,6 +2533,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "uuid"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
@ -2527,6 +2577,12 @@ version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"

View File

@ -37,6 +37,7 @@ notify = { version = "4.0.17" }
num-bigint = { version = "0.4.3" } num-bigint = { version = "0.4.3" }
once_cell = { version = "1.16.0" } once_cell = { version = "1.16.0" }
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] } path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
quick-junit = "0.3.2"
rayon = { version = "1.5.3" } rayon = { version = "1.5.3" }
regex = { version = "1.6.0" } regex = { version = "1.6.0" }
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false } ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }

View File

@ -279,7 +279,7 @@ Options:
--per-file-ignores <PER_FILE_IGNORES> --per-file-ignores <PER_FILE_IGNORES>
List of mappings from file pattern to code to exclude List of mappings from file pattern to code to exclude
--format <FORMAT> --format <FORMAT>
Output serialization format for error messages [default: text] [possible values: text, json, grouped] Output serialization format for error messages [default: text] [possible values: text, json, junit, grouped]
--show-source --show-source
Show violations with source code Show violations with source code
--show-files --show-files
@ -1457,7 +1457,7 @@ line-length = 120
#### [`format`](#format) #### [`format`](#format)
The style in which violation messages should be formatted: `"text"` (default), `"grouped"` The style in which violation messages should be formatted: `"text"` (default), `"grouped"`
(group messages by file), or `"json"` (machine-readable). (group messages by file), `"json"` (machine-readable), or `"junit"` (machine-readable XML).
**Default value**: `"text"` **Default value**: `"text"`

View File

@ -3,7 +3,7 @@ use std::str::FromStr;
use itertools::Itertools; use itertools::Itertools;
use rustpython_parser::ast::Location; use rustpython_parser::ast::Location;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use strum_macros::{AsRefStr, EnumIter, EnumString}; use strum_macros::{AsRefStr, Display, EnumIter, EnumString};
use crate::ast::types::Range; use crate::ast::types::Range;
use crate::autofix::Fix; use crate::autofix::Fix;
@ -17,6 +17,7 @@ use crate::pyupgrade::types::Primitive;
EnumIter, EnumIter,
EnumString, EnumString,
Debug, Debug,
Display,
PartialEq, PartialEq,
Eq, Eq,
Clone, Clone,

View File

@ -1,6 +1,6 @@
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::{bail, Result};
use serde::Serialize; use serde::Serialize;
use walkdir::DirEntry; use walkdir::DirEntry;
@ -61,6 +61,9 @@ pub fn explain(code: &CheckCode, format: SerializationFormat) -> Result<()> {
})? })?
); );
} }
SerializationFormat::Junit => {
bail!("`--explain` does not support junit format")
}
}; };
Ok(()) Ok(())
} }

View File

@ -96,6 +96,50 @@ impl<'a> Printer<'a> {
)? )?
); );
} }
SerializationFormat::Junit => {
use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite};
// Group by filename.
let mut grouped_messages = BTreeMap::default();
for message in &diagnostics.messages {
grouped_messages
.entry(&message.filename)
.or_insert_with(Vec::new)
.push(message);
}
let mut report = Report::new("ruff");
for (filename, messages) in grouped_messages {
let mut test_suite = TestSuite::new(filename);
test_suite
.extra
.insert("package".to_string(), "org.ruff".to_string());
for message in messages {
let mut status = TestCaseStatus::non_success(NonSuccessKind::Failure);
status.set_message(message.kind.body());
status.set_description(format!(
"line {}, col {}, {}",
message.location.row(),
message.location.column(),
message.kind.body()
));
let mut case =
TestCase::new(format!("org.ruff.{}", message.kind.code()), status);
let file_path = Path::new(filename);
let file_stem = file_path.file_stem().unwrap().to_str().unwrap();
let classname = file_path.parent().unwrap().join(file_stem);
case.set_classname(classname.to_str().unwrap());
case.extra
.insert("line".to_string(), message.location.row().to_string());
case.extra
.insert("column".to_string(), message.location.column().to_string());
test_suite.add_test_case(case);
}
report.add_test_suite(test_suite);
}
println!("{}", report.to_string().unwrap());
}
SerializationFormat::Text => { SerializationFormat::Text => {
self.pre_text(diagnostics); self.pre_text(diagnostics);

View File

@ -148,5 +148,6 @@ impl FromStr for PatternPrefixPair {
pub enum SerializationFormat { pub enum SerializationFormat {
Text, Text,
Json, Json,
Junit,
Grouped, Grouped,
} }