Skip to main content

cuenv_ci/
context.rs

1use std::fmt;
2
3/// Context information about the current CI environment.
4///
5/// Contains metadata about the CI provider, event type, and git references
6/// that triggered the pipeline execution.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct CIContext {
9    /// The CI provider name (e.g., "github", "gitlab", "local").
10    pub provider: String,
11    /// The event that triggered the pipeline (e.g., "push", "pull_request").
12    pub event: String,
13    /// The git ref name (e.g., "refs/heads/main", "refs/tags/v1.0.0").
14    pub ref_name: String,
15    /// The base ref for pull requests (e.g., "refs/heads/main").
16    pub base_ref: Option<String>,
17    /// The git commit SHA.
18    pub sha: String,
19}
20
21impl Default for CIContext {
22    fn default() -> Self {
23        Self {
24            provider: String::from("local"),
25            event: String::from("manual"),
26            ref_name: String::new(),
27            base_ref: None,
28            sha: String::new(),
29        }
30    }
31}
32
33impl fmt::Display for CIContext {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        write!(
36            f,
37            "{}/{} on {} ({})",
38            self.provider,
39            self.event,
40            self.ref_name,
41            &self.sha.get(..7).unwrap_or(&self.sha)
42        )
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn test_ci_context_default() {
52        let ctx = CIContext::default();
53        assert_eq!(ctx.provider, "local");
54        assert_eq!(ctx.event, "manual");
55        assert!(ctx.ref_name.is_empty());
56        assert!(ctx.base_ref.is_none());
57        assert!(ctx.sha.is_empty());
58    }
59
60    #[test]
61    fn test_ci_context_display_with_long_sha() {
62        let ctx = CIContext {
63            provider: "github".to_string(),
64            event: "push".to_string(),
65            ref_name: "refs/heads/main".to_string(),
66            base_ref: None,
67            sha: "abc1234567890def".to_string(),
68        };
69        let display = format!("{ctx}");
70        assert!(display.contains("github/push"));
71        assert!(display.contains("refs/heads/main"));
72        assert!(display.contains("abc1234")); // First 7 chars
73        assert!(!display.contains("567890def")); // Not the rest
74    }
75
76    #[test]
77    fn test_ci_context_display_with_short_sha() {
78        let ctx = CIContext {
79            provider: "gitlab".to_string(),
80            event: "merge_request".to_string(),
81            ref_name: "refs/heads/feature".to_string(),
82            base_ref: Some("refs/heads/main".to_string()),
83            sha: "abc".to_string(),
84        };
85        let display = format!("{ctx}");
86        assert!(display.contains("gitlab/merge_request"));
87        assert!(display.contains("abc")); // Full short sha
88    }
89
90    #[test]
91    fn test_ci_context_equality() {
92        let ctx1 = CIContext {
93            provider: "github".to_string(),
94            event: "push".to_string(),
95            ref_name: "refs/heads/main".to_string(),
96            base_ref: None,
97            sha: "abc123".to_string(),
98        };
99        let ctx2 = ctx1.clone();
100        assert_eq!(ctx1, ctx2);
101    }
102
103    #[test]
104    fn test_ci_context_inequality() {
105        let ctx1 = CIContext::default();
106        let ctx2 = CIContext {
107            provider: "github".to_string(),
108            ..CIContext::default()
109        };
110        assert_ne!(ctx1, ctx2);
111    }
112
113    #[test]
114    fn test_ci_context_debug() {
115        let ctx = CIContext::default();
116        let debug_str = format!("{ctx:?}");
117        assert!(debug_str.contains("CIContext"));
118        assert!(debug_str.contains("local"));
119    }
120
121    #[test]
122    fn test_ci_context_with_base_ref() {
123        let ctx = CIContext {
124            provider: "github".to_string(),
125            event: "pull_request".to_string(),
126            ref_name: "refs/pull/123/head".to_string(),
127            base_ref: Some("refs/heads/main".to_string()),
128            sha: "abc1234".to_string(),
129        };
130        assert_eq!(ctx.base_ref, Some("refs/heads/main".to_string()));
131    }
132}