loom_core/manifest/
sync.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum SyncStatus {
8 Active,
9 Partial,
10 Closed,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
17#[serde(rename_all = "camelCase")]
18pub struct SyncManifest {
19 pub name: String,
20 pub created: DateTime<Utc>,
21 #[serde(default = "default_sync_status")]
22 pub status: SyncStatus,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
27 pub branch: Option<String>,
28 #[serde(default)]
29 pub repos: Vec<SyncRepoEntry>,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct SyncRepoEntry {
36 pub name: String,
37 pub remote_url: String,
38 pub branch: String,
39}
40
41fn default_sync_status() -> SyncStatus {
42 SyncStatus::Active
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn test_sync_manifest_round_trip() {
51 let manifest = SyncManifest {
52 name: "my-feature".to_string(),
53 created: Utc::now(),
54 status: SyncStatus::Active,
55 branch: Some("loom/bold-cedar-hawk".to_string()),
56 repos: vec![SyncRepoEntry {
57 name: "dsp-api".to_string(),
58 remote_url: "git@github.com:dasch-swiss/dsp-api.git".to_string(),
59 branch: "loom/my-feature".to_string(),
60 }],
61 };
62
63 let json = serde_json::to_string_pretty(&manifest).unwrap();
64 let parsed: SyncManifest = serde_json::from_str(&json).unwrap();
65
66 assert_eq!(parsed.name, "my-feature");
67 assert_eq!(parsed.status, SyncStatus::Active);
68 assert_eq!(parsed.branch, Some("loom/bold-cedar-hawk".to_string()));
69 assert_eq!(parsed.repos.len(), 1);
70 }
71
72 #[test]
73 fn test_sync_status_serialization() {
74 assert_eq!(
75 serde_json::to_string(&SyncStatus::Active).unwrap(),
76 "\"active\""
77 );
78 assert_eq!(
79 serde_json::to_string(&SyncStatus::Partial).unwrap(),
80 "\"partial\""
81 );
82 assert_eq!(
83 serde_json::to_string(&SyncStatus::Closed).unwrap(),
84 "\"closed\""
85 );
86 }
87
88 #[test]
89 fn test_sync_manifest_defaults() {
90 let json = r#"{
91 "name": "minimal",
92 "created": "2026-01-15T10:00:00Z"
93 }"#;
94
95 let manifest: SyncManifest = serde_json::from_str(json).unwrap();
96 assert_eq!(manifest.status, SyncStatus::Active);
97 assert!(manifest.branch.is_none());
98 assert!(manifest.repos.is_empty());
99 }
100}