feat: add Code Climate output format

This commit is contained in:
Alexandre Franke 2024-02-07 21:39:07 +01:00
parent e4d7f4a4d0
commit 724e616e4d
2 changed files with 94 additions and 0 deletions

View file

@ -10,6 +10,7 @@ pub enum Format {
#[default] #[default]
Long, Long,
Json, Json,
CodeClimate,
} }
impl Format { impl Format {
@ -19,6 +20,7 @@ impl Format {
Format::Brief => Box::new(crate::report::PrintBrief), Format::Brief => Box::new(crate::report::PrintBrief),
Format::Long => Box::new(crate::report::PrintLong), Format::Long => Box::new(crate::report::PrintLong),
Format::Json => Box::new(crate::report::PrintJson), Format::Json => Box::new(crate::report::PrintJson),
Format::CodeClimate => Box::new(crate::report::PrintCodeClimate),
} }
} }
} }

View file

@ -280,6 +280,98 @@ impl Report for PrintJson {
} }
} }
pub struct PrintCodeClimate;
impl Report for PrintCodeClimate {
fn report(&self, msg: Message) -> Result<(), std::io::Error> {
let mut climate: CodeClimate = Default::default();
climate.r#type = "issue";
climate.check_name = "typos";
match msg {
Message::BinaryFile(_msg) => {
climate.severity = "info";
}
Message::Typo(msg) => {
match msg.corrections {
typos::Status::Valid => {}
typos::Status::Invalid => {
climate.description = format!("`{}` is disallowed", msg.typo,);
}
typos::Status::Corrections(corrections) => {
climate.description = format!(
"`{}` should be {}",
msg.typo,
itertools::join(corrections.iter().map(|s| format!("`{}`", s)), ", ")
);
}
}
climate.categories = "Clarity";
climate.severity = "minor";
climate.location = Location::from(msg.context.unwrap());
}
Message::Error(msg) => {
climate.severity = "error";
climate.description = context_display(&msg.context).to_string();
}
_ => {
climate.severity = "minor";
}
}
writeln!(
stdout().lock(),
"{}",
serde_json::to_string(&climate).unwrap()
)?;
Ok(())
}
}
#[derive(Default, serde::Serialize)]
struct CodeClimate<'l> {
check_name: &'l str,
description: String,
categories: &'l str,
location: Location<'l>,
severity: &'l str,
r#type: &'l str,
}
#[derive(serde::Serialize)]
struct Location<'l> {
path: &'l std::path::Path,
lines: Lines,
}
impl<'l> Default for Location<'l> {
fn default() -> Self {
Self {
path: std::path::Path::new("-"),
lines: Lines { begin: 0 },
}
}
}
impl<'l> From<Context<'l>> for Location<'l> {
fn from(context: Context<'l>) -> Self {
match context {
Context::File(c) => Self {
path: c.path,
lines: Lines { begin: c.line_num },
},
Context::Path(c) => Self {
path: c.path,
..Default::default()
},
_ => Default::default(),
}
}
}
#[derive(Default, serde::Serialize)]
struct Lines {
begin: usize,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;