ghostflow_github/
queries.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7// We are ignoring warnings about `GraphQLQuery` not being used in this module.
8#![allow(unused_imports)]
9// The GraphQL uses names we need to match.
10#![allow(clippy::upper_case_acronyms)]
11
12use chrono::Utc;
13use graphql_client::GraphQLQuery;
14use log::{log, trace, Level};
15
16type DateTime = chrono::DateTime<Utc>;
17type GitObjectID = String;
18type GitSSHRemote = String;
19type URI = String;
20
21#[rustfmt::skip]
22macro_rules! gql_query_base {
23    ($name:ident) => {
24        #[derive(GraphQLQuery)]
25        #[graphql(
26            schema_path = "src/graphql/schema.graphql",
27            query_path = "src/graphql/query.graphql",
28            deprecated = "warn",
29            response_derives = "Debug, Clone",
30            variables_derives = "Debug, Clone"
31        )]
32        pub struct $name;
33    };
34}
35
36macro_rules! gql_query {
37    ($name:ident, $query_name:expr) => {
38        gql_query_base!($name);
39
40        impl $name {
41            pub(crate) fn name() -> &'static str {
42                $query_name
43            }
44        }
45    };
46}
47
48macro_rules! gql_mutation {
49    ($name:ident, $query_name:expr) => {
50        gql_query_base!($name);
51    };
52}
53
54gql_query!(User, "User");
55gql_query!(Commit, "Commit");
56gql_query!(PullRequest, "PullRequest");
57gql_query!(Repository, "Repository");
58gql_query!(IssueID, "IssueID");
59gql_query!(PullRequestComments, "PullRequestComments");
60gql_query!(PullRequestID, "PullRequestID");
61gql_query!(CommitStatuses, "CommitStatuses");
62// gql_query!(RepositoryID, "RepositoryID");
63gql_query!(PullRequestReactions, "PullRequestReactions");
64gql_query!(IssuesClosedByPullRequest, "IssuesClosedByPullRequest");
65gql_query!(LabelID, "LabelID");
66
67gql_mutation!(PostComment, "PostComment");
68// gql_mutation!(PostCheckRun, "PostCheckRun");
69gql_mutation!(AddIssueLabels, "AddIssueLabels");
70gql_mutation!(RemoveIssueLabels, "RemoveIssueLabels");
71
72pub(crate) struct RepoParentInfo<'a> {
73    pub owner: &'a str,
74    pub name: &'a str,
75    pub ssh_url: &'a str,
76    pub http_url: &'a str,
77    pub parent: Option<(&'a str, &'a str)>,
78}
79
80pub(crate) trait RepoInfo {
81    fn name(&self) -> String;
82    fn ssh_url(&self) -> &str;
83    fn http_url(&self) -> &str;
84    fn parent(&self) -> Option<RepoParentInfo<'_>>;
85}
86
87macro_rules! impl_repo_info {
88    ($type:path) => {
89        impl RepoInfo for $type {
90            fn name(&self) -> String {
91                format!("{}/{}", self.owner.login, self.name)
92            }
93
94            fn ssh_url(&self) -> &str {
95                &self.ssh_url
96            }
97
98            fn http_url(&self) -> &str {
99                &self.url
100            }
101
102            fn parent(&self) -> Option<RepoParentInfo<'_>> {
103                self.parent.as_ref().map(|parent| {
104                    RepoParentInfo {
105                        owner: &parent.owner.login,
106                        name: &parent.name,
107                        ssh_url: &parent.ssh_url.as_ref(),
108                        http_url: &parent.url.as_ref(),
109                        parent: parent.parent.as_ref().map(|grandparent| {
110                            (grandparent.owner.login.as_ref(), grandparent.name.as_ref())
111                        }),
112                    }
113                })
114            }
115        }
116    };
117}
118
119impl_repo_info!(commit::RepoInfo);
120impl_repo_info!(pull_request::RepoInfo);
121impl_repo_info!(repository::RepoInfo);
122impl_repo_info!(issues_closed_by_pull_request::RepoInfo);
123
124/// Rate limit info for GraphQL queries.
125#[derive(Debug, Clone, Copy)]
126pub struct RateLimitInfo {
127    /// The cost of the query.
128    pub cost: i64,
129    /// The "credit" limit for the client.
130    pub limit: i64,
131    /// The number of remaining "credits".
132    pub remaining: i64,
133    /// When the rate limit resets.
134    pub reset_at: DateTime,
135}
136
137impl RateLimitInfo {
138    pub(crate) fn inspect(&self, name: &str) {
139        let (level, desc) = if self.remaining == 0 {
140            (Level::Error, "has been hit")
141        } else if self.remaining <= 100 {
142            (Level::Warn, "is nearing")
143        } else if self.remaining <= 1000 {
144            (Level::Info, "is approaching")
145        } else {
146            (Level::Debug, "is OK")
147        };
148
149        log!(
150            target: "github",
151            level,
152            "{}: rate limit {}: {} / {} left (resets at {})",
153            name, desc, self.remaining, self.limit, self.reset_at,
154        );
155        trace!(
156            target: "github",
157            "rate limit cost: {} / {}",
158            self.cost,
159            self.limit,
160        );
161    }
162}
163
164macro_rules! impl_into_rate_limit_info {
165    ($type:path) => {
166        impl From<$type> for RateLimitInfo {
167            fn from(info: $type) -> Self {
168                Self {
169                    cost: info.cost,
170                    limit: info.limit,
171                    remaining: info.remaining,
172                    reset_at: info.reset_at,
173                }
174            }
175        }
176    };
177}
178
179impl_into_rate_limit_info!(user::RateLimitInfoRateLimit);
180impl_into_rate_limit_info!(commit::RateLimitInfoRateLimit);
181impl_into_rate_limit_info!(pull_request::RateLimitInfoRateLimit);
182impl_into_rate_limit_info!(repository::RateLimitInfoRateLimit);
183impl_into_rate_limit_info!(issue_id::RateLimitInfoRateLimit);
184impl_into_rate_limit_info!(pull_request_comments::RateLimitInfoRateLimit);
185impl_into_rate_limit_info!(pull_request_id::RateLimitInfoRateLimit);
186impl_into_rate_limit_info!(commit_statuses::RateLimitInfoRateLimit);
187// impl_into_rate_limit_info!(repository_id::RateLimitInfoRateLimit);
188impl_into_rate_limit_info!(pull_request_reactions::RateLimitInfoRateLimit);
189impl_into_rate_limit_info!(issues_closed_by_pull_request::RateLimitInfoRateLimit);
190impl_into_rate_limit_info!(label_id::RateLimitInfoRateLimit);