use time::{format_description::well_known, OffsetDateTime};
use crate::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Date {
pub year: u16,
pub month: u8,
pub day: u8,
}
impl fmt::Display for Date {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Date { year, month, day } = self;
write!(f, "{year}-{month:02}-{day:02}")
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DateFilter {
Created(Date),
Updated(Date),
None,
}
impl fmt::Display for DateFilter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DateFilter::Created(date) => write!(f, "created:{date}"),
DateFilter::Updated(date) => write!(f, "updated:{date}"),
DateFilter::None => f.write_str(""), }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LabelFilter<I, S>
where
I: IntoIterator<Item = S> + Clone,
S: AsRef<str> + fmt::Display + fmt::Debug,
{
Any(I),
All(I),
None(PhantomData<I>),
}
impl LabelFilter<Vec<String>, String> {
pub fn none() -> Self {
LabelFilter::None(PhantomData)
}
}
impl<I, S> fmt::Display for LabelFilter<I, S>
where
I: IntoIterator<Item = S> + Clone,
S: AsRef<str> + fmt::Display + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LabelFilter::Any(labels) => write!(
f,
"label:{}",
labels
.clone()
.into_iter()
.map(|l| format!("\"{l}\""))
.collect::<Vec<String>>()
.join(",")
),
LabelFilter::All(labels) => write!(
f,
"{}",
labels
.clone()
.into_iter()
.map(|l| format!("label:\"{l}\""))
.collect::<Vec<String>>()
.join(" ")
),
LabelFilter::None(_) => f.write_str(""), }
}
}
pub fn timestamp_from_log(log: &str) -> Result<OffsetDateTime> {
static RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z").unwrap());
let captures = RE.captures(log);
if let Some(captures) = captures {
let timestamp = captures
.get(0)
.context("Could not extract timestamp")?
.as_str();
OffsetDateTime::parse(timestamp, &well_known::Iso8601::DEFAULT)
.with_context(|| format!("Could not parse timestamp: {timestamp}"))
} else {
bail!("Could not extract timestamp from log: {log}")
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JobLog {
pub name: String,
pub content: String,
}
impl JobLog {
pub fn new(name: String, content: String) -> Self {
Self { name, content }
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
#[test]
fn test_date_display() {
let date = Date {
year: 2021,
month: 6,
day: 2,
};
assert_eq!(date.to_string(), "2021-06-02");
}
#[test]
fn test_date_filter_display() {
let date = Date {
year: 2021,
month: 6,
day: 2,
};
let date_filter = DateFilter::Created(date);
assert_eq!(date_filter.to_string(), "created:2021-06-02");
}
#[test]
fn test_label_filter_any_display() {
let label_filter = LabelFilter::Any(["kind/bug", "area/bake"]);
assert_eq!(label_filter.to_string(), r#"label:"kind/bug","area/bake""#);
}
#[test]
fn test_label_filter_all_display() {
let label_filter = LabelFilter::All(["kind/bug", "area/bake"]);
assert_eq!(
label_filter.to_string(),
r#"label:"kind/bug" label:"area/bake""#
);
}
#[test]
fn test_label_filter_all_1_display() {
let label_filter = LabelFilter::All(["kind/bug"]);
assert_eq!(label_filter.to_string(), r#"label:"kind/bug""#);
}
}