wasmer_deploy_schema/schema/
app_version.rs1use anyhow::Context;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4
5use super::{entity::EntityDescriptorConst, AnyEntity, WorkloadV2};
6
7#[derive(Serialize, Deserialize, JsonSchema, PartialEq, Eq, Clone, Debug)]
11pub struct AppVersionV1Spec {
12 pub app_id: String,
13 pub app_version_id: String,
14
15 #[serde(default)]
18 #[serde(skip_serializing_if = "Vec::is_empty")]
19 pub aliases: Vec<String>,
20
21 pub workload: WorkloadV2,
23}
24
25#[derive(Serialize, Deserialize, JsonSchema, PartialEq, Eq, Clone, Debug)]
26pub struct AppVersionV1State {}
27
28impl EntityDescriptorConst for AppVersionV1Spec {
29 const NAMESPACE: &'static str = "wasmer.io";
30 const NAME: &'static str = "AppVersion";
31 const VERSION: &'static str = "1";
32 const KIND: &'static str = "wasmer.io/AppVersion.v1";
33
34 type Spec = AppVersionV1Spec;
35 type State = AppVersionV1State;
36}
37
38pub type AppVersionV1 = super::Entity<AppVersionV1Spec, AnyEntity>;
39
40pub fn parse_upcast_app_version_yaml(yaml: &str) -> Result<AppVersionV1, anyhow::Error> {
42 let value: serde_yaml::Value =
43 serde_yaml::from_str(yaml).context("could not parse app version: invalid yaml")?;
44
45 let kind = value.get("kind").and_then(|x| x.as_str());
46
47 if kind == Some(AppVersionV1Spec::KIND) {
48 serde_yaml::from_value::<AppVersionV1>(value)
49 .context("could not parse app version: invalid app v1 schema")
50 } else if kind == Some(super::AppV1Spec::KIND) {
51 let mut app: super::AppV1 = serde_yaml::from_value(value)
52 .context("could not parse app version: invalid app v1 schema")?;
53
54 let annotations = super::AppMeta::try_from_annotations(&app.meta.annotations)?;
55 app.meta
56 .annotations
57 .remove(super::AppMeta::ANNOTATION_BACKEND_APP_ID);
58 app.meta
59 .annotations
60 .remove(super::AppMeta::ANNOTATION_BACKEND_APP_VERSION_ID);
61
62 Ok(AppVersionV1 {
63 meta: app.meta,
64 spec: AppVersionV1Spec {
65 app_id: annotations.app_id,
66 app_version_id: annotations.app_version_id,
67 aliases: app.spec.aliases,
68 workload: app.spec.workload,
69 },
70 children: None,
71 })
72 } else if let Some(other) = kind {
73 anyhow::bail!("could not parse app version: unknown kind: {other}");
74 } else {
75 anyhow::bail!("could not parse app version: no kind field in yaml");
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use pretty_assertions::assert_eq;
82
83 use crate::schema::EntityMeta;
84
85 use super::*;
86
87 #[test]
89 fn test_deser_app_v1_sparse() {
90 let inp = r#"
91kind: wasmer.io/App.v1
92meta:
93 name: my-app
94spec:
95 app_id: da_123
96 app_version_id: dav_123
97 workload:
98 source: theduke/amaze
99"#;
100
101 let a1 = serde_yaml::from_str::<AppVersionV1>(inp).unwrap();
102
103 assert_eq!(
104 a1,
105 AppVersionV1 {
106 meta: EntityMeta::new("my-app"),
107 spec: AppVersionV1Spec {
108 app_id: "da_123".to_string(),
109 app_version_id: "dav_123".to_string(),
110 aliases: Vec::new(),
111 workload: crate::schema::WorkloadV2 {
112 source: "theduke/amaze".parse().unwrap(),
113 capabilities: Default::default(),
114 },
115 },
116 children: None,
117 },
118 );
119 }
120
121 #[test]
122 fn test_deser_app_v1_full() {
123 let inp = r#"
124kind: wasmer.io/App.v1
125meta:
126 name: my-app
127 description: hello
128 labels:
129 "my/label": "value"
130 annotations:
131 "my/annotation": {nested: [1, 2, 3]}
132spec:
133 app_id: da_123
134 app_version_id: dav_123
135 aliases:
136 - a
137 - b
138 workload:
139 source: "theduke/my-app"
140"#;
141
142 let a1 = serde_yaml::from_str::<AppVersionV1>(inp).unwrap();
143
144 let expected = AppVersionV1 {
145 meta: EntityMeta {
146 name: "my-app".to_string(),
147 description: Some("hello".to_string()),
148 labels: vec![("my/label".to_string(), "value".to_string())]
149 .into_iter()
150 .collect(),
151 annotations: vec![(
152 "my/annotation".to_string(),
153 serde_json::json!({
154 "nested": [1, 2, 3],
155 }),
156 )]
157 .into_iter()
158 .collect(),
159 parent: None,
160 },
161 spec: AppVersionV1Spec {
162 app_id: "da_123".to_string(),
163 app_version_id: "dav_123".to_string(),
164 aliases: vec!["a".to_string(), "b".to_string()],
165 workload: WorkloadV2 {
166 source: "theduke/my-app".parse().unwrap(),
167 capabilities: Default::default(),
168 },
169 },
170 children: None,
171 };
172
173 assert_eq!(a1, expected);
174 }
175}