fundaia 0.53.0

Command line for the Fundaia deployment platform: projects, services, variables, deployments, logs and metrics
use super::*;

pub struct ComposeDraft<'a> {
    pub compose: &'a str,
    pub name: Option<&'a str>,
    pub workspace_id: Option<&'a str>,
    pub project_id: Option<&'a str>,
    pub repository: Option<&'a str>,
    pub branch: Option<&'a str>,
    pub deploy: bool,
}

impl ApiClient {
    pub async fn import_compose(&self, draft: &ComposeDraft<'_>) -> Result<Answer<ComposeImport>> {
        self.post_answer(
            "/api/infra/projects/import-compose",
            &compose_body(draft, self.environment()),
        )
        .await
    }

    pub async fn stacks(&self) -> Result<Answer<StacksPage>> {
        self.get_answer("/api/infra/stacks").await
    }

    pub async fn add_stack(
        &self,
        project_id: &str,
        key: &str,
        deploy: bool,
    ) -> Result<Answer<PlacedStack>> {
        self.post_answer(
            &format!(
                "/api/infra/projects/{project_id}/stacks/{}{}",
                utf8_percent_encode(key, NON_ALPHANUMERIC),
                self.environment_query('?')
            ),
            &serde_json::json!({ "deploy": deploy }),
        )
        .await
    }

    pub async fn create_from_stack(
        &self,
        key: &str,
        name: Option<&str>,
        workspace_id: Option<&str>,
        deploy: bool,
    ) -> Result<Answer<PlacedStack>> {
        let mut body = serde_json::Map::new();
        body.insert("deploy".into(), deploy.into());
        if let Some(name) = name {
            body.insert("name".into(), name.into());
        }
        if let Some(workspace_id) = workspace_id {
            body.insert("workspaceId".into(), workspace_id.into());
        }

        self.post_answer(
            &format!(
                "/api/infra/stacks/{}/projects",
                utf8_percent_encode(key, NON_ALPHANUMERIC)
            ),
            &serde_json::Value::Object(body),
        )
        .await
    }

    pub async fn duplicate_service(
        &self,
        service_environment_id: &str,
        name: &str,
        deploy: bool,
    ) -> Result<Answer<CopiedServicePage>> {
        let mut body = serde_json::Map::new();
        body.insert("name".into(), name.into());
        if !deploy {
            body.insert("deployNow".into(), false.into());
        }

        self.post_answer(
            &format!("/api/infra/services/{service_environment_id}/duplicate"),
            &serde_json::Value::Object(body),
        )
        .await
    }
}

fn compose_body(draft: &ComposeDraft<'_>, environment: Option<&str>) -> serde_json::Value {
    let mut body = serde_json::Map::new();
    body.insert("compose".into(), draft.compose.into());
    body.insert("deploy".into(), draft.deploy.into());
    if let Some(name) = draft.name {
        body.insert("name".into(), name.into());
    }
    if let Some(workspace_id) = draft.workspace_id {
        body.insert("workspaceId".into(), workspace_id.into());
    }
    if let Some(project_id) = draft.project_id {
        body.insert("projectId".into(), project_id.into());
        if let Some(environment) = environment {
            body.insert("environment".into(), environment.into());
        }
    }
    if let Some(repository) = draft.repository {
        body.insert("repository".into(), repository.into());
        body.insert("branch".into(), draft.branch.unwrap_or("main").into());
    }
    serde_json::Value::Object(body)
}

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

    fn draft<'a>(project_id: Option<&'a str>, repository: Option<&'a str>) -> ComposeDraft<'a> {
        ComposeDraft {
            compose: "services: {}",
            name: None,
            workspace_id: None,
            project_id,
            repository,
            branch: None,
            deploy: false,
        }
    }

    #[test]
    fn it_should_send_the_environment_only_with_a_project_to_add_to() {
        assert!(compose_body(&draft(None, None), Some("staging"))
            .get("environment")
            .is_none());
    }

    #[test]
    fn it_should_send_the_environment_of_the_project_to_add_to() {
        assert_eq!(
            compose_body(&draft(Some("prj_1"), None), Some("staging"))["environment"],
            "staging"
        );
    }

    #[test]
    fn it_should_build_from_main_unless_a_branch_is_given() {
        assert_eq!(
            compose_body(&draft(None, Some("pepito/tienda")), None)["branch"],
            "main"
        );
    }
}