137 lines
3.2 KiB
Rust
137 lines
3.2 KiB
Rust
use chrono::{DateTime, FixedOffset};
|
|
use serde::de::{self, Visitor};
|
|
use serde::{Deserialize, Deserializer};
|
|
use std::fmt;
|
|
use std::marker::PhantomData;
|
|
|
|
pub const ISSUE_QUERY: &str = r#"query ($repo: ID!, $id: String) {
|
|
project (fullPath: $repo) {
|
|
issue (iid: $id) {
|
|
id
|
|
descriptionHtml
|
|
author {
|
|
username
|
|
}
|
|
title
|
|
createdAt
|
|
webUrl
|
|
notes {
|
|
nodes {
|
|
id
|
|
author {
|
|
username
|
|
}
|
|
body
|
|
bodyHtml
|
|
createdAt
|
|
url
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}"#;
|
|
|
|
pub const MR_QUERY: &str = r#"query ($repo: ID!, $id: String!) {
|
|
project (fullPath: $repo) {
|
|
mergeRequest (iid: $id) {
|
|
id
|
|
descriptionHtml
|
|
author {
|
|
username
|
|
}
|
|
title
|
|
createdAt
|
|
webUrl
|
|
notes {
|
|
nodes {
|
|
id
|
|
author {
|
|
username
|
|
}
|
|
body
|
|
bodyHtml
|
|
createdAt
|
|
url
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}"#;
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Data {
|
|
pub data: Project,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Project {
|
|
pub project: IssueOrMR,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub enum IssueOrMR {
|
|
Issue(IssueInfo),
|
|
MergeRequest(IssueInfo),
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct IssueInfo {
|
|
pub id: String,
|
|
pub description_html: String,
|
|
pub author: Author,
|
|
pub title: String,
|
|
#[serde(deserialize_with = "deserialize_datetime")]
|
|
pub created_at: DateTime<FixedOffset>,
|
|
pub web_url: String,
|
|
pub notes: NoteConnection,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Author {
|
|
pub username: String,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct NoteConnection {
|
|
pub nodes: Vec<Note>,
|
|
}
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Note {
|
|
pub id: String,
|
|
pub author: Author,
|
|
pub body: String,
|
|
pub body_html: String,
|
|
#[serde(deserialize_with = "deserialize_datetime")]
|
|
pub created_at: DateTime<FixedOffset>,
|
|
pub url: String,
|
|
}
|
|
|
|
fn deserialize_datetime<'de, D>(deserializer: D) -> Result<DateTime<FixedOffset>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct DeserializeDateTime<T>(PhantomData<fn() -> T>);
|
|
|
|
impl<'de> Visitor<'de> for DeserializeDateTime<DateTime<FixedOffset>> {
|
|
type Value = DateTime<FixedOffset>;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("RFC3339 datetime string")
|
|
}
|
|
|
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
// https://brokenco.de/2020/08/03/serde-deserialize-with-string.html
|
|
DateTime::parse_from_rfc3339(value).map_err(serde::de::Error::custom)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_any(DeserializeDateTime(PhantomData))
|
|
}
|