use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use super::ProviderApp;
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum CheckConclusion {
Success,
Failure,
Neutral,
Cancelled,
TimedOut,
ActionRequired,
Skipped,
Stale,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PublishedCheckConclusion {
Success,
Failure,
Neutral,
Cancelled,
TimedOut,
ActionRequired,
Skipped,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum CheckStatus {
Requested,
Queued,
Pending,
Waiting,
InProgress,
Completed {
conclusion: CheckConclusion,
completed_at: DateTime<Utc>,
},
}
impl CheckStatus {
#[must_use]
pub const fn conclusion(&self) -> Option<CheckConclusion> {
match self {
Self::Completed { conclusion, .. } => Some(*conclusion),
Self::Requested | Self::Queued | Self::Pending | Self::Waiting | Self::InProgress => {
None
}
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct CheckRun {
pub name: String,
pub head_sha: String,
pub via_app: Option<ProviderApp>,
pub status: CheckStatus,
pub summary: Option<String>,
pub html_url: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct CheckOutcome {
pub name: String,
pub head_sha: String,
pub conclusion: PublishedCheckConclusion,
pub summary: String,
}
#[cfg(test)]
mod tests {
use chrono::TimeZone;
use super::*;
#[test]
fn every_status_before_completion_carries_no_conclusion() {
for status in [
CheckStatus::Requested,
CheckStatus::Queued,
CheckStatus::Pending,
CheckStatus::Waiting,
CheckStatus::InProgress,
] {
assert_eq!(status.conclusion(), None);
}
}
#[test]
fn an_observed_check_carries_a_conclusion_only_once_it_has_completed() {
let running = CheckRun {
name: "quality".to_owned(),
head_sha: "head".to_owned(),
via_app: None,
status: CheckStatus::InProgress,
summary: None,
html_url: None,
};
let completed = CheckRun {
status: CheckStatus::Completed {
conclusion: CheckConclusion::TimedOut,
completed_at: Utc.timestamp_opt(3, 0).single().expect("timestamp"),
},
summary: Some("The job exceeded its limit.".to_owned()),
..running.clone()
};
assert_eq!(running.status.conclusion(), None);
assert_eq!(
completed.status.conclusion(),
Some(CheckConclusion::TimedOut)
);
assert_eq!(
serde_json::to_value(&running.status).expect("serializes running status"),
serde_json::json!("in_progress")
);
assert_eq!(
serde_json::to_value(&completed.status).expect("serializes completed status"),
serde_json::json!({
"completed": {
"conclusion": "timed_out",
"completed_at": "1970-01-01T00:00:03Z"
}
})
);
}
#[test]
fn check_conclusions_cover_every_conclusion_a_check_run_reports() {
for (conclusion, expected) in [
(CheckConclusion::Success, "success"),
(CheckConclusion::Failure, "failure"),
(CheckConclusion::Neutral, "neutral"),
(CheckConclusion::Cancelled, "cancelled"),
(CheckConclusion::TimedOut, "timed_out"),
(CheckConclusion::ActionRequired, "action_required"),
(CheckConclusion::Skipped, "skipped"),
(CheckConclusion::Stale, "stale"),
] {
assert_eq!(
serde_json::to_value(conclusion).expect("serializes conclusion"),
serde_json::json!(expected)
);
}
}
}