Skip to content

Commit 7762b5d

Browse files
authored
Merge pull request #51 from a-kenji/ke-group-rules
report: Group failure logs by rule
2 parents bce111c + 59c3de1 commit 7762b5d

2 files changed

Lines changed: 60 additions & 32 deletions

File tree

src/output.rs

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::error::Result;
33
use crate::rules::{Severity, Violation};
44
use colored::*;
55
use serde::{Deserialize, Serialize};
6+
use std::collections::BTreeMap;
67
use std::io::{self, Write};
78
use std::path::{Path, PathBuf};
89
use std::time::Duration;
@@ -109,31 +110,54 @@ impl OutputFormatter {
109110
elapsed: Duration,
110111
) -> Result<()> {
111112
let mut stdout = io::stdout();
113+
let gutter = "┃".dimmed();
112114

113-
for violation in violations {
114-
let severity_icon = match violation.severity {
115-
Severity::Error => "✗".red().bold(),
116-
Severity::Warning => "⚠".yellow().bold(),
117-
};
118-
let path_str = self.relative_path(&violation.path);
119-
let rule_info = format!(
120-
"[{}:{}]",
121-
violation.rule_name,
122-
match violation.severity {
123-
Severity::Error => "error",
124-
Severity::Warning => "warning",
125-
}
126-
)
127-
.dimmed();
115+
let mut by_rule: BTreeMap<&str, Vec<&Violation>> = BTreeMap::new();
116+
for v in violations {
117+
by_rule.entry(&v.rule_name).or_default().push(v);
118+
}
128119

129-
writeln!(
130-
stdout,
131-
"{} {}: {} {}",
132-
severity_icon,
133-
path_str.bold(),
134-
violation.message,
135-
rule_info
136-
)?;
120+
for (rule_name, rule_violations) in &by_rule {
121+
writeln!(stdout, "{}", rule_name.bold())?;
122+
writeln!(stdout, "{gutter}")?;
123+
124+
let mut errors: Vec<&Violation> = Vec::new();
125+
let mut warnings: Vec<&Violation> = Vec::new();
126+
for v in rule_violations {
127+
match v.severity {
128+
Severity::Error => errors.push(v),
129+
Severity::Warning => warnings.push(v),
130+
}
131+
}
132+
errors.sort_by(|a, b| b.sort_key.cmp(&a.sort_key));
133+
warnings.sort_by(|a, b| b.sort_key.cmp(&a.sort_key));
134+
135+
for (severity_group, marker, color_fn) in [
136+
(
137+
&errors,
138+
"[E]",
139+
ColoredString::red as fn(ColoredString) -> ColoredString,
140+
),
141+
(&warnings, "[W]", ColoredString::yellow),
142+
] {
143+
if severity_group.is_empty() {
144+
continue;
145+
}
146+
let message = &severity_group[0].message;
147+
writeln!(stdout, "{gutter} {} {}", color_fn(marker.bold()), message)?;
148+
for v in severity_group {
149+
let path_str = self.relative_path(&v.path);
150+
match &v.actual_value {
151+
Some(actual) => {
152+
writeln!(stdout, "{gutter} {} ({})", path_str.bold(), actual)?;
153+
}
154+
None => {
155+
writeln!(stdout, "{gutter} {}", path_str.bold())?;
156+
}
157+
}
158+
}
159+
}
160+
writeln!(stdout)?;
137161
}
138162

139163
if !self.quiet {

src/rules/mod.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub struct Violation {
4242
pub severity: Severity,
4343
pub actual_value: Option<String>,
4444
pub expected_value: Option<String>,
45+
pub sort_key: u64,
4546
}
4647

4748
impl Violation {
@@ -58,6 +59,7 @@ impl Violation {
5859
severity,
5960
actual_value: None,
6061
expected_value: None,
62+
sort_key: 0,
6163
}
6264
}
6365

@@ -71,6 +73,11 @@ impl Violation {
7173
self
7274
}
7375

76+
pub fn with_sort_key(mut self, key: u64) -> Self {
77+
self.sort_key = key;
78+
self
79+
}
80+
7481
pub fn diagnostic_code(&self) -> String {
7582
format!(
7683
"sizelint::{}::{}",
@@ -444,14 +451,14 @@ impl Rule for ConfigurableRule {
444451
path.to_path_buf(),
445452
self.name.clone(),
446453
format!(
447-
"File size {} exceeds maximum allowed size {}",
448-
format_size(file_size),
454+
"File exceeds maximum allowed size {}",
449455
format_size(max_size)
450456
),
451457
Severity::Error,
452458
)
453459
.with_actual_value(format_size(file_size))
454-
.with_expected_value(format!("≤ {}", format_size(max_size))),
460+
.with_expected_value(format!("≤ {}", format_size(max_size)))
461+
.with_sort_key(file_size),
455462
);
456463
return Ok(violations);
457464
}
@@ -464,15 +471,12 @@ impl Rule for ConfigurableRule {
464471
Violation::new(
465472
path.to_path_buf(),
466473
self.name.clone(),
467-
format!(
468-
"File size {} exceeds warning threshold {}",
469-
format_size(file_size),
470-
format_size(warn_size)
471-
),
474+
format!("File exceeds warning threshold {}", format_size(warn_size)),
472475
Severity::Warning,
473476
)
474477
.with_actual_value(format_size(file_size))
475-
.with_expected_value(format!("≤ {}", format_size(warn_size))),
478+
.with_expected_value(format!("≤ {}", format_size(warn_size)))
479+
.with_sort_key(file_size),
476480
);
477481
}
478482

0 commit comments

Comments
 (0)