rust_cnb/
pulls.rs

1//! Pulls API 客户端
2
3use crate::error::{ApiError, Result};
4use reqwest::Client;
5use serde_json::Value;
6use url::Url;
7
8/// Pulls API 客户端
9pub struct PullsClient {
10    base_url: String,
11    client: Client,
12}
13
14impl PullsClient {
15    /// 创建新的 Pulls API 客户端
16    pub fn new(base_url: String, client: Client) -> Self {
17        Self { base_url, client }
18    }
19
20    /// 设置认证信息
21    pub fn with_auth(self, token: &str) -> Self {
22        // 这里可以扩展认证逻辑
23        self
24    }
25
26    /// 查询特定 pull reviews 列表。List pull reviews.
27    pub async fn get_repo_pulls_number_reviews(
28        &self,
29        repo: String,
30        number: String,
31        page: Option<i64>,
32        page_size: Option<i64>,
33    ) -> Result<Value> {
34        let path = format!("/{}/-/pulls/{}/reviews", repo, number);
35        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
36        
37        if let Some(value) = page {
38            url.query_pairs_mut().append_pair("page", &value.to_string());
39        }
40        if let Some(value) = page_size {
41            url.query_pairs_mut().append_pair("page_size", &value.to_string());
42        }
43
44                let request = self.client.request(
45            reqwest::Method::GET,
46            url
47        );
48        
49
50
51
52        let response = request.send().await?;
53        
54        if response.status().is_success() {
55            let json: Value = response.json().await?;
56            Ok(json)
57        } else {
58            Err(ApiError::HttpError(response.status().as_u16()))
59        }
60    }
61
62    /// 新增一次 pull request 评审。Create a pull review.
63    pub async fn post_repo_pulls_number_reviews(
64        &self,
65        repo: String,
66        number: String,
67        post_pull_review_form: serde_json::Value,
68    ) -> Result<Value> {
69        let path = format!("/{}/-/pulls/{}/reviews", repo, number);
70        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
71        
72
73        
74        let mut request = self.client.request(
75            reqwest::Method::POST,
76            url
77        );
78
79
80
81        request = request.json(&post_pull_review_form);
82
83        let response = request.send().await?;
84        
85        if response.status().is_success() {
86            let json: Value = response.json().await?;
87            Ok(json)
88        } else {
89            Err(ApiError::HttpError(response.status().as_u16()))
90        }
91    }
92
93    /// 查询指定 Pull Review Comments 列表评论。List pull review comments.
94    pub async fn get_repo_pulls_number_reviews_review_id_comments(
95        &self,
96        repo: String,
97        number: i64,
98        review_id: i64,
99        page: Option<i64>,
100        page_size: Option<i64>,
101    ) -> Result<Value> {
102        let path = format!("/{}/-/pulls/{}/reviews/{}/comments", repo, number, review_id);
103        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
104        
105        if let Some(value) = page {
106            url.query_pairs_mut().append_pair("page", &value.to_string());
107        }
108        if let Some(value) = page_size {
109            url.query_pairs_mut().append_pair("page_size", &value.to_string());
110        }
111
112                let request = self.client.request(
113            reqwest::Method::GET,
114            url
115        );
116        
117
118
119
120        let response = request.send().await?;
121        
122        if response.status().is_success() {
123            let json: Value = response.json().await?;
124            Ok(json)
125        } else {
126            Err(ApiError::HttpError(response.status().as_u16()))
127        }
128    }
129
130    /// 检查用户是否可以被添加到 PullRequest 的 Assignees 中。 Checks if a user can be assigned to a pull request.
131    pub async fn get_repo_pulls_number_assignees_assignee(
132        &self,
133        repo: String,
134        number: String,
135        assignee: String,
136    ) -> Result<Value> {
137        let path = format!("/{}/-/pulls/{}/assignees/{}", repo, number, assignee);
138        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
139        
140
141                let request = self.client.request(
142            reqwest::Method::GET,
143            url
144        );
145        
146
147
148
149        let response = request.send().await?;
150        
151        if response.status().is_success() {
152            let json: Value = response.json().await?;
153            Ok(json)
154        } else {
155            Err(ApiError::HttpError(response.status().as_u16()))
156        }
157    }
158
159    /// 查询 Pull 的标签(label) 列表。List labels for a pull.
160    pub async fn get_repo_pulls_number_labels(
161        &self,
162        repo: String,
163        number: String,
164        page: Option<i64>,
165        page_size: Option<i64>,
166    ) -> Result<Value> {
167        let path = format!("/{}/-/pulls/{}/labels", repo, number);
168        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
169        
170        if let Some(value) = page {
171            url.query_pairs_mut().append_pair("page", &value.to_string());
172        }
173        if let Some(value) = page_size {
174            url.query_pairs_mut().append_pair("page_size", &value.to_string());
175        }
176
177                let request = self.client.request(
178            reqwest::Method::GET,
179            url
180        );
181        
182
183
184
185        let response = request.send().await?;
186        
187        if response.status().is_success() {
188            let json: Value = response.json().await?;
189            Ok(json)
190        } else {
191            Err(ApiError::HttpError(response.status().as_u16()))
192        }
193    }
194
195    /// 新增 Pull 标签。Add labels to a pull.
196    pub async fn post_repo_pulls_number_labels(
197        &self,
198        repo: String,
199        number: String,
200        post_pull_labels_form: serde_json::Value,
201    ) -> Result<Value> {
202        let path = format!("/{}/-/pulls/{}/labels", repo, number);
203        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
204        
205
206        
207        let mut request = self.client.request(
208            reqwest::Method::POST,
209            url
210        );
211
212
213
214        request = request.json(&post_pull_labels_form);
215
216        let response = request.send().await?;
217        
218        if response.status().is_success() {
219            let json: Value = response.json().await?;
220            Ok(json)
221        } else {
222            Err(ApiError::HttpError(response.status().as_u16()))
223        }
224    }
225
226    /// 设置 Pull 标签。Set the new labels for a pull.
227    pub async fn put_repo_pulls_number_labels(
228        &self,
229        repo: String,
230        number: String,
231        put_pull_labels_form: serde_json::Value,
232    ) -> Result<Value> {
233        let path = format!("/{}/-/pulls/{}/labels", repo, number);
234        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
235        
236
237        
238        let mut request = self.client.request(
239            reqwest::Method::PUT,
240            url
241        );
242
243
244
245        request = request.json(&put_pull_labels_form);
246
247        let response = request.send().await?;
248        
249        if response.status().is_success() {
250            let json: Value = response.json().await?;
251            Ok(json)
252        } else {
253            Err(ApiError::HttpError(response.status().as_u16()))
254        }
255    }
256
257    /// 清空 Pull 标签。Remove all labels from a pull.
258    pub async fn delete_repo_pulls_number_labels(
259        &self,
260        repo: String,
261        number: String,
262    ) -> Result<Value> {
263        let path = format!("/{}/-/pulls/{}/labels", repo, number);
264        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
265        
266
267                let request = self.client.request(
268            reqwest::Method::DELETE,
269            url
270        );
271        
272
273
274
275        let response = request.send().await?;
276        
277        if response.status().is_success() {
278            let json: Value = response.json().await?;
279            Ok(json)
280        } else {
281            Err(ApiError::HttpError(response.status().as_u16()))
282        }
283    }
284
285    /// 查询指定 PullRequest 的 Assignees。List repository pull request assignees.
286    pub async fn get_repo_pulls_number_assignees(
287        &self,
288        repo: String,
289        number: String,
290    ) -> Result<Value> {
291        let path = format!("/{}/-/pulls/{}/assignees", repo, number);
292        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
293        
294
295                let request = self.client.request(
296            reqwest::Method::GET,
297            url
298        );
299        
300
301
302
303        let response = request.send().await?;
304        
305        if response.status().is_success() {
306            let json: Value = response.json().await?;
307            Ok(json)
308        } else {
309            Err(ApiError::HttpError(response.status().as_u16()))
310        }
311    }
312
313    /// 添加 Assignees 到指定的 PullRequest。 Adds up to 10 assignees to a pull request. Users already assigned to an issue are not replaced.
314    pub async fn post_repo_pulls_number_assignees(
315        &self,
316        repo: String,
317        number: String,
318        post_pull_assignees_form: serde_json::Value,
319    ) -> Result<Value> {
320        let path = format!("/{}/-/pulls/{}/assignees", repo, number);
321        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
322        
323
324        
325        let mut request = self.client.request(
326            reqwest::Method::POST,
327            url
328        );
329
330
331
332        request = request.json(&post_pull_assignees_form);
333
334        let response = request.send().await?;
335        
336        if response.status().is_success() {
337            let json: Value = response.json().await?;
338            Ok(json)
339        } else {
340            Err(ApiError::HttpError(response.status().as_u16()))
341        }
342    }
343
344    /// 删除 PullRequest 中的 Assignees。 Removes one or more assignees from a pull request.
345    pub async fn delete_repo_pulls_number_assignees(
346        &self,
347        repo: String,
348        number: String,
349        delete_pull_assignees_form: serde_json::Value,
350    ) -> Result<Value> {
351        let path = format!("/{}/-/pulls/{}/assignees", repo, number);
352        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
353        
354
355        
356        let mut request = self.client.request(
357            reqwest::Method::DELETE,
358            url
359        );
360
361
362
363        request = request.json(&delete_pull_assignees_form);
364
365        let response = request.send().await?;
366        
367        if response.status().is_success() {
368            let json: Value = response.json().await?;
369            Ok(json)
370        } else {
371            Err(ApiError::HttpError(response.status().as_u16()))
372        }
373    }
374
375    /// 合并一个 Pull Request。Merge a pull request.
376    pub async fn put_repo_pulls_number_merge(
377        &self,
378        repo: String,
379        number: String,
380        merge_pull_request_form: serde_json::Value,
381    ) -> Result<Value> {
382        let path = format!("/{}/-/pulls/{}/merge", repo, number);
383        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
384        
385
386        
387        let mut request = self.client.request(
388            reqwest::Method::PUT,
389            url
390        );
391
392
393
394        request = request.json(&merge_pull_request_form);
395
396        let response = request.send().await?;
397        
398        if response.status().is_success() {
399            let json: Value = response.json().await?;
400            Ok(json)
401        } else {
402            Err(ApiError::HttpError(response.status().as_u16()))
403        }
404    }
405
406    /// 拣选一个已合并的 Pull Request 的提交到选定的分支
407    pub async fn post_repo_pulls_number_cherry_pick(
408        &self,
409        repo: String,
410        number: i64,
411        cherry_pick_pull_request_form: serde_json::Value,
412    ) -> Result<Value> {
413        let path = format!("/{}/-/pulls/{}/cherry-pick", repo, number);
414        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
415        
416
417        
418        let mut request = self.client.request(
419            reqwest::Method::POST,
420            url
421        );
422
423
424
425        request = request.json(&cherry_pick_pull_request_form);
426
427        let response = request.send().await?;
428        
429        if response.status().is_success() {
430            let json: Value = response.json().await?;
431            Ok(json)
432        } else {
433            Err(ApiError::HttpError(response.status().as_u16()))
434        }
435    }
436
437    /// 查询 Pull 列表。List pull requests.
438    pub async fn get_repo_pulls(
439        &self,
440        repo: String,
441        page: Option<i64>,
442        page_size: Option<i64>,
443        state: Option<String>,
444        authors: Option<String>,
445        reviewers: Option<String>,
446        assignees: Option<String>,
447        base_ref: Option<String>,
448    ) -> Result<Value> {
449        let path = format!("/{}/-/pulls", repo);
450        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
451        
452        if let Some(value) = page {
453            url.query_pairs_mut().append_pair("page", &value.to_string());
454        }
455        if let Some(value) = page_size {
456            url.query_pairs_mut().append_pair("page_size", &value.to_string());
457        }
458        if let Some(value) = state {
459            url.query_pairs_mut().append_pair("state", &value.to_string());
460        }
461        if let Some(value) = authors {
462            url.query_pairs_mut().append_pair("authors", &value.to_string());
463        }
464        if let Some(value) = reviewers {
465            url.query_pairs_mut().append_pair("reviewers", &value.to_string());
466        }
467        if let Some(value) = assignees {
468            url.query_pairs_mut().append_pair("assignees", &value.to_string());
469        }
470        if let Some(value) = base_ref {
471            url.query_pairs_mut().append_pair("base_ref", &value.to_string());
472        }
473
474                let request = self.client.request(
475            reqwest::Method::GET,
476            url
477        );
478        
479
480
481
482        let response = request.send().await?;
483        
484        if response.status().is_success() {
485            let json: Value = response.json().await?;
486            Ok(json)
487        } else {
488            Err(ApiError::HttpError(response.status().as_u16()))
489        }
490    }
491
492    /// 新增一个 Pull。Create a pull request.
493    pub async fn post_repo_pulls(
494        &self,
495        repo: String,
496        post_pull_form: serde_json::Value,
497    ) -> Result<Value> {
498        let path = format!("/{}/-/pulls", repo);
499        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
500        
501
502        
503        let mut request = self.client.request(
504            reqwest::Method::POST,
505            url
506        );
507
508
509
510        request = request.json(&post_pull_form);
511
512        let response = request.send().await?;
513        
514        if response.status().is_success() {
515            let json: Value = response.json().await?;
516            Ok(json)
517        } else {
518            Err(ApiError::HttpError(response.status().as_u16()))
519        }
520    }
521
522    /// 查询指定 Pull。Get a pull request.
523    pub async fn get_repo_pulls_number(
524        &self,
525        repo: String,
526        number: String,
527    ) -> Result<Value> {
528        let path = format!("/{}/-/pulls/{}", repo, number);
529        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
530        
531
532                let request = self.client.request(
533            reqwest::Method::GET,
534            url
535        );
536        
537
538
539
540        let response = request.send().await?;
541        
542        if response.status().is_success() {
543            let json: Value = response.json().await?;
544            Ok(json)
545        } else {
546            Err(ApiError::HttpError(response.status().as_u16()))
547        }
548    }
549
550    /// 更新一个 Pull Request。Update a pull request.
551    pub async fn patch_repo_pulls_number(
552        &self,
553        repo: String,
554        number: String,
555        update_pull_request_form: serde_json::Value,
556    ) -> Result<Value> {
557        let path = format!("/{}/-/pulls/{}", repo, number);
558        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
559        
560
561        
562        let mut request = self.client.request(
563            reqwest::Method::PATCH,
564            url
565        );
566
567
568
569        request = request.json(&update_pull_request_form);
570
571        let response = request.send().await?;
572        
573        if response.status().is_success() {
574            let json: Value = response.json().await?;
575            Ok(json)
576        } else {
577            Err(ApiError::HttpError(response.status().as_u16()))
578        }
579    }
580
581    /// 删除 Pull 标签。Remove a label from a pull.
582    pub async fn delete_repo_pulls_number_labels_name(
583        &self,
584        repo: String,
585        number: String,
586        name: String,
587    ) -> Result<Value> {
588        let path = format!("/{}/-/pulls/{}/labels/{}", repo, number, name);
589        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
590        
591
592                let request = self.client.request(
593            reqwest::Method::DELETE,
594            url
595        );
596        
597
598
599
600        let response = request.send().await?;
601        
602        if response.status().is_success() {
603            let json: Value = response.json().await?;
604            Ok(json)
605        } else {
606            Err(ApiError::HttpError(response.status().as_u16()))
607        }
608    }
609
610    /// 查询 Pull Comments 列表。List pull comments requests.
611    pub async fn get_repo_pulls_number_comments(
612        &self,
613        repo: String,
614        number: String,
615        page: Option<i64>,
616        page_size: Option<i64>,
617    ) -> Result<Value> {
618        let path = format!("/{}/-/pulls/{}/comments", repo, number);
619        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
620        
621        if let Some(value) = page {
622            url.query_pairs_mut().append_pair("page", &value.to_string());
623        }
624        if let Some(value) = page_size {
625            url.query_pairs_mut().append_pair("page_size", &value.to_string());
626        }
627
628                let request = self.client.request(
629            reqwest::Method::GET,
630            url
631        );
632        
633
634
635
636        let response = request.send().await?;
637        
638        if response.status().is_success() {
639            let json: Value = response.json().await?;
640            Ok(json)
641        } else {
642            Err(ApiError::HttpError(response.status().as_u16()))
643        }
644    }
645
646    /// 新增一个 Pull Comment。Create a pull comment.
647    pub async fn post_repo_pulls_number_comments(
648        &self,
649        repo: String,
650        number: String,
651        post_pull_comment_form: serde_json::Value,
652    ) -> Result<Value> {
653        let path = format!("/{}/-/pulls/{}/comments", repo, number);
654        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
655        
656
657        
658        let mut request = self.client.request(
659            reqwest::Method::POST,
660            url
661        );
662
663
664
665        request = request.json(&post_pull_comment_form);
666
667        let response = request.send().await?;
668        
669        if response.status().is_success() {
670            let json: Value = response.json().await?;
671            Ok(json)
672        } else {
673            Err(ApiError::HttpError(response.status().as_u16()))
674        }
675    }
676
677    /// 还原一个已合并的 Pull Request
678    pub async fn post_repo_pulls_number_revert(
679        &self,
680        repo: String,
681        number: i64,
682        revert_pull_request_form: serde_json::Value,
683    ) -> Result<Value> {
684        let path = format!("/{}/-/pulls/{}/revert", repo, number);
685        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
686        
687
688        
689        let mut request = self.client.request(
690            reqwest::Method::POST,
691            url
692        );
693
694
695
696        request = request.json(&revert_pull_request_form);
697
698        let response = request.send().await?;
699        
700        if response.status().is_success() {
701            let json: Value = response.json().await?;
702            Ok(json)
703        } else {
704            Err(ApiError::HttpError(response.status().as_u16()))
705        }
706    }
707
708    /// 根据numbers查询 Pull 列表。List pull requests by numbers.
709    pub async fn get_repo_pull_in_batch(
710        &self,
711        repo: String,
712        n: Vec<String>,
713    ) -> Result<Value> {
714        let path = format!("/{}/-/pull-in-batch", repo);
715        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
716        
717        for item in &n {
718            url.query_pairs_mut().append_pair("n", item);
719        }
720
721                let request = self.client.request(
722            reqwest::Method::GET,
723            url
724        );
725        
726
727
728
729        let response = request.send().await?;
730        
731        if response.status().is_success() {
732            let json: Value = response.json().await?;
733            Ok(json)
734        } else {
735            Err(ApiError::HttpError(response.status().as_u16()))
736        }
737    }
738
739}