use time::OffsetDateTime;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RunId(pub String);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct JobId(pub String);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JobStatus {
Queued,
Running,
Ok,
Failed,
Skipped,
Neutral,
}
impl JobStatus {
#[must_use]
pub fn glyph(self) -> &'static str {
match self {
Self::Ok => "✓",
Self::Failed => "×",
Self::Running => "●",
Self::Queued => "·",
Self::Skipped => "–",
Self::Neutral => "○",
}
}
#[must_use]
pub fn worse(self, other: Self) -> Self {
let rank = |s: Self| match s {
Self::Failed => 5,
Self::Running => 4,
Self::Queued => 3,
Self::Skipped => 2,
Self::Neutral => 1,
Self::Ok => 0,
};
if rank(self) >= rank(other) {
self
} else {
other
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CiRun {
pub id: RunId,
pub name: String,
pub title: String,
pub branch: String,
pub commit: String,
pub author: String,
pub created: Option<OffsetDateTime>,
pub status: JobStatus,
pub url: Option<String>,
pub remote: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CiJob {
pub id: JobId,
pub name: String,
pub status: JobStatus,
pub needs: Vec<JobId>,
pub duration_secs: Option<i64>,
}
pub fn fmt_duration(secs: i64) -> String {
let secs = secs.max(0);
if secs < 60 {
format!("{secs}s")
} else {
format!("{}m{:02}s", secs / 60, secs % 60)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RunDetail {
pub run: CiRun,
pub jobs: Vec<CiJob>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogStepMeta {
pub name: String,
pub status: JobStatus,
pub start_key: u64,
pub duration_secs: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogChunk {
pub text: String,
pub steps: Vec<LogStepMeta>,
pub next_offset: u64,
pub done: bool,
}
#[must_use]
pub fn ts_sort_key(iso: &str) -> u64 {
let digits: String = iso.chars().filter(char::is_ascii_digit).take(14).collect();
if digits.len() == 14 {
digits.parse().unwrap_or(0)
} else {
0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PullRequest {
pub number: u64,
pub title: String,
pub url: Option<String>,
pub base_ref: String,
pub head_ref: String,
pub head_oid: String,
pub author: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PrComment {
pub id: String,
pub path: String,
pub line: Option<u32>,
pub start_line: Option<u32>,
pub new_side: bool,
pub body: String,
pub author: String,
pub reply_to: Option<String>,
pub thread_id: Option<String>,
pub resolved: bool,
pub at: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Artifact {
pub name: String,
pub size_bytes: u64,
pub expired: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AnnotationLevel {
Notice,
Warning,
Failure,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Annotation {
pub level: AnnotationLevel,
pub title: String,
pub message: String,
pub path: String,
pub start_line: Option<u64>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct RunExtras {
pub artifacts: Vec<Artifact>,
pub annotations: Vec<Annotation>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Capabilities {
pub dag: DagSource,
pub logs: LogMode,
pub resolve_threads: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DagSource {
RunApi,
ConfigFile,
None,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogMode {
Stream,
Poll,
Dump,
None,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn worse_picks_the_more_severe_status() {
assert_eq!(JobStatus::Ok.worse(JobStatus::Failed), JobStatus::Failed);
assert_eq!(JobStatus::Running.worse(JobStatus::Ok), JobStatus::Running);
assert_eq!(
JobStatus::Queued.worse(JobStatus::Skipped),
JobStatus::Queued
);
assert_eq!(JobStatus::Ok.worse(JobStatus::Ok), JobStatus::Ok);
}
}