zlayer_types/api/syncs.rs
1//! Sync DTOs.
2//!
3//! Wire types for the sync CRUD + diff/apply endpoints. A sync resource
4//! points at a directory within a project's git checkout that contains
5//! `ZLayer` resource YAMLs. The diff endpoint scans the directory and
6//! reports what would change; the apply endpoint actually reconciles.
7
8use serde::{Deserialize, Serialize};
9use utoipa::ToSchema;
10
11/// Body for `POST /api/v1/syncs`.
12#[derive(Debug, Serialize, Deserialize, ToSchema)]
13pub struct CreateSyncRequest {
14 /// Display name for this sync.
15 pub name: String,
16 /// Linked project id.
17 #[serde(default)]
18 pub project_id: Option<String>,
19 /// Path within the project's checkout to scan for resource YAMLs.
20 pub git_path: String,
21 /// Whether the sync should automatically apply on pull.
22 #[serde(default)]
23 pub auto_apply: Option<bool>,
24 /// Whether `apply` should delete resources on the API that are missing
25 /// from the manifest directory. Defaults to `false` (the safer choice).
26 #[serde(default)]
27 pub delete_missing: Option<bool>,
28 /// How often (in seconds) the continuous reconciliation controller should
29 /// re-apply this sync while `auto_apply` is enabled. `None` (the default)
30 /// uses the controller's configured default interval.
31 #[serde(default)]
32 pub reconcile_interval_secs: Option<u64>,
33}
34
35/// Result of reconciling a single resource during apply.
36#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
37pub struct SyncResourceResult {
38 /// The source manifest path (or remote resource name for deletions).
39 pub resource: String,
40 /// Resource kind: `"deployment"`, `"job"`, `"cron"`, or other.
41 pub kind: String,
42 /// Action taken: `"create"`, `"update"`, `"delete"`, or `"skip"`.
43 pub action: String,
44 /// Outcome status: `"ok"` or `"error"`.
45 pub status: String,
46 /// Optional error message (`status == "error"`) or skip reason
47 /// (`action == "skip"`). Omitted on successful `"ok"` results.
48 #[serde(skip_serializing_if = "Option::is_none")]
49 pub error: Option<String>,
50}
51
52impl SyncResourceResult {
53 /// Build a successful result for the given resource/kind/action.
54 #[must_use]
55 pub fn ok(resource: &str, kind: &str, action: &str) -> Self {
56 Self {
57 resource: resource.to_string(),
58 kind: kind.to_string(),
59 action: action.to_string(),
60 status: "ok".to_string(),
61 error: None,
62 }
63 }
64
65 /// Build an error result with a human-readable message.
66 #[must_use]
67 pub fn err(resource: &str, kind: &str, action: &str, message: String) -> Self {
68 Self {
69 resource: resource.to_string(),
70 kind: kind.to_string(),
71 action: action.to_string(),
72 status: "error".to_string(),
73 error: Some(message),
74 }
75 }
76
77 /// Build a skip result with a reason recorded in `error`.
78 #[must_use]
79 pub fn skip(resource: &str, kind: &str, message: String) -> Self {
80 Self {
81 resource: resource.to_string(),
82 kind: kind.to_string(),
83 action: "skip".to_string(),
84 status: "ok".to_string(),
85 error: Some(message),
86 }
87 }
88}
89
90/// Response for a real apply. Reports per-resource outcomes, the current
91/// commit SHA the sync was applied at (when known), and a short human-readable
92/// summary for CLI display.
93///
94/// NOTE: This is a breaking change from the previous dry-run-only
95/// `{ diff, message }` shape. Clients inspecting the apply response directly
96/// must be updated — callers that only consumed the HTTP status stay working.
97#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
98pub struct SyncApplyResponse {
99 /// Per-resource reconcile results.
100 pub results: Vec<SyncResourceResult>,
101 /// Commit SHA the sync was applied against (when resolvable).
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub applied_sha: Option<String>,
104 /// Aggregate summary suitable for CLI output, e.g.
105 /// `"3 created, 2 updated, 1 deleted, 0 skipped"`.
106 pub summary: String,
107}
108
109/// JSON-friendly wrapper around the sync diff output.
110#[derive(Debug, Serialize, Deserialize, ToSchema)]
111pub struct SyncDiffResponse {
112 /// Resources to create.
113 pub to_create: Vec<SyncResourceResponse>,
114 /// Resources to update.
115 pub to_update: Vec<SyncResourceResponse>,
116 /// Resource names to delete.
117 pub to_delete: Vec<String>,
118}
119
120/// A single resource in the diff output.
121#[derive(Debug, Serialize, Deserialize, ToSchema)]
122pub struct SyncResourceResponse {
123 /// Source file name.
124 pub file_path: String,
125 /// Resource kind.
126 pub kind: String,
127 /// Resource name.
128 pub name: String,
129}