sherpack_core/
context.rs

1//! Template rendering context
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value as JsonValue;
5
6use crate::pack::PackMetadata;
7use crate::release::ReleaseInfo;
8use crate::values::Values;
9
10/// Context available to all templates
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct TemplateContext {
13    /// User values (merged)
14    pub values: JsonValue,
15
16    /// Release information
17    pub release: ReleaseInfo,
18
19    /// Pack metadata
20    pub pack: PackInfo,
21
22    /// Cluster capabilities
23    pub capabilities: Capabilities,
24
25    /// Current template info
26    pub template: TemplateInfo,
27}
28
29/// Pack information for templates
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct PackInfo {
33    /// Pack name
34    pub name: String,
35
36    /// Pack version
37    pub version: String,
38
39    /// App version
40    pub app_version: Option<String>,
41}
42
43impl From<&PackMetadata> for PackInfo {
44    fn from(meta: &PackMetadata) -> Self {
45        Self {
46            name: meta.name.clone(),
47            version: meta.version.to_string(),
48            app_version: meta.app_version.clone(),
49        }
50    }
51}
52
53/// Cluster capabilities
54#[derive(Debug, Clone, Default, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct Capabilities {
57    /// Kubernetes version
58    pub kube_version: KubeVersion,
59
60    /// Available API versions
61    pub api_versions: Vec<String>,
62}
63
64/// Kubernetes version info
65#[derive(Debug, Clone, Serialize, Deserialize)]
66#[serde(rename_all = "camelCase")]
67pub struct KubeVersion {
68    pub version: String,
69    pub major: String,
70    pub minor: String,
71}
72
73impl Default for KubeVersion {
74    fn default() -> Self {
75        // Default to a recent stable Kubernetes version for lint/template modes
76        Self {
77            version: "v1.28.0".to_string(),
78            major: "1".to_string(),
79            minor: "28".to_string(),
80        }
81    }
82}
83
84impl KubeVersion {
85    pub fn new(version: &str) -> Self {
86        let version = version.trim_start_matches('v');
87        let parts: Vec<&str> = version.split('.').collect();
88
89        Self {
90            version: format!("v{}", version),
91            major: parts.first().unwrap_or(&"1").to_string(),
92            minor: parts.get(1).unwrap_or(&"28").to_string(),
93        }
94    }
95}
96
97/// Current template information
98#[derive(Debug, Clone, Default, Serialize, Deserialize)]
99#[serde(rename_all = "camelCase")]
100pub struct TemplateInfo {
101    /// Template name (filename)
102    pub name: String,
103
104    /// Base path
105    pub base_path: String,
106}
107
108impl TemplateContext {
109    /// Create a new template context
110    pub fn new(values: Values, release: ReleaseInfo, pack: &PackMetadata) -> Self {
111        Self {
112            values: values.into_inner(),
113            release,
114            pack: PackInfo::from(pack),
115            capabilities: Capabilities::default(),
116            template: TemplateInfo::default(),
117        }
118    }
119
120    /// Set the current template info
121    pub fn with_template(mut self, name: &str, base_path: &str) -> Self {
122        self.template = TemplateInfo {
123            name: name.to_string(),
124            base_path: base_path.to_string(),
125        };
126        self
127    }
128
129    /// Set capabilities
130    pub fn with_capabilities(mut self, capabilities: Capabilities) -> Self {
131        self.capabilities = capabilities;
132        self
133    }
134
135    /// Convert to minijinja-compatible context
136    pub fn to_json(&self) -> JsonValue {
137        serde_json::to_value(self).unwrap_or(JsonValue::Null)
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144    use semver::Version;
145
146    #[test]
147    fn test_template_context() {
148        let values = Values::from_yaml("replicas: 3").unwrap();
149        let release = ReleaseInfo::for_install("myapp", "default");
150        let pack = PackMetadata {
151            name: "mypack".to_string(),
152            version: Version::new(1, 0, 0),
153            description: None,
154            app_version: Some("2.0.0".to_string()),
155            kube_version: None,
156            home: None,
157            icon: None,
158            sources: vec![],
159            keywords: vec![],
160            maintainers: vec![],
161            annotations: Default::default(),
162        };
163
164        let ctx = TemplateContext::new(values, release, &pack);
165
166        assert_eq!(ctx.pack.name, "mypack");
167        assert_eq!(ctx.release.name, "myapp");
168        assert!(ctx.release.is_install);
169    }
170}