subalfred_core/github/
mod.rs1#[cfg(test)] mod test;
4
5pub mod substrate;
6
7use std::{env, sync::Arc};
9use githuber::api::{ApiExt, Method::*};
11use reqwest::{
12 Client,
13 header::{ACCEPT, USER_AGENT},
14};
15use serde::{Deserialize, de::DeserializeOwned};
16use crate::{http::CLIENT, prelude::*};
18
19#[derive(Debug, Clone)]
21pub struct ApiClient {
22 inner: Arc<Client>,
23 token: String,
24}
25impl ApiClient {
26 const PER_PAGE: u8 = 100;
27 const USER_AGENT: &'static str = "subalfred-api-client";
28
29 pub fn new() -> Result<Self> {
31 Ok(Self { inner: CLIENT.clone(), token: get_github_token()? })
32 }
33
34 pub async fn request<R, D>(&self, request: &R) -> Result<D>
36 where
37 R: ApiExt,
38 D: DeserializeOwned,
39 {
40 let api = request.api();
41 let payload_params = request.payload_params();
42
43 tracing::trace!("Request({api}),Payload({payload_params:?})");
44
45 let response = match R::METHOD {
46 Delete => todo!(),
47 Get => self
48 .inner
49 .get(api)
50 .header(ACCEPT, R::ACCEPT)
51 .header(USER_AGENT, Self::USER_AGENT)
52 .bearer_auth(&self.token)
53 .query(&payload_params),
54 Patch => todo!(),
55 Post => todo!(),
56 Put => todo!(),
57 }
58 .send()
59 .await
60 .map_err(error::Generic::Reqwest)?
61 .json::<D>()
62 .await
63 .map_err(error::Generic::Reqwest)?;
64
65 Ok(response)
66 }
67
68 pub async fn request_auto_retry<R, D>(&self, request: &R) -> D
74 where
75 R: Clone + ApiExt,
76 D: DeserializeOwned,
77 {
78 for i in 0_u16.. {
79 match self.request::<R, D>(request).await {
80 Ok(r) => return r,
81 Err(e) => {
82 tracing::warn!("request failed dut to: {e:?}, retried {i} times");
83 },
84 }
85 }
86
87 unreachable!(
88 "[core::github] there is an infinity loop before; hence this block can never be reached; qed"
89 )
90 }
91}
92
93#[derive(Debug, Deserialize)]
94struct Commits {
95 commits: Vec<Commit>,
96}
97#[derive(Debug, Deserialize)]
98struct Commit {
99 sha: String,
100}
101
102#[cfg_attr(test, derive(PartialEq, Eq))]
104#[derive(Clone, Debug, Deserialize)]
105pub struct PullRequest {
106 pub title: String,
108 pub html_url: String,
110 pub labels: Vec<Label>,
112}
113#[cfg_attr(test, derive(PartialEq, Eq))]
115#[derive(Clone, Debug, Deserialize)]
116pub struct Label {
117 pub name: String,
119}
120
121fn get_github_token() -> Result<String> {
122 Ok(env::var("GITHUB_TOKEN").map_err(error::Github::NoTokenFound)?)
123}