knope_versioning/release_notes/
config.rs1use std::{fmt, fmt::Display};
2
3use git_conventional::FooterToken;
4use serde::{Deserialize, Serialize};
5
6use crate::changes::ChangeType;
7
8#[derive(Clone, Debug, Hash, Eq, PartialEq)]
11pub enum SectionSource {
12 CommitFooter(CommitFooter),
13 CustomChangeType(CustomChangeType),
14}
15
16impl From<CommitFooter> for SectionSource {
17 fn from(footer: CommitFooter) -> Self {
18 Self::CommitFooter(footer)
19 }
20}
21
22impl From<CustomChangeType> for SectionSource {
23 fn from(change_type: CustomChangeType) -> Self {
24 Self::CustomChangeType(change_type)
25 }
26}
27
28impl Display for SectionSource {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self {
31 Self::CommitFooter(footer) => footer.fmt(f),
32 Self::CustomChangeType(change_type) => change_type.fmt(f),
33 }
34 }
35}
36
37#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
40#[serde(transparent)]
41pub struct CustomChangeType(String);
42
43impl PartialEq<str> for CustomChangeType {
44 fn eq(&self, other: &str) -> bool {
45 self.0 == other
46 }
47}
48
49#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
50#[serde(transparent)]
51pub struct CommitFooter(String);
52
53impl Display for CommitFooter {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "{}", self.0)
56 }
57}
58
59impl From<&str> for CommitFooter {
60 fn from(token: &str) -> Self {
61 Self(token.into())
62 }
63}
64
65impl From<FooterToken<'_>> for CommitFooter {
66 fn from(token: FooterToken) -> Self {
67 Self(token.as_str().into())
68 }
69}
70
71impl Display for CustomChangeType {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(f, "{}", self.0)
74 }
75}
76
77impl From<String> for CustomChangeType {
78 fn from(token: String) -> Self {
79 Self(token)
80 }
81}
82
83impl From<&str> for CustomChangeType {
84 fn from(token: &str) -> Self {
85 Self(token.into())
86 }
87}
88
89impl From<CustomChangeType> for String {
90 fn from(custom: CustomChangeType) -> Self {
91 custom.0
92 }
93}
94
95#[derive(Clone, Debug, Eq, PartialEq)]
96pub struct Sections(pub Vec<(SectionName, Vec<ChangeType>)>);
97
98impl Sections {
99 #[must_use]
100 pub fn defaults() -> Vec<(SectionName, ChangeType)> {
101 vec![
102 (SectionName::from("Breaking Changes"), ChangeType::Breaking),
103 (SectionName::from("Features"), ChangeType::Feature),
104 (SectionName::from("Fixes"), ChangeType::Fix),
105 ("Notes".into(), CommitFooter::from("Changelog-Note").into()),
106 ]
107 }
108
109 pub fn iter(&self) -> impl Iterator<Item = &(SectionName, Vec<ChangeType>)> {
110 self.0.iter()
111 }
112
113 #[allow(dead_code)]
114 pub(crate) fn is_default(&self) -> bool {
115 let defaults = Self::defaults();
116 self.0.iter().enumerate().all(|(index, (name, sources))| {
117 if sources.len() != 1 {
118 return false;
119 }
120 sources.first().is_some_and(|source| {
121 defaults
122 .get(index)
123 .is_some_and(|(default_name, default_source)| {
124 name == default_name && source == default_source
125 })
126 })
127 })
128 }
129
130 pub(crate) fn contains_footer(&self, footer: &git_conventional::Footer) -> bool {
131 self.0.iter().any(|(_, sources)| {
132 sources.iter().any(|source| match source {
133 ChangeType::Custom(SectionSource::CommitFooter(footer_token)) => {
134 footer_token.0.eq_ignore_ascii_case(footer.token().as_str())
135 }
136 _ => false,
137 })
138 })
139 }
140}
141
142impl Default for Sections {
143 fn default() -> Self {
144 Self(
145 Self::defaults()
146 .into_iter()
147 .map(|(name, source)| (name, vec![source]))
148 .collect(),
149 )
150 }
151}
152
153impl IntoIterator for Sections {
154 type Item = (SectionName, Vec<ChangeType>);
155 type IntoIter = std::vec::IntoIter<Self::Item>;
156
157 fn into_iter(self) -> Self::IntoIter {
158 self.0.into_iter()
159 }
160}
161
162#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
163#[serde(transparent)]
164pub struct SectionName(String);
165
166impl Display for SectionName {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 write!(f, "{}", self.0)
169 }
170}
171
172impl From<&str> for SectionName {
173 fn from(token: &str) -> Self {
174 Self(token.into())
175 }
176}
177
178impl AsRef<str> for SectionName {
179 fn as_ref(&self) -> &str {
180 &self.0
181 }
182}