1#[derive(Debug, Clone, PartialEq)]
5pub enum ReleaseStatus {
6 Unreleased,
8 Latest,
10 Pending,
12 Inconsistent,
14 Unknown,
16}
17
18impl std::fmt::Display for ReleaseStatus {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 Self::Unreleased => write!(f, "未发布"),
31 Self::Latest => write!(f, "已是最新"),
32 Self::Pending => write!(f, "待发布"),
33 Self::Inconsistent => write!(f, "版本冲突"),
34 Self::Unknown => write!(f, "状态未知"),
35 }
36 }
37}
38
39#[derive(Debug)]
45pub struct ReleaseState {
46 pub status: ReleaseStatus,
48 pub scope: String,
50 pub scope_path: String,
52 pub current_version: Option<String>,
54 pub pending_commits: usize,
56 pub changelog: String,
58 pub version_consistent: Option<bool>,
60}
61
62impl ReleaseState {
63 pub fn new(
80 status: ReleaseStatus,
81 scope: impl Into<String>,
82 scope_path: impl Into<String>,
83 current_version: Option<String>,
84 pending_commits: usize,
85 version_consistent: Option<bool>,
86 ) -> Self {
87 Self {
88 status,
89 scope: scope.into(),
90 scope_path: scope_path.into(),
91 current_version,
92 pending_commits,
93 changelog: "CHANGELOG.md".into(),
94 version_consistent,
95 }
96 }
97}
98
99impl std::fmt::Display for ReleaseState {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 writeln!(f, " [{}]", self.scope)?;
113 writeln!(f, " 状态: {}", self.status)?;
114 writeln!(f, " 路径: {}", self.scope_path)?;
115 match &self.current_version {
116 Some(v) => writeln!(f, " 最新版本: {}", v)?,
117 None => writeln!(f, " 最新版本: (无)")?,
118 }
119 writeln!(f, " 未发布提交: {}", self.pending_commits)?;
120 writeln!(f, " 变更日志: {}", self.changelog)?;
121 match self.version_consistent {
122 Some(true) => writeln!(f, " 版本一致: 是"),
123 Some(false) => writeln!(f, " 版本一致: 否"),
124 None => Ok(()),
125 }
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
136 fn test_release_status_variants() {
137 assert_ne!(ReleaseStatus::Unreleased, ReleaseStatus::Latest);
138 assert_ne!(ReleaseStatus::Latest, ReleaseStatus::Pending);
139 assert_ne!(ReleaseStatus::Pending, ReleaseStatus::Inconsistent);
140 assert_ne!(ReleaseStatus::Inconsistent, ReleaseStatus::Unknown);
141 }
142
143 #[test]
144 fn test_release_status_debug() {
145 let s = format!("{:?}", ReleaseStatus::Unreleased);
146 assert_eq!(s, "Unreleased");
147 }
148
149 #[test]
150 fn test_release_status_display() {
151 assert_eq!(format!("{}", ReleaseStatus::Unreleased), "未发布");
152 assert_eq!(format!("{}", ReleaseStatus::Latest), "已是最新");
153 assert_eq!(format!("{}", ReleaseStatus::Pending), "待发布");
154 assert_eq!(format!("{}", ReleaseStatus::Inconsistent), "版本冲突");
155 assert_eq!(format!("{}", ReleaseStatus::Unknown), "状态未知");
156 }
157
158 #[test]
161 fn test_release_state_unreleased() {
162 let state = ReleaseState {
163 status: ReleaseStatus::Unreleased,
164 scope: "cli".into(),
165 scope_path: "src/cli".into(),
166 current_version: None,
167 pending_commits: 0,
168 changelog: "CHANGELOG.md".into(),
169 version_consistent: None,
170 };
171 assert_eq!(state.status, ReleaseStatus::Unreleased);
172 assert!(state.current_version.is_none());
173 assert_eq!(state.pending_commits, 0);
174 }
175
176 #[test]
177 fn test_release_state_pending() {
178 let state = ReleaseState {
179 status: ReleaseStatus::Pending,
180 scope: "core".into(),
181 scope_path: "packages/core".into(),
182 current_version: Some("v1.2.3".into()),
183 pending_commits: 5,
184 changelog: "CHANGELOG.md".into(),
185 version_consistent: Some(true),
186 };
187 assert_eq!(state.status, ReleaseStatus::Pending);
188 assert_eq!(state.current_version.as_deref(), Some("v1.2.3"));
189 assert_eq!(state.pending_commits, 5);
190 assert_eq!(state.version_consistent, Some(true));
191 }
192
193 #[test]
194 fn test_release_state_latest() {
195 let state = ReleaseState {
196 status: ReleaseStatus::Latest,
197 scope: "(root)".into(),
198 scope_path: ".".into(),
199 current_version: Some("v5.0.0".into()),
200 pending_commits: 0,
201 changelog: "CHANGELOG.md".into(),
202 version_consistent: Some(true),
203 };
204 assert_eq!(state.status, ReleaseStatus::Latest);
205 assert_eq!(state.pending_commits, 0);
206 }
207
208 #[test]
209 fn test_release_state_inconsistent() {
210 let state = ReleaseState {
211 status: ReleaseStatus::Inconsistent,
212 scope: "web".into(),
213 scope_path: "src/web".into(),
214 current_version: Some("v2.0.0".into()),
215 pending_commits: 3,
216 changelog: "CHANGELOG.md".into(),
217 version_consistent: Some(false),
218 };
219 assert_eq!(state.status, ReleaseStatus::Inconsistent);
220 assert_eq!(state.version_consistent, Some(false));
221 }
222
223 #[test]
224 fn test_release_state_unknown() {
225 let state = ReleaseState {
226 status: ReleaseStatus::Unknown,
227 scope: "service".into(),
228 scope_path: "apps/service".into(),
229 current_version: None,
230 pending_commits: 0,
231 changelog: "CHANGELOG.md".into(),
232 version_consistent: None,
233 };
234 assert_eq!(state.status, ReleaseStatus::Unknown);
235 }
236
237 #[test]
238 fn test_release_state_new() {
239 let s = ReleaseState::new(ReleaseStatus::Unreleased, "cli", "src/cli", None, 0, None);
240 assert_eq!(s.scope, "cli");
241 assert_eq!(s.scope_path, "src/cli");
242 assert_eq!(s.status, ReleaseStatus::Unreleased);
243 assert!(s.current_version.is_none());
244 assert_eq!(s.pending_commits, 0);
245 assert_eq!(s.changelog, "CHANGELOG.md");
246 assert!(s.version_consistent.is_none());
247
248 let s = ReleaseState::new(
249 ReleaseStatus::Pending,
250 "(root)",
251 ".",
252 Some("v2.0.0".into()),
253 5,
254 Some(false),
255 );
256 assert_eq!(s.scope, "(root)");
257 assert_eq!(s.current_version.as_deref(), Some("v2.0.0"));
258 assert_eq!(s.pending_commits, 5);
259 assert_eq!(s.version_consistent, Some(false));
260 }
261
262 #[test]
263 fn test_release_state_display() {
264 let state = ReleaseState {
265 status: ReleaseStatus::Latest,
266 scope: "qtcloud-core".into(),
267 scope_path: "apps/qtcloud-core".into(),
268 current_version: Some("v2.1.0".into()),
269 pending_commits: 0,
270 changelog: "CHANGELOG.md".into(),
271 version_consistent: Some(true),
272 };
273 assert_eq!(
274 format!("{}", state),
275 " [qtcloud-core]\n 状态: 已是最新\n 路径: apps/qtcloud-core\n 最新版本: v2.1.0\n 未发布提交: 0\n 变更日志: CHANGELOG.md\n 版本一致: 是\n"
276 );
277
278 let state = ReleaseState {
279 status: ReleaseStatus::Unreleased,
280 scope: "(root)".into(),
281 scope_path: ".".into(),
282 current_version: None,
283 pending_commits: 0,
284 changelog: "CHANGELOG.md".into(),
285 version_consistent: None,
286 };
287 assert_eq!(
288 format!("{}", state),
289 " [(root)]\n 状态: 未发布\n 路径: .\n 最新版本: (无)\n 未发布提交: 0\n 变更日志: CHANGELOG.md\n"
290 );
291
292 let state = ReleaseState {
293 status: ReleaseStatus::Inconsistent,
294 scope: "web".into(),
295 scope_path: "src/web".into(),
296 current_version: Some("v2.0.0".into()),
297 pending_commits: 3,
298 changelog: "CHANGELOG.md".into(),
299 version_consistent: Some(false),
300 };
301 assert_eq!(
302 format!("{}", state),
303 " [web]\n 状态: 版本冲突\n 路径: src/web\n 最新版本: v2.0.0\n 未发布提交: 3\n 变更日志: CHANGELOG.md\n 版本一致: 否\n"
304 );
305 }
306}