miyabi_github/
pull_requests.rs1use crate::client::GitHubClient;
6use miyabi_types::error::{MiyabiError, Result};
7use miyabi_types::issue::{PRResult, PRState};
8use octocrab::models::pulls::PullRequest as OctoPR;
9use octocrab::params::pulls::State as PullState;
10use octocrab::params::State;
11
12impl GitHubClient {
13 pub async fn get_pull_request(&self, number: u64) -> Result<PRResult> {
18 let pr = self.client.pulls(&self.owner, &self.repo).get(number).await.map_err(|e| {
19 MiyabiError::GitHub(format!(
20 "Failed to get pull request #{} from {}/{}: {}",
21 number, self.owner, self.repo, e
22 ))
23 })?;
24
25 convert_pull_request(pr)
26 }
27
28 pub async fn list_pull_requests(&self, state: Option<State>) -> Result<Vec<PRResult>> {
33 let pulls = self.client.pulls(&self.owner, &self.repo);
34 let mut handler = pulls.list();
35
36 if let Some(s) = state {
38 handler = handler.state(s);
39 }
40
41 let page = handler.send().await.map_err(|e| {
42 MiyabiError::GitHub(format!(
43 "Failed to list pull requests for {}/{}: {}",
44 self.owner, self.repo, e
45 ))
46 })?;
47
48 page.items.into_iter().map(convert_pull_request).collect()
49 }
50
51 pub async fn create_pull_request(
60 &self,
61 title: &str,
62 head: &str,
63 base: &str,
64 body: Option<&str>,
65 draft: bool,
66 ) -> Result<PRResult> {
67 let pulls = self.client.pulls(&self.owner, &self.repo);
68 let mut handler = pulls.create(title, head, base);
69
70 if let Some(b) = body {
71 handler = handler.body(b);
72 }
73
74 handler = handler.draft(draft);
75
76 let pr = handler.send().await.map_err(|e| {
77 MiyabiError::GitHub(format!(
78 "Failed to create pull request in {}/{}: {}",
79 self.owner, self.repo, e
80 ))
81 })?;
82
83 convert_pull_request(pr)
84 }
85
86 pub async fn update_pull_request(
94 &self,
95 number: u64,
96 title: Option<&str>,
97 body: Option<&str>,
98 state: Option<PullState>,
99 ) -> Result<PRResult> {
100 let pulls = self.client.pulls(&self.owner, &self.repo);
101 let mut handler = pulls.update(number);
102
103 if let Some(t) = title {
104 handler = handler.title(t);
105 }
106
107 if let Some(b) = body {
108 handler = handler.body(b);
109 }
110
111 if let Some(s) = state {
112 handler = handler.state(s);
113 }
114
115 let pr = handler.send().await.map_err(|e| {
116 MiyabiError::GitHub(format!(
117 "Failed to update pull request #{} in {}/{}: {}",
118 number, self.owner, self.repo, e
119 ))
120 })?;
121
122 convert_pull_request(pr)
123 }
124
125 pub async fn close_pull_request(&self, number: u64) -> Result<PRResult> {
127 self.update_pull_request(number, None, None, Some(PullState::Closed)).await
128 }
129
130 pub async fn merge_pull_request(
137 &self,
138 number: u64,
139 commit_title: Option<&str>,
140 commit_message: Option<&str>,
141 ) -> Result<()> {
142 let pulls = self.client.pulls(&self.owner, &self.repo);
143 let mut handler = pulls.merge(number);
144
145 if let Some(title) = commit_title {
146 handler = handler.title(title);
147 }
148
149 if let Some(message) = commit_message {
150 handler = handler.message(message);
151 }
152
153 handler.send().await.map_err(|e| {
154 MiyabiError::GitHub(format!(
155 "Failed to merge pull request #{} in {}/{}: {}",
156 number, self.owner, self.repo, e
157 ))
158 })?;
159
160 Ok(())
161 }
162
163 pub async fn is_mergeable(&self, number: u64) -> Result<bool> {
165 let pr = self.get_pull_request(number).await?;
166
167 Ok(matches!(pr.state, PRState::Open | PRState::Draft))
169 }
170}
171
172fn convert_pull_request(pr: OctoPR) -> Result<PRResult> {
174 use octocrab::models::IssueState as OctoState;
175
176 let state = if pr.merged_at.is_some() {
177 PRState::Merged
178 } else if pr.draft.unwrap_or(false) {
179 PRState::Draft
180 } else {
181 match pr.state {
182 Some(OctoState::Open) => PRState::Open,
183 Some(OctoState::Closed) => PRState::Closed,
184 Some(ref s) => {
185 return Err(MiyabiError::GitHub(format!("Unknown pull request state: {:?}", s)))
186 },
187 None => return Err(MiyabiError::GitHub("Pull request state is missing".to_string())),
188 }
189 };
190
191 Ok(PRResult {
192 number: pr.number,
193 url: pr.html_url.map(|u| u.to_string()).unwrap_or_default(),
194 state,
195 created_at: pr
196 .created_at
197 .ok_or_else(|| MiyabiError::GitHub("Pull request created_at is missing".to_string()))?,
198 })
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_pr_state_conversion() {
207 let _draft = PRState::Draft;
210 let _open = PRState::Open;
211 let _merged = PRState::Merged;
212 let _closed = PRState::Closed;
213 }
214
215 }