1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10#[serde(default)]
11pub struct ReleaseConfig {
12 pub git: ReleaseGitConfig,
14 pub packages: ReleasePackagesConfig,
16 pub changelog: ChangelogConfig,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22#[serde(default)]
23pub struct ReleaseGitConfig {
24 #[serde(rename = "defaultBranch")]
26 pub default_branch: String,
27 #[serde(rename = "tagFormat")]
29 pub tag_format: String,
30 #[serde(rename = "createTags")]
32 pub create_tags: bool,
33 #[serde(rename = "pushTags")]
35 pub push_tags: bool,
36}
37
38impl Default for ReleaseGitConfig {
39 fn default() -> Self {
40 Self {
41 default_branch: "main".to_string(),
42 tag_format: "v${version}".to_string(),
43 create_tags: true,
44 push_tags: true,
45 }
46 }
47}
48
49impl ReleaseGitConfig {
50 #[must_use]
54 pub fn format_tag(&self, package: &str, version: &str) -> String {
55 self.tag_format
56 .replace("${package}", package)
57 .replace("${version}", version)
58 }
59}
60
61#[derive(Debug, Clone, Default, Serialize, Deserialize)]
63#[serde(default)]
64pub struct ReleasePackagesConfig {
65 pub fixed: Vec<Vec<String>>,
67 pub linked: Vec<Vec<String>>,
69}
70
71impl ReleasePackagesConfig {
72 #[must_use]
74 pub fn is_in_fixed_group(&self, package: &str) -> bool {
75 self.fixed
76 .iter()
77 .any(|group| group.contains(&package.to_string()))
78 }
79
80 #[must_use]
82 pub fn get_fixed_group(&self, package: &str) -> Option<&Vec<String>> {
83 self.fixed
84 .iter()
85 .find(|group| group.contains(&package.to_string()))
86 }
87
88 #[must_use]
90 pub fn is_in_linked_group(&self, package: &str) -> bool {
91 self.linked
92 .iter()
93 .any(|group| group.contains(&package.to_string()))
94 }
95
96 #[must_use]
98 pub fn get_linked_group(&self, package: &str) -> Option<&Vec<String>> {
99 self.linked
100 .iter()
101 .find(|group| group.contains(&package.to_string()))
102 }
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107#[serde(default)]
108pub struct ChangelogConfig {
109 pub path: String,
111 #[serde(rename = "perPackage")]
113 pub per_package: bool,
114 pub workspace: bool,
116}
117
118impl Default for ChangelogConfig {
119 fn default() -> Self {
120 Self {
121 path: "CHANGELOG.md".to_string(),
122 per_package: true,
123 workspace: true,
124 }
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn test_release_config_default() {
134 let config = ReleaseConfig::default();
135 assert_eq!(config.git.default_branch, "main");
136 assert_eq!(config.git.tag_format, "v${version}");
137 assert!(config.git.create_tags);
138 assert!(config.git.push_tags);
139 }
140
141 #[test]
142 fn test_git_config_format_tag() {
143 let config = ReleaseGitConfig::default();
144 assert_eq!(config.format_tag("my-pkg", "1.0.0"), "v1.0.0");
145
146 let monorepo_config = ReleaseGitConfig {
147 tag_format: "${package}-v${version}".to_string(),
148 ..Default::default()
149 };
150 assert_eq!(
151 monorepo_config.format_tag("my-pkg", "1.0.0"),
152 "my-pkg-v1.0.0"
153 );
154 }
155
156 #[test]
157 fn test_packages_config_fixed_groups() {
158 let config = ReleasePackagesConfig {
159 fixed: vec![
160 vec!["pkg-a".to_string(), "pkg-b".to_string()],
161 vec!["pkg-c".to_string()],
162 ],
163 linked: vec![],
164 };
165
166 assert!(config.is_in_fixed_group("pkg-a"));
167 assert!(config.is_in_fixed_group("pkg-b"));
168 assert!(config.is_in_fixed_group("pkg-c"));
169 assert!(!config.is_in_fixed_group("pkg-d"));
170
171 let group = config.get_fixed_group("pkg-a").unwrap();
172 assert!(group.contains(&"pkg-a".to_string()));
173 assert!(group.contains(&"pkg-b".to_string()));
174 }
175
176 #[test]
177 fn test_packages_config_linked_groups() {
178 let config = ReleasePackagesConfig {
179 fixed: vec![],
180 linked: vec![vec!["pkg-x".to_string(), "pkg-y".to_string()]],
181 };
182
183 assert!(config.is_in_linked_group("pkg-x"));
184 assert!(config.is_in_linked_group("pkg-y"));
185 assert!(!config.is_in_linked_group("pkg-z"));
186 }
187
188 #[test]
189 fn test_changelog_config_default() {
190 let config = ChangelogConfig::default();
191 assert_eq!(config.path, "CHANGELOG.md");
192 assert!(config.per_package);
193 assert!(config.workspace);
194 }
195
196 #[test]
197 fn test_config_serialization() {
198 let config = ReleaseConfig::default();
199 let json = serde_json::to_string(&config).unwrap();
200 let parsed: ReleaseConfig = serde_json::from_str(&json).unwrap();
201 assert_eq!(parsed.git.default_branch, config.git.default_branch);
202 }
203}