Skip to main content

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}
29
30/// Result of reconciling a single resource during apply.
31#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
32pub struct SyncResourceResult {
33    /// The source manifest path (or remote resource name for deletions).
34    pub resource: String,
35    /// Resource kind: `"deployment"`, `"job"`, `"cron"`, or other.
36    pub kind: String,
37    /// Action taken: `"create"`, `"update"`, `"delete"`, or `"skip"`.
38    pub action: String,
39    /// Outcome status: `"ok"` or `"error"`.
40    pub status: String,
41    /// Optional error message (`status == "error"`) or skip reason
42    /// (`action == "skip"`). Omitted on successful `"ok"` results.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub error: Option<String>,
45}
46
47impl SyncResourceResult {
48    /// Build a successful result for the given resource/kind/action.
49    #[must_use]
50    pub fn ok(resource: &str, kind: &str, action: &str) -> Self {
51        Self {
52            resource: resource.to_string(),
53            kind: kind.to_string(),
54            action: action.to_string(),
55            status: "ok".to_string(),
56            error: None,
57        }
58    }
59
60    /// Build an error result with a human-readable message.
61    #[must_use]
62    pub fn err(resource: &str, kind: &str, action: &str, message: String) -> Self {
63        Self {
64            resource: resource.to_string(),
65            kind: kind.to_string(),
66            action: action.to_string(),
67            status: "error".to_string(),
68            error: Some(message),
69        }
70    }
71
72    /// Build a skip result with a reason recorded in `error`.
73    #[must_use]
74    pub fn skip(resource: &str, kind: &str, message: String) -> Self {
75        Self {
76            resource: resource.to_string(),
77            kind: kind.to_string(),
78            action: "skip".to_string(),
79            status: "ok".to_string(),
80            error: Some(message),
81        }
82    }
83}
84
85/// Response for a real apply. Reports per-resource outcomes, the current
86/// commit SHA the sync was applied at (when known), and a short human-readable
87/// summary for CLI display.
88///
89/// NOTE: This is a breaking change from the previous dry-run-only
90/// `{ diff, message }` shape. Clients inspecting the apply response directly
91/// must be updated — callers that only consumed the HTTP status stay working.
92#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
93pub struct SyncApplyResponse {
94    /// Per-resource reconcile results.
95    pub results: Vec<SyncResourceResult>,
96    /// Commit SHA the sync was applied against (when resolvable).
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub applied_sha: Option<String>,
99    /// Aggregate summary suitable for CLI output, e.g.
100    /// `"3 created, 2 updated, 1 deleted, 0 skipped"`.
101    pub summary: String,
102}
103
104/// JSON-friendly wrapper around the sync diff output.
105#[derive(Debug, Serialize, Deserialize, ToSchema)]
106pub struct SyncDiffResponse {
107    /// Resources to create.
108    pub to_create: Vec<SyncResourceResponse>,
109    /// Resources to update.
110    pub to_update: Vec<SyncResourceResponse>,
111    /// Resource names to delete.
112    pub to_delete: Vec<String>,
113}
114
115/// A single resource in the diff output.
116#[derive(Debug, Serialize, Deserialize, ToSchema)]
117pub struct SyncResourceResponse {
118    /// Source file name.
119    pub file_path: String,
120    /// Resource kind.
121    pub kind: String,
122    /// Resource name.
123    pub name: String,
124}