agent-deploy-contract 0.3.1

Transport-neutral deploy contracts for Agent Infra
Documentation
use serde::{Deserialize, Serialize};

use crate::{CursorPage, GitLabVisibility, OwnerRef};

pub type RuntimeRepositoryRecordPage = CursorPage<RuntimeRepositoryRecord>;

#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeRepositoryStatus {
    Importing,
    #[default]
    Ready,
    Failed,
}

impl RuntimeRepositoryStatus {
    pub fn as_str(self) -> &'static str {
        match self {
            Self::Importing => "importing",
            Self::Ready => "ready",
            Self::Failed => "failed",
        }
    }

    pub fn parse(value: &str) -> Self {
        match value.trim() {
            "importing" => Self::Importing,
            "failed" => Self::Failed,
            _ => Self::Ready,
        }
    }

    pub fn from_gitlab_import(import_status: Option<&str>, default_branch: Option<&str>) -> Self {
        match import_status.map(str::trim).unwrap_or_default() {
            "failed" => Self::Failed,
            "scheduled" | "started" => Self::Importing,
            "finished" => Self::Ready,
            "none" | "" if default_branch.is_some() => Self::Ready,
            _ => Self::Importing,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct RuntimeRepositoryRecord {
    pub id: String,
    pub tenant_id: String,
    pub project_id: String,
    pub template_id: String,
    pub owners: Vec<OwnerRef>,
    pub namespace: String,
    pub gitlab_project_id: u64,
    pub path_with_namespace: String,
    /// HTTPS clone URL derived from GitLab. Not an identity key; clients clone locally.
    pub repository_url: String,
    pub default_branch: Option<String>,
    #[serde(default)]
    pub status: RuntimeRepositoryStatus,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error_message: Option<String>,
    pub version: i64,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CreateRuntimeRepositoryRequest {
    pub template_id: String,
    pub project_name: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub project_path: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub namespace: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(default)]
    pub visibility: GitLabVisibility,
    #[serde(default)]
    pub owners: Vec<OwnerRef>,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn gitlab_import_status_maps_to_repository_status() {
        assert_eq!(
            RuntimeRepositoryStatus::from_gitlab_import(Some("started"), None),
            RuntimeRepositoryStatus::Importing
        );
        assert_eq!(
            RuntimeRepositoryStatus::from_gitlab_import(Some("finished"), Some("master")),
            RuntimeRepositoryStatus::Ready
        );
        assert_eq!(
            RuntimeRepositoryStatus::from_gitlab_import(Some("none"), Some("master")),
            RuntimeRepositoryStatus::Ready
        );
        assert_eq!(
            RuntimeRepositoryStatus::from_gitlab_import(Some("none"), None),
            RuntimeRepositoryStatus::Importing
        );
        assert_eq!(
            RuntimeRepositoryStatus::from_gitlab_import(Some("failed"), None),
            RuntimeRepositoryStatus::Failed
        );
    }

    #[test]
    fn record_defaults_missing_status_to_ready() {
        let record: RuntimeRepositoryRecord = serde_json::from_value(serde_json::json!({
            "id": "rrepo-1",
            "tenantId": "local",
            "projectId": "default",
            "templateId": "rtpl-1",
            "owners": [],
            "namespace": "runtimes",
            "gitlabProjectId": 1,
            "pathWithNamespace": "runtimes/demo",
            "repositoryUrl": "https://git.test/runtimes/demo.git",
            "defaultBranch": "master",
            "version": 1,
            "createdAt": "t",
            "updatedAt": "t"
        }))
        .unwrap();
        assert_eq!(record.status, RuntimeRepositoryStatus::Ready);
        assert_eq!(record.error_message, None);
    }
}