emoji_commit_type/
lib.rs

1use std::fmt;
2use std::mem;
3
4/// A semver bump level
5#[derive(PartialEq, Eq, Copy, Clone, Debug)]
6pub enum BumpLevel {
7    Major,
8    Minor,
9    Patch,
10    None,
11}
12
13impl BumpLevel {
14    /// Return the name of this bump level
15    pub fn name(&self) -> &'static str {
16        match *self {
17            BumpLevel::Major => "Major",
18            BumpLevel::Minor => "Minor",
19            BumpLevel::Patch => "Patch",
20            BumpLevel::None => "None",
21        }
22    }
23}
24
25/// A specific commit type
26#[derive(PartialEq, Eq, Copy, Clone)]
27pub enum CommitType {
28    Breaking,
29    Feature,
30    Bugfix,
31    Other,
32    Meta,
33}
34
35/// Iterator over the different commit types
36pub struct CommitTypeIterator {
37    current: Option<CommitType>
38}
39
40impl CommitType {
41    /// Return the first commit type (Breaking)
42    pub fn first_variant() -> CommitType { CommitType::Breaking }
43
44    /// Return the last commit variant (Meta)
45    pub fn last_variant() -> CommitType { CommitType::Meta }
46
47    /// Given a commit type, return the next commit type
48    pub fn next_variant(&self) -> Option<CommitType> {
49        match *self {
50            CommitType::Breaking => Some(CommitType::Feature),
51            CommitType::Feature => Some(CommitType::Bugfix),
52            CommitType::Bugfix => Some(CommitType::Other),
53            CommitType::Other => Some(CommitType::Meta),
54            CommitType::Meta => None,
55        }
56    }
57
58    /// Given a commit type, return the previous commit type
59    pub fn prev_variant(&self) -> Option<CommitType> {
60        match *self {
61            CommitType::Breaking => None,
62            CommitType::Feature => Some(CommitType::Breaking),
63            CommitType::Bugfix => Some(CommitType::Feature),
64            CommitType::Other => Some(CommitType::Bugfix),
65            CommitType::Meta => Some(CommitType::Other),
66        }
67    }
68
69    /// Return an iterator over all commit types
70    pub fn iter_variants() -> CommitTypeIterator {
71        CommitTypeIterator { current: Some(CommitType::first_variant()) }
72    }
73
74    /// Return the emoji for this commit type
75    pub fn emoji(&self) -> &'static str {
76        match *self {
77            CommitType::Breaking => "💥",
78            CommitType::Feature => "🎉",
79            CommitType::Bugfix => "🐛",
80            CommitType::Other => "🔥",
81            CommitType::Meta => "🌹",
82        }
83    }
84
85    /// Return the bump level for this commit type
86    pub fn bump_level(&self) -> BumpLevel {
87        match *self {
88            CommitType::Breaking => BumpLevel::Major,
89            CommitType::Feature => BumpLevel::Minor,
90            CommitType::Bugfix => BumpLevel::Patch,
91            CommitType::Other => BumpLevel::Patch,
92            CommitType::Meta => BumpLevel::None,
93        }
94    }
95
96    /// Return the description for this commit type
97    pub fn description(&self) -> &'static str {
98        match *self {
99            CommitType::Breaking => "Breaking change",
100            CommitType::Feature => "New functionality",
101            CommitType::Bugfix => "Bugfix",
102            CommitType::Other => "Cleanup / Performance",
103            CommitType::Meta => "Meta",
104        }
105    }
106}
107
108impl fmt::Debug for CommitType {
109    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110        write!(f, "CommitType {{ {} }}", self.emoji())
111    }
112}
113
114impl Iterator for CommitTypeIterator {
115    type Item = CommitType;
116
117    fn next(&mut self) -> Option<CommitType> {
118        match self.current {
119            Some(commit_type) => mem::replace(&mut self.current, commit_type.next_variant()),
120            None => None,
121        }
122    }
123
124    fn size_hint(&self) -> (usize, Option<usize>) {
125        match self.current {
126            Some(CommitType::Breaking) => (5, Some(5)),
127            Some(CommitType::Feature) => (4, Some(4)),
128            Some(CommitType::Bugfix) => (3, Some(3)),
129            Some(CommitType::Other) => (2, Some(2)),
130            Some(CommitType::Meta) => (1, Some(1)),
131            None => (0, Some(0)),
132        }
133    }
134}
135
136impl ExactSizeIterator for CommitTypeIterator {
137    fn len(&self) -> usize {
138        5
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use super::{CommitType, BumpLevel};
145
146    #[test]
147    fn it_gives_the_first_type() {
148        assert_eq!(CommitType::first_variant(), CommitType::Breaking);
149    }
150
151    #[test]
152    fn it_gives_the_last_type() {
153        assert_eq!(CommitType::last_variant(), CommitType::Meta);
154    }
155
156    #[test]
157    fn it_gives_the_next_type() {
158        assert_eq!(CommitType::Breaking.next_variant(), Some(CommitType::Feature));
159        assert_eq!(CommitType::Feature.next_variant(), Some(CommitType::Bugfix));
160        assert_eq!(CommitType::Bugfix.next_variant(), Some(CommitType::Other));
161        assert_eq!(CommitType::Other.next_variant(), Some(CommitType::Meta));
162        assert_eq!(CommitType::Meta.next_variant(), None);
163    }
164
165    #[test]
166    fn it_gives_the_previous_type() {
167        assert_eq!(CommitType::Breaking.prev_variant(), None);
168        assert_eq!(CommitType::Feature.prev_variant(), Some(CommitType::Breaking));
169        assert_eq!(CommitType::Bugfix.prev_variant(), Some(CommitType::Feature));
170        assert_eq!(CommitType::Other.prev_variant(), Some(CommitType::Bugfix));
171        assert_eq!(CommitType::Meta.prev_variant(), Some(CommitType::Other));
172    }
173
174    #[test]
175    fn it_gives_an_variant_iterator() {
176        let mut iter = CommitType::iter_variants();
177
178        assert_eq!(iter.next(), Some(CommitType::Breaking));
179        assert_eq!(iter.next(), Some(CommitType::Feature));
180        assert_eq!(iter.next(), Some(CommitType::Bugfix));
181        assert_eq!(iter.next(), Some(CommitType::Other));
182        assert_eq!(iter.next(), Some(CommitType::Meta));
183        assert_eq!(iter.next(), None);
184    }
185
186    #[test]
187    fn it_gives_an_emoji() {
188        assert_eq!(CommitType::Breaking.emoji(), "💥");
189        assert_eq!(CommitType::Feature.emoji(), "🎉");
190        assert_eq!(CommitType::Bugfix.emoji(), "🐛");
191        assert_eq!(CommitType::Other.emoji(), "🔥");
192        assert_eq!(CommitType::Meta.emoji(), "🌹");
193    }
194
195    #[test]
196    fn it_gives_a_bump_level() {
197        assert_eq!(CommitType::Breaking.bump_level(), BumpLevel::Major);
198        assert_eq!(CommitType::Feature.bump_level(), BumpLevel::Minor);
199        assert_eq!(CommitType::Bugfix.bump_level(), BumpLevel::Patch);
200        assert_eq!(CommitType::Other.bump_level(), BumpLevel::Patch);
201        assert_eq!(CommitType::Meta.bump_level(), BumpLevel::None);
202    }
203
204    #[test]
205    fn it_gives_a_bump_level_name() {
206        assert_eq!(CommitType::Breaking.bump_level().name(), "Major");
207        assert_eq!(CommitType::Feature.bump_level().name(), "Minor");
208        assert_eq!(CommitType::Bugfix.bump_level().name(), "Patch");
209        assert_eq!(CommitType::Meta.bump_level().name(), "None");
210    }
211
212    #[test]
213    fn it_gives_a_description() {
214        assert_eq!(CommitType::Breaking.description(), "Breaking change");
215        assert_eq!(CommitType::Feature.description(), "New functionality");
216        assert_eq!(CommitType::Bugfix.description(), "Bugfix");
217        assert_eq!(CommitType::Other.description(), "Cleanup / Performance");
218        assert_eq!(CommitType::Meta.description(), "Meta");
219    }
220}