1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub enum MetadataSection {
3 Workspace,
4 Package,
5}
6
7impl std::fmt::Display for MetadataSection {
8 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9 match self {
10 Self::Workspace => f.write_str("[workspace.metadata.changeset]"),
11 Self::Package => f.write_str("[package.metadata.changeset]"),
12 }
13 }
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
17#[non_exhaustive]
18pub enum TagFormat {
19 #[default]
20 VersionOnly,
21 CratePrefixed,
22}
23
24impl TagFormat {
25 #[must_use]
26 pub const fn as_str(self) -> &'static str {
27 match self {
28 Self::VersionOnly => "version-only",
29 Self::CratePrefixed => "crate-prefixed",
30 }
31 }
32}
33
34impl std::fmt::Display for TagFormat {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 f.write_str(self.as_str())
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
41#[non_exhaustive]
42pub enum ChangelogLocation {
43 #[default]
44 Root,
45 PerPackage,
46}
47
48impl ChangelogLocation {
49 #[must_use]
50 pub const fn as_str(self) -> &'static str {
51 match self {
52 Self::Root => "root",
53 Self::PerPackage => "per-package",
54 }
55 }
56}
57
58impl std::fmt::Display for ChangelogLocation {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 f.write_str(self.as_str())
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
65#[non_exhaustive]
66pub enum ComparisonLinks {
67 #[default]
68 Auto,
69 Enabled,
70 Disabled,
71}
72
73impl ComparisonLinks {
74 #[must_use]
75 pub const fn as_str(self) -> &'static str {
76 match self {
77 Self::Auto => "auto",
78 Self::Enabled => "enabled",
79 Self::Disabled => "disabled",
80 }
81 }
82}
83
84impl std::fmt::Display for ComparisonLinks {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 f.write_str(self.as_str())
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
91#[non_exhaustive]
92pub enum ZeroVersionBehavior {
93 #[default]
94 EffectiveMinor,
95 AutoPromoteOnMajor,
96}
97
98impl ZeroVersionBehavior {
99 #[must_use]
100 pub const fn as_str(self) -> &'static str {
101 match self {
102 Self::EffectiveMinor => "effective-minor",
103 Self::AutoPromoteOnMajor => "auto-promote-on-major",
104 }
105 }
106}
107
108impl std::fmt::Display for ZeroVersionBehavior {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 f.write_str(self.as_str())
111 }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
115#[non_exhaustive]
116pub enum NoneBumpBehavior {
117 #[default]
118 PromoteToPatch,
119 Allow,
120 Disallow,
121}
122
123impl NoneBumpBehavior {
124 #[must_use]
125 pub const fn as_str(self) -> &'static str {
126 match self {
127 Self::PromoteToPatch => "promote-to-patch",
128 Self::Allow => "allow",
129 Self::Disallow => "disallow",
130 }
131 }
132}
133
134impl std::fmt::Display for NoneBumpBehavior {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 f.write_str(self.as_str())
137 }
138}
139
140#[derive(Debug, Clone, Default)]
141pub struct InitConfig {
142 pub commit: Option<bool>,
143 pub tags: Option<bool>,
144 pub keep_changesets: Option<bool>,
145 pub tag_format: Option<TagFormat>,
146 pub changelog: Option<ChangelogLocation>,
147 pub comparison_links: Option<ComparisonLinks>,
148 pub zero_version_behavior: Option<ZeroVersionBehavior>,
149 pub dependency_bump_changelog_template: Option<String>,
150 pub base_branch: Option<String>,
151 pub none_bump_behavior: Option<NoneBumpBehavior>,
152 pub none_bump_promote_message_template: Option<String>,
153 pub commit_title_template: Option<String>,
154 pub changes_in_body: Option<bool>,
155 pub comparison_links_template: Option<String>,
156 pub ignored_files: Option<Vec<String>>,
157}
158
159impl InitConfig {
160 #[must_use]
161 pub fn is_empty(&self) -> bool {
162 self.commit.is_none()
163 && self.tags.is_none()
164 && self.keep_changesets.is_none()
165 && self.tag_format.is_none()
166 && self.changelog.is_none()
167 && self.comparison_links.is_none()
168 && self.zero_version_behavior.is_none()
169 && self.dependency_bump_changelog_template.is_none()
170 && self.base_branch.is_none()
171 && self.none_bump_behavior.is_none()
172 && self.none_bump_promote_message_template.is_none()
173 && self.commit_title_template.is_none()
174 && self.changes_in_body.is_none()
175 && self.comparison_links_template.is_none()
176 && self.ignored_files.is_none()
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn is_empty_returns_false_when_only_dependency_bump_changelog_template_set() {
186 let config = InitConfig {
187 dependency_bump_changelog_template: Some(
188 "Updated dependency `{dependency}` to v{version}".to_string(),
189 ),
190 ..Default::default()
191 };
192 assert!(!config.is_empty());
193 }
194
195 #[test]
196 fn is_empty_returns_false_when_only_base_branch_set() {
197 let config = InitConfig {
198 base_branch: Some("develop".to_string()),
199 ..Default::default()
200 };
201 assert!(!config.is_empty());
202 }
203
204 #[test]
205 fn is_empty_returns_false_when_only_none_bump_behavior_set() {
206 let config = InitConfig {
207 none_bump_behavior: Some(NoneBumpBehavior::Allow),
208 ..Default::default()
209 };
210 assert!(!config.is_empty());
211 }
212
213 #[test]
214 fn is_empty_returns_false_when_only_none_bump_promote_message_template_set() {
215 let config = InitConfig {
216 none_bump_promote_message_template: Some("chore: internal changes".to_string()),
217 ..Default::default()
218 };
219 assert!(!config.is_empty());
220 }
221
222 #[test]
223 fn is_empty_returns_false_when_only_commit_title_template_set() {
224 let config = InitConfig {
225 commit_title_template: Some("{new-version}".to_string()),
226 ..Default::default()
227 };
228 assert!(!config.is_empty());
229 }
230
231 #[test]
232 fn is_empty_returns_false_when_only_changes_in_body_set() {
233 let config = InitConfig {
234 changes_in_body: Some(true),
235 ..Default::default()
236 };
237 assert!(!config.is_empty());
238 }
239
240 #[test]
241 fn is_empty_returns_false_when_only_comparison_links_template_set() {
242 let config = InitConfig {
243 comparison_links_template: Some(
244 "https://example.com/{repository}/compare/{base}...{target}".to_string(),
245 ),
246 ..Default::default()
247 };
248 assert!(!config.is_empty());
249 }
250
251 #[test]
252 fn is_empty_returns_false_when_only_ignored_files_set() {
253 let config = InitConfig {
254 ignored_files: Some(vec!["*.md".to_string()]),
255 ..Default::default()
256 };
257 assert!(!config.is_empty());
258 }
259}