use std::{
hash::{DefaultHasher, Hash, Hasher},
path::Path,
};
use serde_json::json;
use crate::{
config::RuleLevel,
rules::{Category, Violation},
};
pub fn generate_gitlab_codequality(violations: &[Violation], project_root: &Path) -> String {
let issues = violations
.iter()
.map(|v| generate_issue(v, project_root))
.collect::<Vec<_>>();
serde_json::to_string_pretty(&issues).unwrap()
}
fn geneerate_issue_fingerprint(violation: &Violation, relative_path: &str) -> String {
let mut hasher = DefaultHasher::new();
violation.rule.hash(&mut hasher);
relative_path.hash(&mut hasher);
violation.line.hash(&mut hasher);
violation.column.hash(&mut hasher);
hasher.finish().to_string()
}
fn generate_issue(violation: &Violation, project_root: &Path) -> serde_json::Value {
let relative_path = violation
.file
.strip_prefix(project_root)
.unwrap_or(&violation.file)
.display()
.to_string();
let location = json!({
"path": relative_path,
"positions": {
"begin": {
"line": violation.line,
"column": violation.column
}
},
});
json!({
"description": violation.message,
"check_name": violation.rule,
"fingerprint": geneerate_issue_fingerprint(violation, &relative_path),
"severity": rule_level_to_codequality_severity(violation),
"categories": [violation.category],
"location": location,
})
}
fn rule_level_to_codequality_severity(violation: &Violation) -> &'static str {
match (violation.level, violation.category) {
(RuleLevel::Error, _) => "blocker",
(RuleLevel::Warn, Category::Correctness) => "critical",
(RuleLevel::Warn, Category::Perf) => "critical",
(RuleLevel::Warn, _) => "info",
(RuleLevel::Ignore, _) => {
unreachable!("Ignored violations should not be reported")
}
}
}