wtg_cli/
release_filter.rs1use crate::git::TagInfo;
7
8#[derive(Debug, Clone, Default)]
10pub enum ReleaseFilter {
11 #[default]
13 Unrestricted,
14 SkipPrereleases,
16 Specific(String),
18}
19
20impl ReleaseFilter {
21 #[must_use]
25 pub fn filter_tags(&self, tags: Vec<TagInfo>) -> Vec<TagInfo> {
26 match self {
27 Self::Unrestricted => tags,
28 Self::SkipPrereleases => tags
29 .into_iter()
30 .filter(|t| {
31 t.semver_info
34 .as_ref()
35 .is_none_or(|s| s.pre_release.is_none())
36 })
37 .collect(),
38 Self::Specific(name) => tags.into_iter().filter(|t| t.name == *name).collect(),
39 }
40 }
41
42 #[must_use]
44 pub fn specific_tag(&self) -> Option<&str> {
45 match self {
46 Self::Specific(name) => Some(name),
47 _ => None,
48 }
49 }
50
51 #[must_use]
53 pub const fn skips_prereleases(&self) -> bool {
54 matches!(self, Self::SkipPrereleases)
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use crate::semver::parse_semver;
62 use chrono::Utc;
63
64 fn make_tag(name: &str) -> TagInfo {
65 TagInfo {
66 name: name.to_string(),
67 commit_hash: "abc123".to_string(),
68 semver_info: parse_semver(name),
69 created_at: Utc::now(),
70 is_release: false,
71 release_name: None,
72 release_url: None,
73 published_at: None,
74 tag_url: None,
75 }
76 }
77
78 #[test]
79 fn unrestricted_keeps_all_tags() {
80 let tags = vec![
81 make_tag("v1.0.0"),
82 make_tag("v1.1.0-beta.1"),
83 make_tag("v2.0.0-rc.1"),
84 make_tag("release-2024"),
85 ];
86 let filter = ReleaseFilter::Unrestricted;
87 let result = filter.filter_tags(tags);
88 assert_eq!(result.len(), 4);
89 }
90
91 #[test]
92 fn skip_prereleases_filters_correctly() {
93 let tags = vec![
94 make_tag("v1.0.0"),
95 make_tag("v1.1.0-beta.1"),
96 make_tag("v2.0.0-rc.1"),
97 make_tag("release-2024"), ];
99 let filter = ReleaseFilter::SkipPrereleases;
100 let result = filter.filter_tags(tags);
101 assert_eq!(result.len(), 2);
102 assert!(result.iter().any(|t| t.name == "v1.0.0"));
103 assert!(result.iter().any(|t| t.name == "release-2024"));
104 }
105
106 #[test]
107 fn specific_filters_to_one_tag() {
108 let tags = vec![make_tag("v1.0.0"), make_tag("v1.1.0"), make_tag("v2.0.0")];
109 let filter = ReleaseFilter::Specific("v1.1.0".to_string());
110 let result = filter.filter_tags(tags);
111 assert_eq!(result.len(), 1);
112 assert_eq!(result[0].name, "v1.1.0");
113 }
114
115 #[test]
116 fn specific_returns_empty_if_not_found() {
117 let tags = vec![make_tag("v1.0.0"), make_tag("v2.0.0")];
118 let filter = ReleaseFilter::Specific("v99.0.0".to_string());
119 let result = filter.filter_tags(tags);
120 assert!(result.is_empty());
121 }
122
123 #[test]
124 fn specific_tag_returns_name() {
125 let filter = ReleaseFilter::Specific("v1.0.0".to_string());
126 assert_eq!(filter.specific_tag(), Some("v1.0.0"));
127
128 let filter = ReleaseFilter::Unrestricted;
129 assert_eq!(filter.specific_tag(), None);
130
131 let filter = ReleaseFilter::SkipPrereleases;
132 assert_eq!(filter.specific_tag(), None);
133 }
134
135 #[test]
136 fn skips_prereleases_helper() {
137 assert!(!ReleaseFilter::Unrestricted.skips_prereleases());
138 assert!(ReleaseFilter::SkipPrereleases.skips_prereleases());
139 assert!(!ReleaseFilter::Specific("v1.0.0".to_string()).skips_prereleases());
140 }
141}