cuddle_please_misc/versioning/
next_version.rs1use semver::{Prerelease, Version};
2
3use super::conventional_parse::VersionIncrement;
4
5pub trait NextVersion {
6 fn next<I>(&self, commits: I) -> Self
7 where
8 I: IntoIterator,
9 I::Item: AsRef<str>;
10}
11
12impl NextVersion for Version {
13 fn next<I>(&self, commits: I) -> Self
14 where
15 I: IntoIterator,
16 I::Item: AsRef<str>,
17 {
18 let increment = VersionIncrement::from(self, commits);
19
20 match increment {
21 Some(increment) => match increment {
22 VersionIncrement::Major => Self {
23 major: self.major + 1,
24 minor: 0,
25 patch: 0,
26 pre: Prerelease::EMPTY,
27 ..self.clone()
28 },
29 VersionIncrement::Minor => Self {
30 minor: self.minor + 1,
31 patch: 0,
32 pre: Prerelease::EMPTY,
33 ..self.clone()
34 },
35 VersionIncrement::Patch => Self {
36 patch: self.patch + 1,
37 pre: Prerelease::EMPTY,
38 ..self.clone()
39 },
40 VersionIncrement::Prerelease => Self {
41 pre: {
42 let release = &self.pre;
43 let release_version = match release.rsplit_once('.') {
44 Some((tag, version)) => match version.parse::<usize>() {
45 Ok(version) => format!("{tag}.{}", version + 1),
46 Err(_) => format!("{tag}.1"),
47 },
48 None => format!("{release}.1"),
49 };
50 Prerelease::new(&release_version).expect("prerelease is not valid semver")
51 },
52 ..self.clone()
53 },
54 },
55 None => self.clone(),
56 }
57 }
58}
59
60#[cfg(test)]
61mod test {
62 use semver::Version;
63 use tracing_test::traced_test;
64
65 use crate::versioning::next_version::NextVersion;
66
67 #[test]
68 #[traced_test]
69 fn is_no_bump() {
70 let version = Version::parse("0.0.0-prerelease").unwrap();
71 let commits: Vec<&str> = vec![];
72
73 let actual = version.next(commits);
74
75 assert_eq!("0.0.0-prerelease", actual.to_string())
76 }
77
78 #[test]
79 #[traced_test]
80 fn is_prerelease_initial() {
81 let version = Version::parse("0.0.0-prerelease").unwrap();
82 let commits: Vec<&str> = vec!["feat: something"];
83
84 let actual = version.next(commits);
85
86 assert_eq!("0.0.0-prerelease.1", actual.to_string())
87 }
88
89 #[test]
90 #[traced_test]
91 fn is_prerelease_invalid() {
92 let version = Version::parse("0.0.0-prerelease.invalid").unwrap();
93 let commits: Vec<&str> = vec!["feat: something"];
94
95 let actual = version.next(commits);
96
97 assert_eq!("0.0.0-prerelease.1", actual.to_string())
98 }
99
100 #[test]
101 #[traced_test]
102 fn is_prerelease_next() {
103 let version = Version::parse("0.0.0-prerelease.1").unwrap();
104 let commits: Vec<&str> = vec!["feat: something"];
105
106 let actual = version.next(commits);
107
108 assert_eq!("0.0.0-prerelease.2", actual.to_string())
109 }
110
111 #[test]
112 #[traced_test]
113 fn is_patch() {
114 let version = Version::parse("0.0.0").unwrap();
115 let commits: Vec<&str> = vec!["fix: something"];
116
117 let actual = version.next(commits);
118
119 assert_eq!("0.0.1", actual.to_string())
120 }
121
122 #[test]
123 #[traced_test]
124 fn is_minor() {
125 let version = Version::parse("0.1.0").unwrap();
126 let commits: Vec<&str> = vec!["feat: something"];
127
128 let actual = version.next(commits);
129
130 assert_eq!("0.2.0", actual.to_string())
131 }
132 #[test]
133 #[traced_test]
134 fn is_minor_clears_patch() {
135 let version = Version::parse("0.1.1").unwrap();
136 let commits: Vec<&str> = vec!["feat: something"];
137
138 let actual = version.next(commits);
139
140 assert_eq!("0.2.0", actual.to_string())
141 }
142 #[test]
143 #[traced_test]
144 fn is_major() {
145 let version = Version::parse("0.0.0").unwrap();
146 let commits: Vec<&str> = vec![
147 "feat: something
148
149 BREAKING CHANGE: something",
150 ];
151
152 let actual = version.next(commits);
153
154 assert_eq!("1.0.0", actual.to_string())
155 }
156 #[test]
157 #[traced_test]
158 fn is_major_clears_minor_patch() {
159 let version = Version::parse("1.2.3").unwrap();
160 let commits: Vec<&str> = vec![
161 "feat: something
162
163 BREAKING CHANGE: something",
164 ];
165
166 let actual = version.next(commits);
167
168 assert_eq!("2.0.0", actual.to_string())
169 }
170}