Skip to main content

dev_deps/
producer.rs

1//! [`Producer`] integration: wrap a [`DepCheck`] and emit a [`Report`]
2//! every time the producer runs.
3//!
4//! [`Producer`]: dev_report::Producer
5//! [`Report`]: dev_report::Report
6
7use dev_report::{CheckResult, Producer, Report, Severity};
8
9use crate::DepCheck;
10
11/// `Producer` adapter that runs a [`DepCheck`] and converts the result
12/// into a `Report`.
13///
14/// Subprocess failures map to a single failing `CheckResult` named
15/// `deps::health` with `Severity::Critical` — no panics.
16///
17/// # Example
18///
19/// ```no_run
20/// use dev_deps::{DepCheck, DepProducer, DepScope};
21/// use dev_report::Producer;
22///
23/// let producer = DepProducer::new(
24///     DepCheck::new("my-crate", "0.1.0").scope(DepScope::All),
25/// );
26/// let report = producer.produce();
27/// println!("{}", report.to_json().unwrap());
28/// ```
29pub struct DepProducer {
30    check: DepCheck,
31}
32
33impl DepProducer {
34    /// Build a producer that drives the given [`DepCheck`].
35    pub fn new(check: DepCheck) -> Self {
36        Self { check }
37    }
38}
39
40impl Producer for DepProducer {
41    fn produce(&self) -> Report {
42        match self.check.execute() {
43            Ok(result) => result.into_report(),
44            Err(e) => {
45                let mut report = Report::new(self.check.subject(), self.check.subject_version())
46                    .with_producer("dev-deps");
47                let check = CheckResult::fail("deps::health", Severity::Critical)
48                    .with_detail(e.to_string())
49                    .with_tag("deps")
50                    .with_tag("subprocess");
51                report.push(check);
52                report.finish();
53                report
54            }
55        }
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::DepScope;
63
64    #[test]
65    fn produce_returns_report_when_tool_missing() {
66        // Default runner image won't have cargo-udeps + cargo-outdated
67        // installed; the producer should surface that as a failing
68        // CheckResult rather than panicking.
69        let producer = DepProducer::new(DepCheck::new("self", "0.0.0").scope(DepScope::Unused));
70        let report = producer.produce();
71        assert_eq!(report.subject, "self");
72        assert!(!report.checks.is_empty());
73    }
74}