fundaia 0.52.3

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

impl ApiClient {
    pub async fn workflows(&self, project_id: &str, refresh: bool) -> Result<Vec<Workflow>> {
        let path = format!("/api/infra/projects/{project_id}/workflows");
        let page: WorkflowsPage = if refresh {
            self.post_empty(&format!("{path}/refresh")).await?
        } else {
            self.get(&path).await?
        };
        Ok(page.workflows)
    }

    pub async fn workflow_runs(
        &self,
        project_id: &str,
        workflow_path: Option<&str>,
        commit: Option<&str>,
        limit: u32,
    ) -> Result<Vec<WorkflowRun<WorkflowJobSummary>>> {
        let mut path = format!("/api/infra/projects/{project_id}/workflow-runs?limit={limit}");
        if let Some(workflow_path) = workflow_path {
            path.push_str(&format!(
                "&path={}",
                utf8_percent_encode(workflow_path, NON_ALPHANUMERIC)
            ));
        }
        if let Some(commit) = commit {
            path.push_str(&format!(
                "&commit={}",
                utf8_percent_encode(commit, NON_ALPHANUMERIC)
            ));
        }
        Ok(self.get::<WorkflowRunsPage>(&path).await?.runs)
    }

    pub async fn start_workflow(
        &self,
        project_id: &str,
        workflow_path: &str,
        branch: Option<&str>,
        inputs: &std::collections::BTreeMap<String, String>,
    ) -> Result<WorkflowRun> {
        Ok(self
            .post::<WorkflowRunPage, _>(
                &format!("/api/infra/projects/{project_id}/workflow-runs"),
                &serde_json::json!({ "path": workflow_path, "branch": branch, "inputs": inputs }),
            )
            .await?
            .run)
    }

    pub async fn workflow_run(&self, run_id: &str) -> Result<WorkflowRun> {
        Ok(self
            .get::<WorkflowRunPage>(&format!("/api/infra/workflow-runs/{run_id}"))
            .await?
            .run)
    }

    pub async fn workflow_run_answer(&self, run_id: &str) -> Result<Answer<WorkflowRunPage>> {
        self.get_answer(&format!("/api/infra/workflow-runs/{run_id}"))
            .await
    }

    pub async fn cancel_workflow_run(&self, run_id: &str) -> Result<WorkflowRun> {
        Ok(self
            .post_empty::<WorkflowRunPage>(&format!("/api/infra/workflow-runs/{run_id}/cancel"))
            .await?
            .run)
    }

    pub async fn rerun_workflow(&self, run_id: &str) -> Result<WorkflowRun> {
        Ok(self
            .post_empty::<WorkflowRunPage>(&format!("/api/infra/workflow-runs/{run_id}/rerun"))
            .await?
            .run)
    }

    pub async fn workflow_job_log(&self, job_id: &str, after: u64) -> Result<WorkflowLogPage> {
        self.get(&format!(
            "/api/infra/workflow-jobs/{job_id}/logs?after={after}&limit=5000"
        ))
        .await
    }

    pub async fn download_workflow_artifact(
        &self,
        job_id: &str,
        into: &std::path::Path,
    ) -> Result<u64> {
        let response = self
            .request(
                Method::GET,
                &format!("/api/infra/workflow-jobs/{job_id}/artifact"),
                None::<&()>,
            )
            .send()
            .await?;
        if !response.status().is_success() {
            Self::check(response).await?;
            bail!("the server refused the artifact");
        }
        let bytes = response
            .bytes()
            .await
            .context("could not read the artifact")?;
        std::fs::write(into, &bytes)
            .with_context(|| format!("could not write {}", into.display()))?;
        Ok(bytes.len() as u64)
    }
}