Skip to main content

quanttide_devops/stage/
release.rs

1/// 发布阶段的状态枚举。
2///
3/// 描述一个 scope 当前所处的发布生命周期阶段。
4#[derive(Debug, Clone, PartialEq)]
5pub enum ReleaseStatus {
6    /// 从未发布过(无匹配的 git tag)。
7    Unreleased,
8    /// 已发布且为最新状态,无新的未发布变更。
9    Latest,
10    /// 有自上次发布以来的未发布提交。
11    Pending,
12    /// tag 与配置文件版本不一致。
13    Inconsistent,
14    /// 无法确定状态(如 git 命令失败)。
15    Unknown,
16}
17
18/// 发布阶段状态快照。
19///
20/// 记录一个 scope 在某个时刻的发布状态快照。
21/// 与 [`VersionState`] 的关系:`VersionState` 聚焦版本号一致性,
22/// `ReleaseState` 聚焦发布生命周期阶段。
23#[derive(Debug)]
24pub struct ReleaseState {
25    /// 发布生命周期状态。
26    pub status: ReleaseStatus,
27    /// scope 名称。
28    pub scope: String,
29    /// scope 相对路径。
30    pub scope_path: String,
31    /// 当前最新 tag 版本号(若有)。
32    pub current_version: Option<String>,
33    /// 自最新 tag 以来的未发布提交数。
34    pub pending_commits: usize,
35    /// 变更日志路径。
36    pub changelog: String,
37    /// 版本一致性检查结果(空表示未检查或不适用)。
38    pub version_consistent: Option<bool>,
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    // ── ReleaseStatus ──────────────────────────────────────────────
46
47    #[test]
48    fn test_release_status_variants() {
49        assert_ne!(ReleaseStatus::Unreleased, ReleaseStatus::Latest);
50        assert_ne!(ReleaseStatus::Latest, ReleaseStatus::Pending);
51        assert_ne!(ReleaseStatus::Pending, ReleaseStatus::Inconsistent);
52        assert_ne!(ReleaseStatus::Inconsistent, ReleaseStatus::Unknown);
53    }
54
55    #[test]
56    fn test_release_status_debug() {
57        let s = format!("{:?}", ReleaseStatus::Unreleased);
58        assert_eq!(s, "Unreleased");
59    }
60
61    // ── ReleaseState ───────────────────────────────────────────────
62
63    #[test]
64    fn test_release_state_unreleased() {
65        let state = ReleaseState {
66            status: ReleaseStatus::Unreleased,
67            scope: "cli".into(),
68            scope_path: "src/cli".into(),
69            current_version: None,
70            pending_commits: 0,
71            changelog: "CHANGELOG.md".into(),
72            version_consistent: None,
73        };
74        assert_eq!(state.status, ReleaseStatus::Unreleased);
75        assert!(state.current_version.is_none());
76        assert_eq!(state.pending_commits, 0);
77    }
78
79    #[test]
80    fn test_release_state_pending() {
81        let state = ReleaseState {
82            status: ReleaseStatus::Pending,
83            scope: "core".into(),
84            scope_path: "packages/core".into(),
85            current_version: Some("v1.2.3".into()),
86            pending_commits: 5,
87            changelog: "CHANGELOG.md".into(),
88            version_consistent: Some(true),
89        };
90        assert_eq!(state.status, ReleaseStatus::Pending);
91        assert_eq!(state.current_version.as_deref(), Some("v1.2.3"));
92        assert_eq!(state.pending_commits, 5);
93        assert_eq!(state.version_consistent, Some(true));
94    }
95
96    #[test]
97    fn test_release_state_latest() {
98        let state = ReleaseState {
99            status: ReleaseStatus::Latest,
100            scope: "(root)".into(),
101            scope_path: ".".into(),
102            current_version: Some("v5.0.0".into()),
103            pending_commits: 0,
104            changelog: "CHANGELOG.md".into(),
105            version_consistent: Some(true),
106        };
107        assert_eq!(state.status, ReleaseStatus::Latest);
108        assert_eq!(state.pending_commits, 0);
109    }
110
111    #[test]
112    fn test_release_state_inconsistent() {
113        let state = ReleaseState {
114            status: ReleaseStatus::Inconsistent,
115            scope: "web".into(),
116            scope_path: "src/web".into(),
117            current_version: Some("v2.0.0".into()),
118            pending_commits: 3,
119            changelog: "CHANGELOG.md".into(),
120            version_consistent: Some(false),
121        };
122        assert_eq!(state.status, ReleaseStatus::Inconsistent);
123        assert_eq!(state.version_consistent, Some(false));
124    }
125
126    #[test]
127    fn test_release_state_unknown() {
128        let state = ReleaseState {
129            status: ReleaseStatus::Unknown,
130            scope: "service".into(),
131            scope_path: "apps/service".into(),
132            current_version: None,
133            pending_commits: 0,
134            changelog: "CHANGELOG.md".into(),
135            version_consistent: None,
136        };
137        assert_eq!(state.status, ReleaseStatus::Unknown);
138    }
139}