Skip to main content

changeset_operations/verification/rules/
none_bump.rs

1use changeset_core::Changeset;
2
3use super::{VerificationContext, VerificationResult, VerificationRule};
4use crate::Result;
5use crate::traits::ChangesetReader;
6
7pub struct NoneBumpDisallowedRule<'a, R: ChangesetReader> {
8    reader: &'a R,
9}
10
11impl<'a, R: ChangesetReader> NoneBumpDisallowedRule<'a, R> {
12    pub fn new(reader: &'a R) -> Self {
13        Self { reader }
14    }
15}
16
17impl<R: ChangesetReader> VerificationRule for NoneBumpDisallowedRule<'_, R> {
18    fn check(&self, context: &VerificationContext, result: &mut VerificationResult) -> Result<()> {
19        let changesets: Vec<Changeset> = context
20            .changeset_files()
21            .iter()
22            .map(|path| self.reader.read_changeset(path))
23            .collect::<Result<Vec<_>>>()?;
24
25        result.set_none_bump_violations(crate::none_bump::find_none_only_packages(&changesets));
26
27        Ok(())
28    }
29}
30
31#[cfg(test)]
32mod tests {
33    use std::path::PathBuf;
34
35    use anyhow::Result;
36    use changeset_core::{BumpType, ChangeCategory, Changeset, PackageRelease};
37
38    use super::*;
39    use crate::verification::{VerificationContext, VerificationResult};
40
41    fn make_changeset(name: &str, bump: BumpType, summary: &str) -> Changeset {
42        Changeset::new(
43            summary.to_string(),
44            vec![PackageRelease::new(name.to_string(), bump)],
45            ChangeCategory::Changed,
46        )
47    }
48
49    fn empty_result() -> VerificationResult {
50        VerificationResult::new(
51            Vec::new(),
52            std::collections::HashSet::new(),
53            Vec::new(),
54            Vec::new(),
55        )
56    }
57
58    #[test]
59    fn disallow_rule_detects_none_bump_packages() -> Result<()> {
60        let reader = crate::mocks::MockChangesetReader::new().with_changeset(
61            PathBuf::from("a.md"),
62            make_changeset("my-crate", BumpType::None, "Internal change"),
63        );
64
65        let rule = NoneBumpDisallowedRule::new(&reader);
66
67        let context = VerificationContext::new(
68            Vec::new(),
69            std::collections::HashSet::new(),
70            vec![PathBuf::from("a.md")],
71            Vec::new(),
72            Vec::new(),
73            Vec::new(),
74        );
75
76        let mut result = empty_result();
77        rule.check(&context, &mut result)?;
78
79        assert_eq!(result.none_bump_violations(), &vec!["my-crate".to_string()]);
80        assert!(!result.is_success());
81        Ok(())
82    }
83
84    #[test]
85    fn disallow_rule_permits_non_none_packages() -> Result<()> {
86        let reader = crate::mocks::MockChangesetReader::new().with_changeset(
87            PathBuf::from("a.md"),
88            make_changeset("my-crate", BumpType::Patch, "Fix bug"),
89        );
90
91        let rule = NoneBumpDisallowedRule::new(&reader);
92
93        let context = VerificationContext::new(
94            Vec::new(),
95            std::collections::HashSet::new(),
96            vec![PathBuf::from("a.md")],
97            Vec::new(),
98            Vec::new(),
99            Vec::new(),
100        );
101
102        let mut result = empty_result();
103        rule.check(&context, &mut result)?;
104
105        assert!(result.none_bump_violations().is_empty());
106        Ok(())
107    }
108
109    #[test]
110    fn disallow_rule_permits_mixed_bumps_across_changesets() -> Result<()> {
111        let reader = crate::mocks::MockChangesetReader::new()
112            .with_changeset(
113                PathBuf::from("a.md"),
114                make_changeset("my-crate", BumpType::None, "Internal"),
115            )
116            .with_changeset(
117                PathBuf::from("b.md"),
118                make_changeset("my-crate", BumpType::Patch, "Fix bug"),
119            );
120
121        let rule = NoneBumpDisallowedRule::new(&reader);
122
123        let context = VerificationContext::new(
124            Vec::new(),
125            std::collections::HashSet::new(),
126            vec![PathBuf::from("a.md"), PathBuf::from("b.md")],
127            Vec::new(),
128            Vec::new(),
129            Vec::new(),
130        );
131
132        let mut result = empty_result();
133        rule.check(&context, &mut result)?;
134
135        assert!(result.none_bump_violations().is_empty());
136        Ok(())
137    }
138}