Skip to main content

knope_versioning/
action.rs

1use std::str::FromStr;
2
3use relative_path::RelativePathBuf;
4
5use crate::{package, release_notes::Release, semver::Version};
6
7/// Actions to take to finish updating a package
8#[derive(Clone, Debug, Eq, Hash, PartialEq)]
9pub enum Action {
10    WriteToFile {
11        path: RelativePathBuf,
12        content: String,
13        diff: String,
14    },
15    RemoveFile {
16        path: RelativePathBuf,
17    },
18    AddTag {
19        tag: String,
20    },
21    CreateRelease(Release),
22}
23
24#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct ReleaseTag(String);
26
27impl ReleaseTag {
28    /// The tag that a particular version should have for a particular package
29    #[must_use]
30    pub fn new(version: &Version, package_name: &package::Name) -> Self {
31        let prefix = Self::tag_prefix(package_name);
32        Self(format!("{prefix}{version}"))
33    }
34
35    #[must_use]
36    pub fn is_release_tag(val: &str, package_name: &package::Name) -> bool {
37        let tag_prefix = Self::tag_prefix(package_name);
38        val.strip_prefix(&tag_prefix)
39            .and_then(|version_str| Version::from_str(version_str).ok())
40            .is_some()
41    }
42
43    /// The prefix for tags for a particular package
44    fn tag_prefix(package_name: &package::Name) -> String {
45        package_name
46            .as_custom()
47            .as_ref()
48            .map_or_else(|| "v".to_string(), |name| format!("{name}/v"))
49    }
50
51    #[must_use]
52    pub fn as_str(&self) -> &str {
53        &self.0
54    }
55}
56
57impl From<ReleaseTag> for String {
58    fn from(tag: ReleaseTag) -> Self {
59        tag.0
60    }
61}
62
63pub(crate) enum ActionSet {
64    Single(Action),
65    Two([Action; 2]),
66}
67
68impl IntoIterator for ActionSet {
69    type Item = Action;
70    type IntoIter = ActionSetIter;
71
72    fn into_iter(self) -> Self::IntoIter {
73        ActionSetIter {
74            actions: Some(self),
75        }
76    }
77}
78
79#[allow(clippy::module_name_repetitions)]
80pub struct ActionSetIter {
81    actions: Option<ActionSet>,
82}
83
84impl Iterator for ActionSetIter {
85    type Item = Action;
86
87    fn next(&mut self) -> Option<Self::Item> {
88        match self.actions.take() {
89            None => None,
90            Some(ActionSet::Single(action)) => {
91                self.actions = None;
92                Some(action)
93            }
94            Some(ActionSet::Two([first, second])) => {
95                self.actions = None;
96                self.actions = Some(ActionSet::Single(second));
97                Some(first)
98            }
99        }
100    }
101}