bitbucket_cli/api/
pipelines.rs

1use anyhow::Result;
2
3use super::BitbucketClient;
4use crate::models::{Paginated, Pipeline, PipelineStep, TriggerPipelineRequest};
5
6impl BitbucketClient {
7    /// List pipelines for a repository
8    pub async fn list_pipelines(
9        &self,
10        workspace: &str,
11        repo_slug: &str,
12        page: Option<u32>,
13        pagelen: Option<u32>,
14    ) -> Result<Paginated<Pipeline>> {
15        let mut query = Vec::new();
16
17        // Sort by created_on descending to get most recent first
18        query.push(("sort", "-created_on".to_string()));
19
20        if let Some(p) = page {
21            query.push(("page", p.to_string()));
22        }
23        if let Some(len) = pagelen {
24            query.push(("pagelen", len.to_string()));
25        }
26
27        let query_refs: Vec<(&str, &str)> = query.iter().map(|(k, v)| (*k, v.as_str())).collect();
28
29        let path = format!("/repositories/{}/{}/pipelines", workspace, repo_slug);
30        self.get_with_query(&path, &query_refs).await
31    }
32
33    /// Get a specific pipeline
34    pub async fn get_pipeline(
35        &self,
36        workspace: &str,
37        repo_slug: &str,
38        pipeline_uuid: &str,
39    ) -> Result<Pipeline> {
40        let path = format!(
41            "/repositories/{}/{}/pipelines/{}",
42            workspace, repo_slug, pipeline_uuid
43        );
44        self.get(&path).await
45    }
46
47    /// Trigger a new pipeline
48    pub async fn trigger_pipeline(
49        &self,
50        workspace: &str,
51        repo_slug: &str,
52        request: &TriggerPipelineRequest,
53    ) -> Result<Pipeline> {
54        let path = format!("/repositories/{}/{}/pipelines", workspace, repo_slug);
55        self.post(&path, request).await
56    }
57
58    /// Stop a running pipeline
59    pub async fn stop_pipeline(
60        &self,
61        workspace: &str,
62        repo_slug: &str,
63        pipeline_uuid: &str,
64    ) -> Result<()> {
65        let path = format!(
66            "/repositories/{}/{}/pipelines/{}/stopPipeline",
67            workspace, repo_slug, pipeline_uuid
68        );
69        self.post_no_response(&path, &serde_json::json!({})).await
70    }
71
72    /// List steps for a pipeline
73    pub async fn list_pipeline_steps(
74        &self,
75        workspace: &str,
76        repo_slug: &str,
77        pipeline_uuid: &str,
78    ) -> Result<Paginated<PipelineStep>> {
79        let path = format!(
80            "/repositories/{}/{}/pipelines/{}/steps",
81            workspace, repo_slug, pipeline_uuid
82        );
83        self.get(&path).await
84    }
85
86    /// Get a specific pipeline step
87    pub async fn get_pipeline_step(
88        &self,
89        workspace: &str,
90        repo_slug: &str,
91        pipeline_uuid: &str,
92        step_uuid: &str,
93    ) -> Result<PipelineStep> {
94        let path = format!(
95            "/repositories/{}/{}/pipelines/{}/steps/{}",
96            workspace, repo_slug, pipeline_uuid, step_uuid
97        );
98        self.get(&path).await
99    }
100
101    /// Get pipeline step log
102    pub async fn get_step_log(
103        &self,
104        workspace: &str,
105        repo_slug: &str,
106        pipeline_uuid: &str,
107        step_uuid: &str,
108    ) -> Result<String> {
109        let path = format!(
110            "/repositories/{}/{}/pipelines/{}/steps/{}/log",
111            workspace, repo_slug, pipeline_uuid, step_uuid
112        );
113
114        let response = reqwest::Client::new()
115            .get(self.url(&path))
116            .header("Authorization", self.auth_header())
117            .send()
118            .await?;
119
120        if response.status().is_success() {
121            Ok(response.text().await?)
122        } else {
123            anyhow::bail!("Failed to get step log: {}", response.status())
124        }
125    }
126
127    /// Get pipeline by build number
128    pub async fn get_pipeline_by_build_number(
129        &self,
130        workspace: &str,
131        repo_slug: &str,
132        build_number: u64,
133    ) -> Result<Pipeline> {
134        // Search for the pipeline with the given build number
135        let pipelines = self
136            .list_pipelines(workspace, repo_slug, Some(1), Some(100))
137            .await?;
138
139        pipelines
140            .values
141            .into_iter()
142            .find(|p| p.build_number == build_number)
143            .ok_or_else(|| anyhow::anyhow!("Pipeline #{} not found", build_number))
144    }
145}