Skip to main content

callisto_graph/
infer.rs

1use std::path::PathBuf;
2
3use callisto_model::{CommitSha, Package, Severity, Version};
4use callisto_vcs::GitAccess;
5
6use crate::config::PreMajorInferencePolicy;
7use crate::error::GraphError;
8
9pub trait SeverityInference: Send + Sync {
10    /// `git` is the caller's already-discovered [`GitAccess`] (e.g.
11    /// `aggregate()`'s own parameter, itself `Workspace`-shared) -- an impl
12    /// that needs commit history must use this rather than discovering its
13    /// own, so an N-package workspace pays for one discovery, not N.
14    fn infer(
15        &self,
16        pkg: &Package,
17        git: &GitAccess<'_>,
18        window: InferenceWindowSpec<'_>,
19    ) -> Result<Option<InferenceOutcome>, GraphError>;
20}
21
22pub struct InferenceWindowSpec<'a> {
23    pub pathspecs: &'a [PathBuf],
24    pub since: Option<CommitSha>,
25    pub current_version: &'a Version,
26    pub has_prior_release: bool,
27    pub policy: PreMajorInferencePolicy,
28}
29
30#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct InferenceOutcome {
32    pub severity: Severity,
33    pub commit_count: usize,
34    pub remapped: bool,
35    pub commits: Vec<(CommitSha, String)>,
36}
37
38pub struct NoInference;
39
40impl SeverityInference for NoInference {
41    fn infer(
42        &self,
43        _pkg: &Package,
44        _git: &GitAccess<'_>,
45        _window: InferenceWindowSpec<'_>,
46    ) -> Result<Option<InferenceOutcome>, GraphError> {
47        Ok(None)
48    }
49}
50
51/// v0.2's impl, behind the `inference` feature. A thin, stateless adapter over
52/// `callisto_conventional::infer_severity` -- it holds no fields of its own; the caller's
53/// [`GitAccess`] is handed in per call via [`SeverityInference::infer`]'s `git` parameter
54/// rather than discovered here, so this type carries nothing to discover it with.
55#[cfg(feature = "inference")]
56pub struct CommitInference;
57
58#[cfg(feature = "inference")]
59impl SeverityInference for CommitInference {
60    fn infer(
61        &self,
62        pkg: &Package,
63        git: &GitAccess<'_>,
64        window: InferenceWindowSpec<'_>,
65    ) -> Result<Option<InferenceOutcome>, GraphError> {
66        use callisto_conventional::{infer_severity, InferenceInput, InferenceWindow};
67
68        let inf_window = match window.since {
69            Some(sha) => InferenceWindow::SinceCommit(sha),
70            None => InferenceWindow::FullHistory,
71        };
72
73        let input = InferenceInput {
74            package: &pkg.id,
75            pathspecs: window.pathspecs,
76            window: inf_window,
77            current_version: window.current_version,
78            has_prior_release: window.has_prior_release,
79        };
80
81        // Selecting the VCS backend is this layer's job now: callisto-conventional
82        // takes any `callisto_model::CommitWalker` and never names a VCS crate.
83        let raw = infer_severity(git, &input)?;
84        if raw.commit_count == 0 {
85            return Ok(None);
86        }
87
88        let (severity, remapped) = crate::aggregate::apply_pre_major(
89            raw.severity,
90            window.policy,
91            window.current_version,
92            window.has_prior_release,
93        );
94
95        let commits = raw
96            .commits
97            .into_iter()
98            .map(|c| (c.sha().clone(), c.subject().to_string()))
99            .collect();
100
101        Ok(Some(InferenceOutcome {
102            severity,
103            commit_count: raw.commit_count,
104            remapped,
105            commits,
106        }))
107    }
108}