Skip to main content

gitee_rs/pulls/
mod.rs

1use crate::{error::GiteeError, GiteeClient};
2use reqwest::Method;
3
4mod models;
5pub use models::*;
6
7impl GiteeClient {
8    /// List all pull requests for a repository
9    pub async fn list_pulls(&self, owner: &str, repo: &str, options: Option<PullListOptions>) -> Result<Vec<PullRequest>, GiteeError> {
10        let url = format!("{}/repos/{}/{}/pulls", self.base_url(), owner, repo);
11        let mut request = self.client().request(Method::GET, &url)
12            .header("Authorization", self.auth_header());
13        
14        if let Some(opts) = options {
15            request = request.query(&opts);
16        }
17
18        let response = request.send().await?;
19
20        if !response.status().is_success() {
21            return Err(GiteeError::ApiError(format!(
22                "Failed to list pull requests: {}",
23                response.status()
24            )));
25        }
26
27        let pulls: Vec<PullRequest> = response.json().await?;
28        Ok(pulls)
29    }
30
31    /// Create a new pull request
32    pub async fn create_pull(
33        &self,
34        owner: &str,
35        repo: &str,
36        title: &str,
37        head: &str,
38        base: &str,
39        body: Option<&str>,
40    ) -> Result<PullRequest, GiteeError> {
41        let url = format!("{}/repos/{}/{}/pulls", self.base_url(), owner, repo);
42
43        let mut payload = std::collections::HashMap::new();
44        payload.insert("title", title.to_string());
45        payload.insert("head", head.to_string());
46        payload.insert("base", base.to_string());
47        if let Some(body) = body {
48            payload.insert("body", body.to_string());
49        }
50
51        let response = self
52            .client()
53            .request(Method::POST, &url)
54            .header("Authorization", self.auth_header())
55            .json(&payload)
56            .send()
57            .await?;
58
59        if !response.status().is_success() {
60            return Err(GiteeError::ApiError(format!(
61                "Failed to create pull request: {}",
62                response.status()
63            )));
64        }
65
66        let pull: PullRequest = response.json().await?;
67        Ok(pull)
68    }
69
70    /// Close a pull request by setting its state to "closed"
71    pub async fn close_pull(
72        &self,
73        owner: &str,
74        repo: &str,
75        pull_number: &str,
76    ) -> Result<PullRequest, GiteeError> {
77        let url = format!(
78            "{}/repos/{}/{}/pulls/{}",
79            self.base_url(),
80            owner,
81            repo,
82            pull_number
83        );
84
85        let payload = serde_json::json!({
86            "state": "closed"
87        });
88
89        let response = self
90            .client()
91            .request(Method::PATCH, &url)
92            .header("Authorization", self.auth_header())
93            .json(&payload)
94            .send()
95            .await?;
96
97        if !response.status().is_success() {
98            return Err(GiteeError::ApiError(format!(
99                "Failed to close pull request: {}",
100                response.status()
101            )));
102        }
103
104        let pull: PullRequest = response.json().await?;
105        Ok(pull)
106    }
107
108    /// Merge a pull request
109    pub async fn merge_pull(
110        &self,
111        owner: &str,
112        repo: &str,
113        pull_number: &str,
114    ) -> Result<PullRequest, GiteeError> {
115        let url = format!(
116            "{}/repos/{}/{}/pulls/{}/merge",
117            self.base_url(),
118            owner,
119            repo,
120            pull_number
121        );
122
123        let response = self
124            .client()
125            .request(Method::PUT, &url)
126            .header("Authorization", self.auth_header())
127            .send()
128            .await?;
129
130        if !response.status().is_success() {
131            return Err(GiteeError::ApiError(format!(
132                "Failed to merge pull request: {}",
133                response.status()
134            )));
135        }
136
137        // Gitee API returns different response for merge, so we'll return the PR info
138        // by getting the PR again after merging
139        self.get_pull_detail(owner, repo, pull_number).await
140    }
141
142    /// Get pull request detail
143    pub async fn get_pull_detail(&self, owner: &str, repo: &str, number: &str) -> Result<PullRequest, GiteeError> {
144        let url = format!("{}/repos/{}/{}/pulls/{}", self.base_url(), owner, repo, number);
145
146        let response = self
147            .client()
148            .request(Method::GET, &url)
149            .header("Authorization", self.auth_header())
150            .send()
151            .await?;
152
153        if !response.status().is_success() {
154            return Err(GiteeError::ApiError(format!(
155                "Failed to get pull request detail: {}",
156                response.status()
157            )));
158        }
159
160        let pull: PullRequest = response.json().await?;
161        Ok(pull)
162    }
163
164    /// Update a pull request
165    pub async fn update_pull(&self, owner: &str, repo: &str, number: &str, title: Option<&str>, body: Option<&str>, state: Option<&str>) -> Result<PullRequest, GiteeError> {
166        let url = format!("{}/repos/{}/{}/pulls/{}", self.base_url(), owner, repo, number);
167
168        let mut payload = std::collections::HashMap::new();
169        if let Some(t) = title {
170            payload.insert("title", t);
171        }
172        if let Some(b) = body {
173            payload.insert("body", b);
174        }
175        if let Some(s) = state {
176            payload.insert("state", s);  // "open" or "closed"
177        }
178
179        let response = self
180            .client()
181            .request(Method::PATCH, &url)
182            .header("Authorization", self.auth_header())
183            .json(&payload)
184            .send()
185            .await?;
186
187        if !response.status().is_success() {
188            return Err(GiteeError::ApiError(format!(
189                "Failed to update pull request: {}",
190                response.status()
191            )));
192        }
193
194        let pull: PullRequest = response.json().await?;
195        Ok(pull)
196    }
197
198    /// Comment on a pull request
199    pub async fn comment_pull(&self, owner: &str, repo: &str, number: &str, body: &str) -> Result<Comment, GiteeError> {
200        let url = format!("{}/repos/{}/{}/pulls/{}/comments", self.base_url(), owner, repo, number);
201
202        let payload = [("body", body)];
203
204        let response = self
205            .client()
206            .request(Method::POST, &url)
207            .header("Authorization", self.auth_header())
208            .form(&payload)
209            .send()
210            .await?;
211
212        if !response.status().is_success() {
213            return Err(GiteeError::ApiError(format!(
214                "Failed to comment on pull request: {}",
215                response.status()
216            )));
217        }
218
219        let comment: Comment = response.json().await?;
220        Ok(comment)
221    }
222
223    /// List pull request comments
224    pub async fn list_pull_comments(&self, owner: &str, repo: &str, number: &str) -> Result<Vec<Comment>, GiteeError> {
225        let url = format!("{}/repos/{}/{}/pulls/{}/comments", self.base_url(), owner, repo, number);
226
227        let response = self
228            .client()
229            .request(Method::GET, &url)
230            .header("Authorization", self.auth_header())
231            .send()
232            .await?;
233
234        if !response.status().is_success() {
235            return Err(GiteeError::ApiError(format!(
236                "Failed to list pull request comments: {}",
237                response.status()
238            )));
239        }
240
241        let comments: Vec<Comment> = response.json().await?;
242        Ok(comments)
243    }
244
245    /// Get diff files for a pull request
246    pub async fn get_diff_files(&self, owner: &str, repo: &str, number: &str) -> Result<Vec<FileDiff>, GiteeError> {
247        let url = format!("{}/repos/{}/{}/pulls/{}/files", self.base_url(), owner, repo, number);
248
249        let response = self
250            .client()
251            .request(Method::GET, &url)
252            .header("Authorization", self.auth_header())
253            .send()
254            .await?;
255
256        if !response.status().is_success() {
257            return Err(GiteeError::ApiError(format!(
258                "Failed to get diff files: {}",
259                response.status()
260            )));
261        }
262
263        let files: Vec<FileDiff> = response.json().await?;
264        Ok(files)
265    }
266}