knope_versioning/changes/
mod.rs

1use std::{fmt::Display, sync::Arc};
2
3pub use changeset::CHANGESET_DIR;
4use git_conventional::FooterToken;
5
6use crate::{
7    package,
8    release_notes::{CommitFooter, CustomChangeType, SectionSource},
9};
10
11mod changeset;
12pub mod conventional_commit;
13
14/// A change to one or more packages.
15#[derive(Clone, Debug, Eq, PartialEq)]
16pub struct Change {
17    pub change_type: ChangeType,
18    pub description: Arc<str>,
19    pub original_source: ChangeSource,
20}
21
22impl Change {
23    pub fn from_changesets<'a>(
24        package_name: &'a package::Name,
25        releases: &'a [changesets::Release],
26    ) -> impl Iterator<Item = Self> + 'a {
27        releases
28            .iter()
29            .find(|release| *package_name == release.package_name)
30            .into_iter()
31            .flat_map(|release_changes| release_changes.changes.clone().into_iter().map(Self::from))
32    }
33}
34
35impl From<changesets::PackageChange> for Change {
36    fn from(package_change: changesets::PackageChange) -> Self {
37        Self {
38            change_type: package_change.change_type.into(),
39            description: package_change.summary,
40            original_source: ChangeSource::ChangeFile(package_change.unique_id),
41        }
42    }
43}
44
45#[derive(Clone, Debug, Hash, Eq, PartialEq)]
46pub enum ChangeType {
47    Breaking,
48    Feature,
49    Fix,
50    Custom(SectionSource),
51}
52
53impl ChangeType {
54    #[must_use]
55    pub fn to_changeset_type(&self) -> Option<changesets::ChangeType> {
56        match self {
57            Self::Breaking => Some(changesets::ChangeType::Major),
58            Self::Feature => Some(changesets::ChangeType::Minor),
59            Self::Fix => Some(changesets::ChangeType::Patch),
60            Self::Custom(SectionSource::CustomChangeType(custom)) => {
61                Some(changesets::ChangeType::Custom(custom.to_string()))
62            }
63            Self::Custom(SectionSource::CommitFooter(_)) => None,
64        }
65    }
66}
67
68impl From<ChangeType> for changesets::ChangeType {
69    fn from(value: ChangeType) -> Self {
70        match value {
71            ChangeType::Breaking => Self::Major,
72            ChangeType::Feature => Self::Minor,
73            ChangeType::Fix => Self::Patch,
74            ChangeType::Custom(custom) => Self::Custom(custom.to_string()),
75        }
76    }
77}
78
79impl From<&changesets::ChangeType> for ChangeType {
80    fn from(value: &changesets::ChangeType) -> Self {
81        match value {
82            changesets::ChangeType::Major => Self::Breaking,
83            changesets::ChangeType::Minor => Self::Feature,
84            changesets::ChangeType::Patch => Self::Fix,
85            changesets::ChangeType::Custom(custom) => {
86                Self::Custom(SectionSource::CustomChangeType(custom.clone().into()))
87            }
88        }
89    }
90}
91
92impl From<CustomChangeType> for ChangeType {
93    fn from(custom: CustomChangeType) -> Self {
94        changesets::ChangeType::from(String::from(custom)).into()
95    }
96}
97
98impl From<changesets::ChangeType> for ChangeType {
99    fn from(change_type: changesets::ChangeType) -> Self {
100        match change_type {
101            changesets::ChangeType::Major => Self::Breaking,
102            changesets::ChangeType::Minor => Self::Feature,
103            changesets::ChangeType::Patch => Self::Fix,
104            changesets::ChangeType::Custom(custom) => {
105                Self::Custom(SectionSource::CustomChangeType(custom.into()))
106            }
107        }
108    }
109}
110
111impl From<CommitFooter> for ChangeType {
112    fn from(footer: CommitFooter) -> Self {
113        Self::Custom(SectionSource::CommitFooter(footer))
114    }
115}
116
117impl From<FooterToken<'_>> for ChangeType {
118    fn from(footer: FooterToken) -> Self {
119        if footer.breaking() {
120            Self::Breaking
121        } else {
122            Self::Custom(SectionSource::CommitFooter(CommitFooter::from(footer)))
123        }
124    }
125}
126
127#[derive(Clone, Debug, Eq, PartialEq)]
128pub enum ChangeSource {
129    ConventionalCommit(String),
130    ChangeFile(Arc<changesets::UniqueId>),
131}
132
133impl Display for ChangeSource {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        match self {
136            Self::ConventionalCommit(commit) => write!(f, "commit {commit}"),
137            Self::ChangeFile(id) => write!(f, "changeset {}", id.to_file_name()),
138        }
139    }
140}