1use serde::{Deserialize, Serialize};
2
3use crate::{CursorPage, GitLabVisibility, OwnerRef};
4
5pub type RuntimeRepositoryRecordPage = CursorPage<RuntimeRepositoryRecord>;
6
7#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
8#[serde(rename_all = "snake_case")]
9pub enum RuntimeRepositoryStatus {
10 Importing,
11 #[default]
12 Ready,
13 Failed,
14}
15
16impl RuntimeRepositoryStatus {
17 pub fn as_str(self) -> &'static str {
18 match self {
19 Self::Importing => "importing",
20 Self::Ready => "ready",
21 Self::Failed => "failed",
22 }
23 }
24
25 pub fn parse(value: &str) -> Self {
26 match value.trim() {
27 "importing" => Self::Importing,
28 "failed" => Self::Failed,
29 _ => Self::Ready,
30 }
31 }
32
33 pub fn from_gitlab_import(import_status: Option<&str>, default_branch: Option<&str>) -> Self {
34 match import_status.map(str::trim).unwrap_or_default() {
35 "failed" => Self::Failed,
36 "scheduled" | "started" => Self::Importing,
37 "finished" => Self::Ready,
38 "none" | "" if default_branch.is_some() => Self::Ready,
39 _ => Self::Importing,
40 }
41 }
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
45#[serde(rename_all = "camelCase")]
46pub struct RuntimeRepositoryRecord {
47 pub id: String,
48 pub tenant_id: String,
49 pub project_id: String,
50 pub template_id: String,
51 pub owners: Vec<OwnerRef>,
52 pub namespace: String,
53 pub gitlab_project_id: u64,
54 pub path_with_namespace: String,
55 pub repository_url: String,
57 pub default_branch: Option<String>,
58 #[serde(default)]
59 pub status: RuntimeRepositoryStatus,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub error_message: Option<String>,
62 pub version: i64,
63 pub created_at: String,
64 pub updated_at: String,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
68#[serde(rename_all = "camelCase", deny_unknown_fields)]
69pub struct CreateRuntimeRepositoryRequest {
70 pub template_id: String,
71 pub project_name: String,
72 #[serde(default, skip_serializing_if = "Option::is_none")]
73 pub project_path: Option<String>,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub namespace: Option<String>,
76 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub description: Option<String>,
78 #[serde(default)]
79 pub visibility: GitLabVisibility,
80 #[serde(default)]
81 pub owners: Vec<OwnerRef>,
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn gitlab_import_status_maps_to_repository_status() {
90 assert_eq!(
91 RuntimeRepositoryStatus::from_gitlab_import(Some("started"), None),
92 RuntimeRepositoryStatus::Importing
93 );
94 assert_eq!(
95 RuntimeRepositoryStatus::from_gitlab_import(Some("finished"), Some("master")),
96 RuntimeRepositoryStatus::Ready
97 );
98 assert_eq!(
99 RuntimeRepositoryStatus::from_gitlab_import(Some("none"), Some("master")),
100 RuntimeRepositoryStatus::Ready
101 );
102 assert_eq!(
103 RuntimeRepositoryStatus::from_gitlab_import(Some("none"), None),
104 RuntimeRepositoryStatus::Importing
105 );
106 assert_eq!(
107 RuntimeRepositoryStatus::from_gitlab_import(Some("failed"), None),
108 RuntimeRepositoryStatus::Failed
109 );
110 }
111
112 #[test]
113 fn record_defaults_missing_status_to_ready() {
114 let record: RuntimeRepositoryRecord = serde_json::from_value(serde_json::json!({
115 "id": "rrepo-1",
116 "tenantId": "local",
117 "projectId": "default",
118 "templateId": "rtpl-1",
119 "owners": [],
120 "namespace": "runtimes",
121 "gitlabProjectId": 1,
122 "pathWithNamespace": "runtimes/demo",
123 "repositoryUrl": "https://git.test/runtimes/demo.git",
124 "defaultBranch": "master",
125 "version": 1,
126 "createdAt": "t",
127 "updatedAt": "t"
128 }))
129 .unwrap();
130 assert_eq!(record.status, RuntimeRepositoryStatus::Ready);
131 assert_eq!(record.error_message, None);
132 }
133}