1use std::collections::HashMap;
2use std::sync::Arc;
3
4use reqwest::Client as HttpClient;
5use serde::Deserialize;
6use serde::Serialize;
7use serde_json::Value;
8
9use crate::types::ResultDynError;
10use crate::v3::util as client_util;
11
12pub struct GithubPullRequestClient {
13 pub(crate) http_client: Arc<HttpClient>,
14}
15
16impl GithubPullRequestClient {
17 pub fn new(http_client: Arc<HttpClient>) -> ResultDynError<GithubPullRequestClient> {
18 let client = GithubPullRequestClient { http_client };
19
20 return Ok(client);
21 }
22}
23
24#[derive(Debug, Deserialize, Serialize)]
25pub enum GithubMergeMethod {
26 #[serde(rename = "merge")]
27 Merge,
28
29 #[serde(rename = "rebase")]
30 Rebase,
31
32 #[serde(rename = "squash")]
33 Squash,
34}
35
36#[derive(Debug)]
37pub struct CreatePullRequestInput<'a> {
38 pub title: &'a str,
39 pub repo_path: &'a str,
40 pub branch_name: &'a str,
41 pub into_branch: &'a str,
42}
43
44#[derive(Debug)]
45pub struct MergePullRequestInput<'a> {
46 pub repo_path: &'a str,
47 pub pull_number: &'a str,
48 pub merge_method: GithubMergeMethod,
49}
50
51#[derive(Debug)]
52pub struct GetPullRequestByHeadInput<'a> {
53 pub repo_path: &'a str,
54 pub branch_owner: &'a str,
55 pub branch_name: &'a str,
56}
57
58impl GithubPullRequestClient {
59 pub async fn create<'a>(&self, input: CreatePullRequestInput<'a>) -> ResultDynError<Value> {
60 let CreatePullRequestInput {
61 title,
62 repo_path,
63 branch_name,
64 into_branch,
65 } = input;
66 let mut req_body = HashMap::new();
67 req_body.insert("title", title);
68 req_body.insert("head", branch_name);
69 req_body.insert("base", into_branch);
70
71 log::debug!(
72 "Creating pull request {}, req_body: {:?}",
73 repo_path,
74 req_body
75 );
76
77 let req = self
78 .http_client
79 .post(&client_util::api_path(&format!(
80 "/repos/{}/pulls",
81 repo_path
82 )))
83 .body(serde_json::to_string(&req_body)?);
84
85 log::debug!("Initiating request instance {:?} {:?}", req, req_body);
86
87 let res = req.send().await;
88
89 log::debug!("Done creating pull request, response {:?}", res);
90
91 return client_util::result_from_server_response(res?).await;
92 }
93
94 pub async fn merge<'a>(&self, input: MergePullRequestInput<'a>) -> ResultDynError<Value> {
95 let MergePullRequestInput {
96 repo_path,
97 pull_number,
98 merge_method,
99 } = input;
100 let mut req_body = HashMap::new();
101 req_body.insert("merge_method", merge_method);
102
103 log::debug!(
104 "Merging pull request {} pull number {}, req_body: {:?}",
105 repo_path,
106 pull_number,
107 req_body
108 );
109
110 let req = self
111 .http_client
112 .put(&client_util::api_path(&format!(
113 "/repos/{}/pulls/{}/merge",
114 repo_path, pull_number
115 )))
116 .body(serde_json::to_string(&req_body)?);
117
118 log::debug!("Initiating request instance {:?} {:?}", req, req_body);
119
120 let res = req.send().await;
121
122 log::debug!("Done merging pull request, response {:?}", res);
123
124 return client_util::result_from_server_response(res?).await;
125 }
126
127 pub async fn get_by_head<'a>(
132 &self,
133 input: GetPullRequestByHeadInput<'a>,
134 ) -> ResultDynError<Option<Value>> {
135 log::debug!("Getting pull request by head {:?}", input);
136
137 let GetPullRequestByHeadInput {
138 branch_owner,
139 repo_path,
140 branch_name,
141 } = input;
142
143 let req = self.http_client.get(&client_util::api_path(&format!(
144 "/repos/{}/pulls?head={}:{}",
145 repo_path, branch_owner, branch_name
146 )));
147
148 log::debug!(
149 "Initiating request instance to list pull requests {:?}",
150 req
151 );
152
153 let res = req.send().await;
154
155 log::debug!("Done listing pull request, response {:?}", res);
156
157 let body: Value = client_util::result_from_server_response(res?).await?;
158
159 log::debug!("Response body from listing pull request {:?}", body);
160
161 let pull_request: Option<Value> = match &body[0] {
164 Value::Object(obj) => Some(Value::Object(obj.to_owned())),
165 _ => None,
166 };
167
168 if pull_request.is_none() {
174 return Ok(pull_request);
175 }
176
177 let pull_request = pull_request.unwrap();
178
179 let req = self.http_client.get(&client_util::api_path(&format!(
180 "/repos/{}/pulls/{}",
181 repo_path, pull_request["number"]
182 )));
183
184 log::debug!(
185 "Initiating request instance to get pull request detail {:?}",
186 req
187 );
188
189 let res = req.send().await;
190
191 log::debug!("Done getting pull request detail, response {:?}", res);
192
193 return client_util::result_from_server_response(res?)
194 .await
195 .map(Some);
196 }
197}