rust_cnb/
git.rs

1//! Git API 客户端
2
3use crate::error::{ApiError, Result};
4use reqwest::Client;
5use serde_json::Value;
6use url::Url;
7
8/// Git API 客户端
9pub struct GitClient {
10    base_url: String,
11    client: Client,
12}
13
14impl GitClient {
15    /// 创建新的 Git 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    /// 查询指定分支。Get a branch.
27    pub async fn get_repo_git_branches_branch(
28        &self,
29        repo: String,
30        branch: String,
31    ) -> Result<Value> {
32        let path = format!("/{}/-/git/branches/{}", repo, branch);
33        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
34        
35
36                let request = self.client.request(
37            reqwest::Method::GET,
38            url
39        );
40        
41
42
43
44        let response = request.send().await?;
45        
46        if response.status().is_success() {
47            let json: Value = response.json().await?;
48            Ok(json)
49        } else {
50            Err(ApiError::HttpError(response.status().as_u16()))
51        }
52    }
53
54    /// 删除指定分支。Delete the specified branch.
55    pub async fn delete_repo_git_branches_branch(
56        &self,
57        repo: String,
58        branch: String,
59    ) -> Result<Value> {
60        let path = format!("/{}/-/git/branches/{}", repo, branch);
61        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
62        
63
64                let request = self.client.request(
65            reqwest::Method::DELETE,
66            url
67        );
68        
69
70
71
72        let response = request.send().await?;
73        
74        if response.status().is_success() {
75            let json: Value = response.json().await?;
76            Ok(json)
77        } else {
78            Err(ApiError::HttpError(response.status().as_u16()))
79        }
80    }
81
82    /// 查询指定 commit 的元数据。Get commit annotations.
83    pub async fn get_repo_git_commit_annotations_sha(
84        &self,
85        repo: String,
86        sha: String,
87    ) -> Result<Value> {
88        let path = format!("/{}/-/git/commit-annotations/{}", repo, sha);
89        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
90        
91
92                let request = self.client.request(
93            reqwest::Method::GET,
94            url
95        );
96        
97
98
99
100        let response = request.send().await?;
101        
102        if response.status().is_success() {
103            let json: Value = response.json().await?;
104            Ok(json)
105        } else {
106            Err(ApiError::HttpError(response.status().as_u16()))
107        }
108    }
109
110    /// 设定指定 commit 的元数据。Put commit annotations.
111    pub async fn put_repo_git_commit_annotations_sha(
112        &self,
113        repo: String,
114        sha: String,
115        put_commit_annotations_form: serde_json::Value,
116    ) -> Result<Value> {
117        let path = format!("/{}/-/git/commit-annotations/{}", repo, sha);
118        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
119        
120
121        
122        let mut request = self.client.request(
123            reqwest::Method::PUT,
124            url
125        );
126
127
128
129        request = request.json(&put_commit_annotations_form);
130
131        let response = request.send().await?;
132        
133        if response.status().is_success() {
134            let json: Value = response.json().await?;
135            Ok(json)
136        } else {
137            Err(ApiError::HttpError(response.status().as_u16()))
138        }
139    }
140
141    /// 查询分支列表。List branches.
142    pub async fn get_repo_git_branches(
143        &self,
144        repo: String,
145        page: Option<i64>,
146        page_size: Option<i64>,
147    ) -> Result<Value> {
148        let path = format!("/{}/-/git/branches", repo);
149        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
150        
151        if let Some(value) = page {
152            url.query_pairs_mut().append_pair("page", &value.to_string());
153        }
154        if let Some(value) = page_size {
155            url.query_pairs_mut().append_pair("page_size", &value.to_string());
156        }
157
158                let request = self.client.request(
159            reqwest::Method::GET,
160            url
161        );
162        
163
164
165
166        let response = request.send().await?;
167        
168        if response.status().is_success() {
169            let json: Value = response.json().await?;
170            Ok(json)
171        } else {
172            Err(ApiError::HttpError(response.status().as_u16()))
173        }
174    }
175
176    /// 创建新分支。Create a new branch based on a start point.
177    pub async fn post_repo_git_branches(
178        &self,
179        repo: String,
180        create_branch_form: serde_json::Value,
181    ) -> Result<Value> {
182        let path = format!("/{}/-/git/branches", repo);
183        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
184        
185
186        
187        let mut request = self.client.request(
188            reqwest::Method::POST,
189            url
190        );
191
192
193
194        request = request.json(&create_branch_form);
195
196        let response = request.send().await?;
197        
198        if response.status().is_success() {
199            let json: Value = response.json().await?;
200            Ok(json)
201        } else {
202            Err(ApiError::HttpError(response.status().as_u16()))
203        }
204    }
205
206    /// 查询 commit 列表。List commits.
207    pub async fn get_repo_git_commits(
208        &self,
209        repo: String,
210        sha: Option<String>,
211        author: Option<String>,
212        committer: Option<String>,
213        since: Option<String>,
214        until: Option<String>,
215        page: Option<i64>,
216        page_size: Option<i64>,
217    ) -> Result<Value> {
218        let path = format!("/{}/-/git/commits", repo);
219        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
220        
221        if let Some(value) = sha {
222            url.query_pairs_mut().append_pair("sha", &value.to_string());
223        }
224        if let Some(value) = author {
225            url.query_pairs_mut().append_pair("author", &value.to_string());
226        }
227        if let Some(value) = committer {
228            url.query_pairs_mut().append_pair("committer", &value.to_string());
229        }
230        if let Some(value) = since {
231            url.query_pairs_mut().append_pair("since", &value.to_string());
232        }
233        if let Some(value) = until {
234            url.query_pairs_mut().append_pair("until", &value.to_string());
235        }
236        if let Some(value) = page {
237            url.query_pairs_mut().append_pair("page", &value.to_string());
238        }
239        if let Some(value) = page_size {
240            url.query_pairs_mut().append_pair("page_size", &value.to_string());
241        }
242
243                let request = self.client.request(
244            reqwest::Method::GET,
245            url
246        );
247        
248
249
250
251        let response = request.send().await?;
252        
253        if response.status().is_success() {
254            let json: Value = response.json().await?;
255            Ok(json)
256        } else {
257            Err(ApiError::HttpError(response.status().as_u16()))
258        }
259    }
260
261    /// 打包下载两次 ref 之间的变更文件。Download archive of changed files for a compare.
262    pub async fn get_repo_git_archive_compare_changed_files_base_head(
263        &self,
264        repo: String,
265        base_head: String,
266    ) -> Result<Value> {
267        let path = format!("/{}/-/git/archive-compare-changed-files/{}", repo, base_head);
268        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
269        
270
271                let request = self.client.request(
272            reqwest::Method::GET,
273            url
274        );
275        
276
277
278
279        let response = request.send().await?;
280        
281        if response.status().is_success() {
282            let json: Value = response.json().await?;
283            Ok(json)
284        } else {
285            Err(ApiError::HttpError(response.status().as_u16()))
286        }
287    }
288
289    /// 创建一个 blob。Create a blob.
290    pub async fn post_repo_git_blobs(
291        &self,
292        repo: String,
293        post_blob_form: serde_json::Value,
294    ) -> Result<Value> {
295        let path = format!("/{}/-/git/blobs", repo);
296        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
297        
298
299        
300        let mut request = self.client.request(
301            reqwest::Method::POST,
302            url
303        );
304
305
306
307        request = request.json(&post_blob_form);
308
309        let response = request.send().await?;
310        
311        if response.status().is_success() {
312            let json: Value = response.json().await?;
313            Ok(json)
314        } else {
315            Err(ApiError::HttpError(response.status().as_u16()))
316        }
317    }
318
319    /// 查询指定 tag 的元数据。Query the metadata of the specified tag.
320    pub async fn get_repo_git_tag_annotations_tag(
321        &self,
322        repo: String,
323        tag: String,
324    ) -> Result<Value> {
325        let path = format!("/{}/-/git/tag-annotations/{}", repo, tag);
326        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
327        
328
329                let request = self.client.request(
330            reqwest::Method::GET,
331            url
332        );
333        
334
335
336
337        let response = request.send().await?;
338        
339        if response.status().is_success() {
340            let json: Value = response.json().await?;
341            Ok(json)
342        } else {
343            Err(ApiError::HttpError(response.status().as_u16()))
344        }
345    }
346
347    /// 设定指定 tag 的元数据。Set the metadata of the specified tag.
348    pub async fn put_repo_git_tag_annotations_tag(
349        &self,
350        repo: String,
351        tag: String,
352        put_tag_annotations_form: serde_json::Value,
353    ) -> Result<Value> {
354        let path = format!("/{}/-/git/tag-annotations/{}", repo, tag);
355        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
356        
357
358        
359        let mut request = self.client.request(
360            reqwest::Method::PUT,
361            url
362        );
363
364
365
366        request = request.json(&put_tag_annotations_form);
367
368        let response = request.send().await?;
369        
370        if response.status().is_success() {
371            let json: Value = response.json().await?;
372            Ok(json)
373        } else {
374            Err(ApiError::HttpError(response.status().as_u16()))
375        }
376    }
377
378    /// 查询指定 commit 的 check statuses。List commit check statuses.
379    pub async fn get_repo_git_commit_statuses_commitish(
380        &self,
381        repo: String,
382        commitish: String,
383    ) -> Result<Value> {
384        let path = format!("/{}/-/git/commit-statuses/{}", repo, commitish);
385        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
386        
387
388                let request = self.client.request(
389            reqwest::Method::GET,
390            url
391        );
392        
393
394
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    /// 查询 deferred commit 列表
407    pub async fn get_repo_git_deferred_commits(
408        &self,
409        repo: String,
410        cs: String,
411    ) -> Result<Value> {
412        let path = format!("/{}/-/git/deferred-commits", repo);
413        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
414        
415        url.query_pairs_mut().append_pair("cs", &cs.to_string());
416
417                let request = self.client.request(
418            reqwest::Method::GET,
419            url
420        );
421        
422
423
424
425        let response = request.send().await?;
426        
427        if response.status().is_success() {
428            let json: Value = response.json().await?;
429            Ok(json)
430        } else {
431            Err(ApiError::HttpError(response.status().as_u16()))
432        }
433    }
434
435    /// 删除指定 tag 的元数据。Delete the metadata of the specified tag.
436    pub async fn delete_repo_git_tag_annotations_tag_with_key(
437        &self,
438        repo: String,
439        tag_with_key: String,
440    ) -> Result<Value> {
441        let path = format!("/{}/-/git/tag-annotations/{}", repo, tag_with_key);
442        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
443        
444
445                let request = self.client.request(
446            reqwest::Method::DELETE,
447            url
448        );
449        
450
451
452
453        let response = request.send().await?;
454        
455        if response.status().is_success() {
456            let json: Value = response.json().await?;
457            Ok(json)
458        } else {
459            Err(ApiError::HttpError(response.status().as_u16()))
460        }
461    }
462
463    /// 查询指定 commit 的附件。List commit assets.
464    pub async fn get_repo_git_commit_assets_sha_1(
465        &self,
466        repo: String,
467        sha_1: String,
468    ) -> Result<Value> {
469        let path = format!("/{}/-/git/commit-assets/{}", repo, sha_1);
470        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
471        
472
473                let request = self.client.request(
474            reqwest::Method::GET,
475            url
476        );
477        
478
479
480
481        let response = request.send().await?;
482        
483        if response.status().is_success() {
484            let json: Value = response.json().await?;
485            Ok(json)
486        } else {
487            Err(ApiError::HttpError(response.status().as_u16()))
488        }
489    }
490
491    /// 查询标签列表。List tags.
492    pub async fn get_repo_git_tags(
493        &self,
494        repo: String,
495        page: Option<i64>,
496        page_size: Option<i64>,
497    ) -> Result<Value> {
498        let path = format!("/{}/-/git/tags", repo);
499        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
500        
501        if let Some(value) = page {
502            url.query_pairs_mut().append_pair("page", &value.to_string());
503        }
504        if let Some(value) = page_size {
505            url.query_pairs_mut().append_pair("page_size", &value.to_string());
506        }
507
508                let request = self.client.request(
509            reqwest::Method::GET,
510            url
511        );
512        
513
514
515
516        let response = request.send().await?;
517        
518        if response.status().is_success() {
519            let json: Value = response.json().await?;
520            Ok(json)
521        } else {
522            Err(ApiError::HttpError(response.status().as_u16()))
523        }
524    }
525
526    /// 创建一个 tag。Create a tag.
527    pub async fn post_repo_git_tags(
528        &self,
529        repo: String,
530        post_tag_form: serde_json::Value,
531    ) -> Result<Value> {
532        let path = format!("/{}/-/git/tags", repo);
533        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
534        
535
536        
537        let mut request = self.client.request(
538            reqwest::Method::POST,
539            url
540        );
541
542
543
544        request = request.json(&post_tag_form);
545
546        let response = request.send().await?;
547        
548        if response.status().is_success() {
549            let json: Value = response.json().await?;
550            Ok(json)
551        } else {
552            Err(ApiError::HttpError(response.status().as_u16()))
553        }
554    }
555
556    /// 查询指定 commit 的元数据。Get commit annotations in batch.
557    pub async fn post_repo_git_commit_annotations_in_batch(
558        &self,
559        repo: String,
560        get_commit_annotations_form: serde_json::Value,
561    ) -> Result<Value> {
562        let path = format!("/{}/-/git/commit-annotations-in-batch", repo);
563        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
564        
565
566        
567        let mut request = self.client.request(
568            reqwest::Method::POST,
569            url
570        );
571
572
573
574        request = request.json(&get_commit_annotations_form);
575
576        let response = request.send().await?;
577        
578        if response.status().is_success() {
579            let json: Value = response.json().await?;
580            Ok(json)
581        } else {
582            Err(ApiError::HttpError(response.status().as_u16()))
583        }
584    }
585
586    /// 确认 Commit asset 上传完成。Confirm commit asset upload.
587    pub async fn post_repo_git_commit_assets_sha_1_asset_upload_confirmation_upload_token_asset_path(
588        &self,
589        repo: String,
590        sha_1: String,
591        token: String,
592        asset_path: String,
593    ) -> Result<Value> {
594        let path = format!("/{}/-/git/commit-assets/{}/asset-upload-confirmation/{}/{}", repo, sha_1, token, asset_path);
595        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
596        
597
598                let request = self.client.request(
599            reqwest::Method::POST,
600            url
601        );
602        
603
604
605
606        let response = request.send().await?;
607        
608        if response.status().is_success() {
609            let json: Value = response.json().await?;
610            Ok(json)
611        } else {
612            Err(ApiError::HttpError(response.status().as_u16()))
613        }
614    }
615
616    /// 打包下载 commit 变更文件。Download archive of changed files for a commit.
617    pub async fn get_repo_git_archive_commit_changed_files_sha_1(
618        &self,
619        repo: String,
620        sha_1: String,
621    ) -> Result<Value> {
622        let path = format!("/{}/-/git/archive-commit-changed-files/{}", repo, sha_1);
623        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
624        
625
626                let request = self.client.request(
627            reqwest::Method::GET,
628            url
629        );
630        
631
632
633
634        let response = request.send().await?;
635        
636        if response.status().is_success() {
637            let json: Value = response.json().await?;
638            Ok(json)
639        } else {
640            Err(ApiError::HttpError(response.status().as_u16()))
641        }
642    }
643
644    /// 删除指定 commit 的元数据。Delete commit annotation.
645    pub async fn delete_repo_git_commit_annotations_sha_key(
646        &self,
647        repo: String,
648        sha: String,
649        key: String,
650    ) -> Result<Value> {
651        let path = format!("/{}/-/git/commit-annotations/{}/{}", repo, sha, key);
652        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
653        
654
655                let request = self.client.request(
656            reqwest::Method::DELETE,
657            url
658        );
659        
660
661
662
663        let response = request.send().await?;
664        
665        if response.status().is_success() {
666            let json: Value = response.json().await?;
667            Ok(json)
668        } else {
669            Err(ApiError::HttpError(response.status().as_u16()))
670        }
671    }
672
673    /// 查询指定 Tag。Get a tag.
674    pub async fn get_repo_git_tags_tag(
675        &self,
676        repo: String,
677        tag: String,
678    ) -> Result<Value> {
679        let path = format!("/{}/-/git/tags/{}", repo, tag);
680        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
681        
682
683                let request = self.client.request(
684            reqwest::Method::GET,
685            url
686        );
687        
688
689
690
691        let response = request.send().await?;
692        
693        if response.status().is_success() {
694            let json: Value = response.json().await?;
695            Ok(json)
696        } else {
697            Err(ApiError::HttpError(response.status().as_u16()))
698        }
699    }
700
701    /// 删除指定标签。Delete the specified tag.
702    pub async fn delete_repo_git_tags_tag(
703        &self,
704        repo: String,
705        tag: String,
706    ) -> Result<Value> {
707        let path = format!("/{}/-/git/tags/{}", repo, tag);
708        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
709        
710
711                let request = self.client.request(
712            reqwest::Method::DELETE,
713            url
714        );
715        
716
717
718
719        let response = request.send().await?;
720        
721        if response.status().is_success() {
722            let json: Value = response.json().await?;
723            Ok(json)
724        } else {
725            Err(ApiError::HttpError(response.status().as_u16()))
726        }
727    }
728
729    /// 删除指定 commit 的附件。Delete commit asset.
730    pub async fn delete_repo_git_commit_assets_sha_1_asset_id(
731        &self,
732        repo: String,
733        sha_1: String,
734        asset_id: String,
735    ) -> Result<Value> {
736        let path = format!("/{}/-/git/commit-assets/{}/{}", repo, sha_1, asset_id);
737        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
738        
739
740                let request = self.client.request(
741            reqwest::Method::DELETE,
742            url
743        );
744        
745
746
747
748        let response = request.send().await?;
749        
750        if response.status().is_success() {
751            let json: Value = response.json().await?;
752            Ok(json)
753        } else {
754            Err(ApiError::HttpError(response.status().as_u16()))
755        }
756    }
757
758    /// 查询仓库文件列表或文件。List repository files or file.
759    pub async fn get_repo_git_contents_file_path(
760        &self,
761        repo: String,
762        file_path: String,
763        r#ref: Option<String>,
764    ) -> Result<Value> {
765        let path = format!("/{}/-/git/contents/{}", repo, file_path);
766        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
767        
768        if let Some(value) = r#ref {
769            url.query_pairs_mut().append_pair("ref", &value.to_string());
770        }
771
772                let request = self.client.request(
773            reqwest::Method::GET,
774            url
775        );
776        
777
778
779
780        let response = request.send().await?;
781        
782        if response.status().is_success() {
783            let json: Value = response.json().await?;
784            Ok(json)
785        } else {
786            Err(ApiError::HttpError(response.status().as_u16()))
787        }
788    }
789
790    /// 获取仓库默认分支。Get the default branch of the repository.
791    pub async fn get_repo_git_head(
792        &self,
793        repo: String,
794    ) -> Result<Value> {
795        let path = format!("/{}/-/git/head", repo);
796        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
797        
798
799                let request = self.client.request(
800            reqwest::Method::GET,
801            url
802        );
803        
804
805
806
807        let response = request.send().await?;
808        
809        if response.status().is_success() {
810            let json: Value = response.json().await?;
811            Ok(json)
812        } else {
813            Err(ApiError::HttpError(response.status().as_u16()))
814        }
815    }
816
817    /// 查询指定 commit。Get a commit.
818    pub async fn get_repo_git_commits_ref(
819        &self,
820        repo: String,
821        r#ref: String,
822    ) -> Result<Value> {
823        let path = format!("/{}/-/git/commits/{}", repo, r#ref);
824        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
825        
826
827                let request = self.client.request(
828            reqwest::Method::GET,
829            url
830        );
831        
832
833
834
835        let response = request.send().await?;
836        
837        if response.status().is_success() {
838            let json: Value = response.json().await?;
839            Ok(json)
840        } else {
841            Err(ApiError::HttpError(response.status().as_u16()))
842        }
843    }
844
845    /// 对比 base...head。Compare two commits.
846    pub async fn get_repo_git_compare_base_head(
847        &self,
848        repo: String,
849        base_head: String,
850    ) -> Result<Value> {
851        let path = format!("/{}/-/git/compare/{}", repo, base_head);
852        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
853        
854
855                let request = self.client.request(
856            reqwest::Method::GET,
857            url
858        );
859        
860
861
862
863        let response = request.send().await?;
864        
865        if response.status().is_success() {
866            let json: Value = response.json().await?;
867            Ok(json)
868        } else {
869            Err(ApiError::HttpError(response.status().as_u16()))
870        }
871    }
872
873    /// 新增一个 Commit asset。Create a commit asset.
874    pub async fn post_repo_git_commit_assets_sha_1_asset_upload_url(
875        &self,
876        repo: String,
877        sha_1: String,
878        create_commit_asset_upload_url_form: serde_json::Value,
879    ) -> Result<Value> {
880        let path = format!("/{}/-/git/commit-assets/{}/asset-upload-url", repo, sha_1);
881        let url = Url::parse(&format!("{}{}", self.base_url, path))?;
882        
883
884        
885        let mut request = self.client.request(
886            reqwest::Method::POST,
887            url
888        );
889
890
891
892        request = request.json(&create_commit_asset_upload_url_form);
893
894        let response = request.send().await?;
895        
896        if response.status().is_success() {
897            let json: Value = response.json().await?;
898            Ok(json)
899        } else {
900            Err(ApiError::HttpError(response.status().as_u16()))
901        }
902    }
903
904    /// 获取 git lfs 文件下载链接
905    pub async fn get_repo_lfs_oid(
906        &self,
907        repo: String,
908        oid: String,
909        name: String,
910    ) -> Result<Value> {
911        let path = format!("/{}/-/lfs/{}", repo, oid);
912        let mut url = Url::parse(&format!("{}{}", self.base_url, path))?;
913        
914        url.query_pairs_mut().append_pair("name", &name.to_string());
915
916                let request = self.client.request(
917            reqwest::Method::GET,
918            url
919        );
920        
921
922
923
924        let response = request.send().await?;
925        
926        if response.status().is_success() {
927            let json: Value = response.json().await?;
928            Ok(json)
929        } else {
930            Err(ApiError::HttpError(response.status().as_u16()))
931        }
932    }
933
934}