Skip to content

Commit 10fec98

Browse files
feat: add gitlab reporter
1 parent 9ccdca6 commit 10fec98

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

crates/squawk/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ arg_enum! {
8080
Tty,
8181
Gcc,
8282
Json,
83+
Gitlab,
8384
}
8485
}
8586

crates/squawk/src/reporter.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ use squawk_linter::Linter;
1111
use squawk_linter::Rule;
1212
use squawk_linter::Version;
1313
use squawk_syntax::SourceFile;
14+
use std::hash::DefaultHasher;
15+
use std::hash::Hash;
16+
use std::hash::Hasher;
1417
use std::io;
1518
use std::path::PathBuf;
1619
use std::process::ExitCode;
@@ -359,6 +362,86 @@ pub fn fmt_github_annotations<W: io::Write>(f: &mut W, reports: &[CheckReport])
359362
Ok(())
360363
}
361364

365+
#[derive(Serialize)]
366+
struct GitLabLines {
367+
begin: usize,
368+
end: usize,
369+
}
370+
371+
#[derive(Serialize)]
372+
struct GitLabLocation {
373+
path: String,
374+
lines: GitLabLines,
375+
}
376+
377+
#[derive(Serialize)]
378+
struct GitLabIssue {
379+
description: String,
380+
severity: String,
381+
fingerprint: String,
382+
location: GitLabLocation,
383+
check_name: String,
384+
}
385+
386+
impl From<&ViolationLevel> for String {
387+
fn from(level: &ViolationLevel) -> Self {
388+
match level {
389+
ViolationLevel::Warning => "minor".to_string(),
390+
ViolationLevel::Error => "major".to_string(),
391+
}
392+
}
393+
}
394+
395+
fn make_fingerprint(v: &ReportViolation) -> String {
396+
let key = format!(
397+
"{}:{}-{}:{}:{}:{}",
398+
v.file, v.line, v.line_end, v.rule_name, v.message, v.level
399+
);
400+
let mut hasher = DefaultHasher::new();
401+
key.hash(&mut hasher);
402+
format!("{:x}", hasher.finish())
403+
}
404+
405+
fn to_gitlab_issue(v: &ReportViolation) -> GitLabIssue {
406+
let mut desc = v.message.clone();
407+
if let Some(help) = &v.help {
408+
if !help.trim().is_empty() {
409+
desc.push_str(" Suggestion: ");
410+
desc.push_str(help.trim());
411+
}
412+
}
413+
414+
GitLabIssue {
415+
description: desc,
416+
severity: String::from(&v.level),
417+
fingerprint: make_fingerprint(v),
418+
location: GitLabLocation {
419+
path: v.file.clone(),
420+
lines: GitLabLines {
421+
begin: v.line,
422+
end: if v.line_end >= v.line {
423+
v.line_end
424+
} else {
425+
v.line
426+
},
427+
},
428+
},
429+
check_name: v.rule_name.clone(),
430+
}
431+
}
432+
433+
fn fmt_gitlab<W: io::Write>(f: &mut W, reports: Vec<CheckReport>) -> Result<()> {
434+
let issues: Vec<GitLabIssue> = reports
435+
.into_iter()
436+
.flat_map(|r| r.violations.into_iter())
437+
.map(|v| to_gitlab_issue(&v))
438+
.collect();
439+
440+
let json = serde_json::to_string(&issues)?;
441+
writeln!(f, "{json}")?;
442+
Ok(())
443+
}
444+
362445
#[derive(Debug)]
363446
pub struct CheckReport {
364447
pub filename: String,
@@ -379,6 +462,7 @@ pub fn print_violations<W: io::Write>(
379462
Reporter::Gcc => fmt_gcc(writer, &reports),
380463
Reporter::Json => fmt_json(writer, reports),
381464
Reporter::Tty => fmt_tty(writer, &reports),
465+
Reporter::Gitlab => fmt_gitlab(writer, reports),
382466
}
383467
}
384468

0 commit comments

Comments
 (0)