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