227 lines
6.2 KiB
Rust
227 lines
6.2 KiB
Rust
|
|
use std::ops::Deref;
|
||
|
|
|
||
|
|
use reqwest::Method;
|
||
|
|
use serde::Deserialize;
|
||
|
|
|
||
|
|
use crate::{
|
||
|
|
api::{self, user},
|
||
|
|
query,
|
||
|
|
};
|
||
|
|
|
||
|
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Deserialize)]
|
||
|
|
#[serde(transparent)]
|
||
|
|
#[repr(transparent)]
|
||
|
|
pub(crate) struct Id(u64);
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub(crate) struct Issue {
|
||
|
|
pub(crate) id: Id,
|
||
|
|
pub(crate) node_id: String,
|
||
|
|
pub(crate) url: String,
|
||
|
|
pub(crate) repository_url: String,
|
||
|
|
pub(crate) labels_url: String,
|
||
|
|
pub(crate) comments_url: String,
|
||
|
|
pub(crate) events_url: String,
|
||
|
|
pub(crate) html_url: String,
|
||
|
|
pub(crate) number: u64,
|
||
|
|
pub(crate) state: String,
|
||
|
|
pub(crate) state_reason: Option<String>,
|
||
|
|
pub(crate) title: String,
|
||
|
|
pub(crate) body: Option<String>,
|
||
|
|
pub(crate) body_text: Option<String>,
|
||
|
|
pub(crate) body_html: Option<String>,
|
||
|
|
pub(crate) user: Option<user::User>,
|
||
|
|
pub(crate) labels: Vec<Label>,
|
||
|
|
pub(crate) assignee: Option<user::User>,
|
||
|
|
#[serde(default)]
|
||
|
|
pub(crate) assignees: Vec<user::User>,
|
||
|
|
pub(crate) milestone: Option<Milestone>,
|
||
|
|
pub(crate) locked: bool,
|
||
|
|
pub(crate) active_lock_reason: Option<String>,
|
||
|
|
pub(crate) comments: u64,
|
||
|
|
pub(crate) pull_request: Option<PullRequest>,
|
||
|
|
pub(crate) closed_at: Option<String>,
|
||
|
|
pub(crate) created_at: String,
|
||
|
|
pub(crate) updated_at: String,
|
||
|
|
pub(crate) closed_by: Option<user::User>,
|
||
|
|
pub(crate) author_association: String,
|
||
|
|
pub(crate) draft: Option<bool>,
|
||
|
|
pub(crate) timeline_url: Option<String>,
|
||
|
|
pub(crate) repository: Option<Repository>,
|
||
|
|
pub(crate) performed_via_github_app: Option<serde_json::Value>,
|
||
|
|
pub(crate) reactions: Option<Reactions>,
|
||
|
|
pub(crate) pinned_comment: Option<serde_json::Value>,
|
||
|
|
#[serde(rename = "type")]
|
||
|
|
pub(crate) issue_type: Option<IssueType>,
|
||
|
|
pub(crate) sub_issues_summary: Option<SubIssuesSummary>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
#[serde(untagged)]
|
||
|
|
pub(crate) enum Label {
|
||
|
|
Name(String),
|
||
|
|
Detail(LabelDetail),
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub(crate) struct LabelDetail {
|
||
|
|
pub(crate) id: u64,
|
||
|
|
pub(crate) node_id: String,
|
||
|
|
pub(crate) url: String,
|
||
|
|
pub(crate) name: String,
|
||
|
|
pub(crate) description: Option<String>,
|
||
|
|
pub(crate) color: String,
|
||
|
|
pub(crate) default: bool,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub(crate) struct Milestone {
|
||
|
|
pub(crate) url: String,
|
||
|
|
pub(crate) html_url: String,
|
||
|
|
pub(crate) labels_url: String,
|
||
|
|
pub(crate) id: u64,
|
||
|
|
pub(crate) node_id: String,
|
||
|
|
pub(crate) number: u64,
|
||
|
|
pub(crate) state: String,
|
||
|
|
pub(crate) title: String,
|
||
|
|
pub(crate) description: Option<String>,
|
||
|
|
pub(crate) creator: Option<user::User>,
|
||
|
|
pub(crate) open_issues: u64,
|
||
|
|
pub(crate) closed_issues: u64,
|
||
|
|
pub(crate) created_at: String,
|
||
|
|
pub(crate) updated_at: String,
|
||
|
|
pub(crate) closed_at: Option<String>,
|
||
|
|
pub(crate) due_on: Option<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub(crate) struct PullRequest {
|
||
|
|
pub(crate) url: String,
|
||
|
|
pub(crate) html_url: String,
|
||
|
|
pub(crate) diff_url: String,
|
||
|
|
pub(crate) patch_url: String,
|
||
|
|
pub(crate) merged_at: Option<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub(crate) struct Repository {
|
||
|
|
pub(crate) id: u64,
|
||
|
|
pub(crate) node_id: String,
|
||
|
|
pub(crate) name: String,
|
||
|
|
pub(crate) full_name: String,
|
||
|
|
pub(crate) owner: user::User,
|
||
|
|
pub(crate) private: bool,
|
||
|
|
pub(crate) html_url: String,
|
||
|
|
pub(crate) description: Option<String>,
|
||
|
|
pub(crate) fork: bool,
|
||
|
|
pub(crate) url: String,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub(crate) struct Reactions {
|
||
|
|
pub(crate) url: String,
|
||
|
|
pub(crate) total_count: u64,
|
||
|
|
#[serde(rename = "+1")]
|
||
|
|
pub(crate) plus_one: u64,
|
||
|
|
#[serde(rename = "-1")]
|
||
|
|
pub(crate) minus_one: u64,
|
||
|
|
pub(crate) laugh: u64,
|
||
|
|
pub(crate) confused: u64,
|
||
|
|
pub(crate) heart: u64,
|
||
|
|
pub(crate) hooray: u64,
|
||
|
|
pub(crate) rocket: u64,
|
||
|
|
pub(crate) eyes: u64,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub(crate) struct IssueType {
|
||
|
|
pub(crate) id: u64,
|
||
|
|
pub(crate) node_id: String,
|
||
|
|
pub(crate) name: String,
|
||
|
|
pub(crate) description: Option<String>,
|
||
|
|
pub(crate) color: Option<String>,
|
||
|
|
pub(crate) created_at: Option<String>,
|
||
|
|
pub(crate) updated_at: Option<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Deserialize)]
|
||
|
|
pub(crate) struct SubIssuesSummary {
|
||
|
|
pub(crate) total: u64,
|
||
|
|
pub(crate) completed: u64,
|
||
|
|
pub(crate) percent_completed: f64,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Deref for Id {
|
||
|
|
type Target = u64;
|
||
|
|
|
||
|
|
fn deref(&self) -> &Self::Target {
|
||
|
|
&self.0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl From<u64> for Id {
|
||
|
|
fn from(id: u64) -> Self {
|
||
|
|
Self(id)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl std::fmt::Display for Id {
|
||
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
|
|
self.0.fmt(f)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Issue {
|
||
|
|
pub(crate) const FILTER_ASSIGNED: &'static str = "assigned";
|
||
|
|
pub(crate) const FILTER_CREATED: &'static str = "created";
|
||
|
|
pub(crate) const FILTER_MENTIONED: &'static str = "mentioned";
|
||
|
|
pub(crate) const FILTER_SUBSCRIBED: &'static str = "subscribed";
|
||
|
|
pub(crate) const FILTER_REPOS: &'static str = "repos";
|
||
|
|
pub(crate) const FILTER_ALL: &'static str = "all";
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Clone)]
|
||
|
|
pub(crate) struct ListPullRequests {
|
||
|
|
pub filter: Option<&'static str>,
|
||
|
|
pub page: u32,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl query::QueryFn for ListPullRequests {
|
||
|
|
type Data = Vec<Issue>;
|
||
|
|
type Error = api::Error;
|
||
|
|
type Context = api::QueryContext;
|
||
|
|
|
||
|
|
fn key(&self) -> query::Key {
|
||
|
|
format!(
|
||
|
|
"issues/list?pulls=true&page={}&filter={}",
|
||
|
|
self.page,
|
||
|
|
self.filter.unwrap_or_default()
|
||
|
|
)
|
||
|
|
.into()
|
||
|
|
}
|
||
|
|
|
||
|
|
async fn run(&self, c: &Self::Context) -> Result<Self::Data, Self::Error> {
|
||
|
|
#[cfg(debug_assertions)]
|
||
|
|
if c.should_use_fixtures {
|
||
|
|
return super::mock::list_pull_requests(self.filter, self.page);
|
||
|
|
}
|
||
|
|
|
||
|
|
let page_string = self.page.to_string();
|
||
|
|
let mut params: Vec<(&str, &str)> = Vec::with_capacity(4);
|
||
|
|
params.push(("pulls", "true"));
|
||
|
|
params.push(("page", &page_string));
|
||
|
|
params.push(("direction", "desc"));
|
||
|
|
if let Some(filter) = self.filter {
|
||
|
|
params.push(("filter", filter))
|
||
|
|
}
|
||
|
|
|
||
|
|
let res = c
|
||
|
|
.github_request(Method::GET, "/issues")?
|
||
|
|
.query(¶ms)
|
||
|
|
.send()
|
||
|
|
.await?;
|
||
|
|
|
||
|
|
api::parse_response::<Vec<Issue>>(res).await
|
||
|
|
}
|
||
|
|
}
|