automatons_github/resource/check_run/
mod.rs

1use std::fmt::{Display, Formatter};
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Deserializer, Serialize};
5use url::Url;
6
7use crate::resource::{App, CheckSuite, Field, GitSha, MinimalCheckSuite, NodeId, PullRequest};
8use crate::{id, name};
9
10pub use self::conclusion::CheckRunConclusion;
11pub use self::output::{CheckRunOutput, CheckRunOutputSummary, CheckRunOutputTitle};
12pub use self::status::CheckRunStatus;
13
14mod conclusion;
15mod output;
16mod status;
17
18id!(
19    /// Check run id
20    ///
21    /// The [`CheckRunId`] is a unique, numerical id that is used to interact with a check run
22    /// through [GitHub's REST API](https://docs.github.com/en/rest).
23    CheckRunId
24);
25
26name!(
27    /// Check run name
28    ///
29    /// Check runs have a human-readable name that is used prominently in GitHub's user interface.
30    CheckRunName
31);
32
33/// Check run
34///
35/// A check run is an individual test that is part of a check suite. Each run includes a status and
36/// conclusion.
37#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]
38pub struct CheckRun {
39    id: CheckRunId,
40    node_id: NodeId,
41    name: CheckRunName,
42    head_sha: GitSha,
43    external_id: String,
44    url: Url,
45    html_url: Url,
46    details_url: Url,
47    status: CheckRunStatus,
48    conclusion: Option<CheckRunConclusion>,
49    started_at: DateTime<Utc>,
50    completed_at: Option<DateTime<Utc>>,
51    check_suite: Field<MinimalCheckSuite, CheckSuite>,
52    app: App,
53    pull_requests: Vec<PullRequest>,
54
55    #[serde(deserialize_with = "deserialize_output")]
56    output: Option<CheckRunOutput>,
57}
58
59impl CheckRun {
60    /// Returns the check run's id.
61    #[cfg_attr(feature = "tracing", tracing::instrument)]
62    pub fn id(&self) -> CheckRunId {
63        self.id
64    }
65
66    /// Returns the check run's node id.
67    #[cfg_attr(feature = "tracing", tracing::instrument)]
68    pub fn node_id(&self) -> &NodeId {
69        &self.node_id
70    }
71
72    /// Returns the check run's name.
73    #[cfg_attr(feature = "tracing", tracing::instrument)]
74    pub fn name(&self) -> &CheckRunName {
75        &self.name
76    }
77
78    /// Returns the check run's head SHA.
79    #[cfg_attr(feature = "tracing", tracing::instrument)]
80    pub fn head_sha(&self) -> &GitSha {
81        &self.head_sha
82    }
83
84    /// Returns the check run's external id.
85    #[cfg_attr(feature = "tracing", tracing::instrument)]
86    pub fn external_id(&self) -> &str {
87        &self.external_id
88    }
89
90    /// Returns the API endpoint to query the check run.
91    #[cfg_attr(feature = "tracing", tracing::instrument)]
92    pub fn url(&self) -> &Url {
93        &self.url
94    }
95
96    /// Returns the URL to the check run.
97    #[cfg_attr(feature = "tracing", tracing::instrument)]
98    pub fn html_url(&self) -> &Url {
99        &self.html_url
100    }
101
102    /// Returns the URL to the check run's details.
103    #[cfg_attr(feature = "tracing", tracing::instrument)]
104    pub fn details_url(&self) -> &Url {
105        &self.details_url
106    }
107
108    /// Returns the check run's status.
109    #[cfg_attr(feature = "tracing", tracing::instrument)]
110    pub fn status(&self) -> CheckRunStatus {
111        self.status
112    }
113
114    /// Returns the check run's conclusion.
115    #[cfg_attr(feature = "tracing", tracing::instrument)]
116    pub fn conclusion(&self) -> Option<CheckRunConclusion> {
117        self.conclusion
118    }
119
120    /// Returns the date when the check run was started.
121    #[cfg_attr(feature = "tracing", tracing::instrument)]
122    pub fn started_at(&self) -> &DateTime<Utc> {
123        &self.started_at
124    }
125
126    /// Returns the date when the check run was completed.
127    #[cfg_attr(feature = "tracing", tracing::instrument)]
128    pub fn completed_at(&self) -> &Option<DateTime<Utc>> {
129        &self.completed_at
130    }
131
132    /// Returns the check run's output.
133    #[cfg_attr(feature = "tracing", tracing::instrument)]
134    pub fn output(&self) -> &Option<CheckRunOutput> {
135        &self.output
136    }
137
138    /// Returns the check run's check suite.
139    #[cfg_attr(feature = "tracing", tracing::instrument)]
140    pub fn check_suite(&self) -> &Field<MinimalCheckSuite, CheckSuite> {
141        &self.check_suite
142    }
143
144    /// Returns the check run's app.
145    #[cfg_attr(feature = "tracing", tracing::instrument)]
146    pub fn app(&self) -> &App {
147        &self.app
148    }
149
150    /// Returns the check run's pull requests.
151    #[cfg_attr(feature = "tracing", tracing::instrument)]
152    pub fn pull_requests(&self) -> &Vec<PullRequest> {
153        &self.pull_requests
154    }
155}
156
157impl Display for CheckRun {
158    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
159        write!(f, "{}", self.name)
160    }
161}
162
163fn deserialize_output<'de, D>(deserializer: D) -> Result<Option<CheckRunOutput>, D::Error>
164where
165    D: Deserializer<'de>,
166{
167    let json = serde_json::Value::deserialize(deserializer)?;
168
169    let title_field = match json.get("title") {
170        Some(title) => title,
171        None => return Ok(None),
172    };
173
174    // Title is a required field, and if it is null the output has not yet been created.
175    if title_field.is_null() {
176        return Ok(None);
177    }
178
179    // TODO: Remove `expect` and return proper error
180    let output = serde_json::from_value(json).expect("failed to deserialize check run output");
181
182    Ok(Some(output))
183}
184
185#[cfg(test)]
186mod tests {
187    use super::CheckRun;
188
189    #[test]
190    fn trait_deserialize() {
191        let check_run: CheckRun = serde_json::from_str(include_str!(
192            "../../../tests/fixtures/resource/check_run.json"
193        ))
194        .unwrap();
195
196        assert_eq!(&None, check_run.output());
197    }
198
199    #[test]
200    fn trait_send() {
201        fn assert_send<T: Send>() {}
202        assert_send::<CheckRun>();
203    }
204
205    #[test]
206    fn trait_sync() {
207        fn assert_sync<T: Sync>() {}
208        assert_sync::<CheckRun>();
209    }
210}