changeset_operations/verification/rules/
none_bump.rs1use 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}