my-ci 0.0.5

Minimalist Local CICD
use std::time::{SystemTime, UNIX_EPOCH};

use serde::Serialize;

#[derive(Clone, Debug, Serialize)]
pub struct PipelineEvent {
    pub kind: EventKind,
    pub timestamp_ms: u128,
    pub workflow: Option<String>,
    pub phase: Option<WorkflowPhase>,
    pub status: Option<WorkflowStatus>,
    pub message: String,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum EventKind {
    PipelineStarted,
    PipelineFinished,
    PipelineCancelled,
    WorkflowStatus,
    Log,
    Error,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum WorkflowPhase {
    Build,
    Run,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum WorkflowStatus {
    Pending,
    Running,
    Succeeded,
    Failed,
    Skipped,
}

impl PipelineEvent {
    pub fn pipeline(kind: EventKind, message: impl Into<String>) -> Self {
        let event = Self {
            kind,
            timestamp_ms: now_ms(),
            workflow: None,
            phase: None,
            status: None,
            message: message.into(),
        };
        tracing::trace!(
            kind = ?event.kind,
            message = %event.message,
            "created pipeline event"
        );
        event
    }

    pub fn workflow(
        workflow: impl Into<String>,
        phase: WorkflowPhase,
        status: WorkflowStatus,
        message: impl Into<String>,
    ) -> Self {
        let event = Self {
            kind: EventKind::WorkflowStatus,
            timestamp_ms: now_ms(),
            workflow: Some(workflow.into()),
            phase: Some(phase),
            status: Some(status),
            message: message.into(),
        };
        tracing::trace!(
            workflow = ?event.workflow,
            phase = ?event.phase,
            status = ?event.status,
            message = %event.message,
            "created workflow status event"
        );
        event
    }

    pub fn log(
        workflow: impl Into<String>,
        phase: WorkflowPhase,
        message: impl Into<String>,
    ) -> Self {
        let event = Self {
            kind: EventKind::Log,
            timestamp_ms: now_ms(),
            workflow: Some(workflow.into()),
            phase: Some(phase),
            status: None,
            message: message.into(),
        };
        tracing::trace!(
            workflow = ?event.workflow,
            phase = ?event.phase,
            message = %event.message,
            "created workflow log event"
        );
        event
    }

    pub fn error(
        workflow: impl Into<String>,
        phase: WorkflowPhase,
        message: impl Into<String>,
    ) -> Self {
        let event = Self {
            kind: EventKind::Error,
            timestamp_ms: now_ms(),
            workflow: Some(workflow.into()),
            phase: Some(phase),
            status: Some(WorkflowStatus::Failed),
            message: message.into(),
        };
        tracing::trace!(
            workflow = ?event.workflow,
            phase = ?event.phase,
            message = %event.message,
            "created workflow error event"
        );
        event
    }
}

fn now_ms() -> u128 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|d| d.as_millis())
        .unwrap_or(0)
}