use crate::delta::DeltaReport;
use crate::duplicates::compare::DuplicatePair;
use crate::merge::{CrapEntry, ScopeDiagnostics};
use crate::score::Severity;
use anyhow::{Result, bail};
use std::io::Write;
pub mod duplicates;
mod github;
mod human;
mod json;
mod links;
mod markdown;
mod per_crate;
mod pr_comment;
mod sarif;
mod shields;
mod summary;
mod types;
#[cfg(test)]
mod test_support;
pub use json::{DELTA_SCHEMA_URL, Envelope, REPORT_SCHEMA_URL, SCHEMA_VERSION};
pub use links::SourceLinks;
pub use summary::{render_delta_summary, render_summary};
pub use types::set_color_enabled;
#[derive(Debug, Clone, Copy)]
pub enum Format {
Human,
Json,
GitHub,
Markdown,
PrComment,
Sarif,
Shields,
}
#[derive(Debug, Clone, Copy)]
pub struct RenderOptions<'a> {
pub threshold: f64,
pub format: Format,
pub links: Option<&'a SourceLinks>,
pub diagnostics: Option<&'a ScopeDiagnostics>,
pub show_unchanged: bool,
pub uncovered_hints: bool,
pub duplicates: Option<&'a [DuplicatePair]>,
}
impl Default for RenderOptions<'_> {
fn default() -> Self {
Self {
threshold: crate::score::DEFAULT_THRESHOLD,
format: Format::Human,
links: None,
diagnostics: None,
show_unchanged: false,
uncovered_hints: false,
duplicates: None,
}
}
}
pub fn render(
entries: &[CrapEntry],
opts: &RenderOptions,
out: &mut dyn Write,
) -> Result<()> {
let threshold = opts.threshold;
match opts.format {
Format::Json => json::render_json(entries, opts.diagnostics, opts.duplicates, out),
Format::Human => human::render_human(entries, threshold, opts.uncovered_hints, out),
Format::GitHub => github::render_github(entries, threshold, out),
Format::Markdown => {
markdown::render_markdown(entries, threshold, opts.links, opts.uncovered_hints, out)
},
Format::PrComment => {
pr_comment::render_pr_comment(entries, threshold, opts.links, opts.uncovered_hints, out)
},
Format::Sarif => sarif::render_sarif(entries, threshold, out),
Format::Shields => shields::render_shields(entries, threshold, out),
}
}
pub fn render_delta(
report: &DeltaReport,
opts: &RenderOptions,
out: &mut dyn Write,
) -> Result<()> {
let threshold = opts.threshold;
match opts.format {
Format::Json => json::render_delta_json(report, opts.diagnostics, opts.duplicates, out),
Format::Human => human::render_delta_human(
report,
threshold,
opts.show_unchanged,
opts.uncovered_hints,
out,
),
Format::GitHub => github::render_delta_github(report, threshold, out),
Format::Markdown => markdown::render_delta_markdown(
report,
threshold,
opts.links,
opts.show_unchanged,
opts.uncovered_hints,
out,
),
Format::PrComment => pr_comment::render_delta_pr_comment(
report,
threshold,
opts.links,
opts.uncovered_hints,
out,
),
Format::Sarif => bail!(
"--format sarif is incompatible with --baseline; use --format json for delta output"
),
Format::Shields => shields::render_delta_shields(report, threshold, out),
}
}
pub fn render_duplicates(
opts: &RenderOptions,
out: &mut dyn Write,
) -> Result<()> {
let Some(pairs) = opts.duplicates else {
return Ok(());
};
if !matches!(opts.format, Format::Human) {
return Ok(());
}
writeln!(out)?;
duplicates::render(pairs, out)
}
pub(crate) fn write_pr_comment_marker(out: &mut dyn Write) -> Result<()> {
writeln!(out, "<!-- cargo-crap-report -->")?;
writeln!(out)?;
Ok(())
}
#[must_use]
pub fn crappy_count(
entries: &[CrapEntry],
threshold: f64,
) -> usize {
entries
.iter()
.filter(|e| Severity::classify(e.crap, threshold) == Severity::Crappy)
.count()
}
#[cfg(test)]
mod tests {
use super::*;
use test_support::sample;
#[test]
fn crappy_count_respects_threshold() {
assert_eq!(crappy_count(&sample(), 30.0), 1);
assert_eq!(crappy_count(&sample(), 200.0), 0);
}
}