use serde::{Deserialize, Serialize}; use time::{OffsetDateTime}; use uuid::Uuid; /// Versioned internal job request schema published to the message bus. /// Keep additions backward compatible; never reuse or repurpose existing fields. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct JobRequest { /// Schema identifier for routing and evolution. #[serde(default = "default_schema_version")] pub schema_version: String, // e.g., "jobrequest.v1" /// Unique request identifier for idempotency and tracing correlation. pub request_id: Uuid, /// Source system of this request (forge or manual trigger). pub source: SourceSystem, /// Repository clone URL (SSH or HTTPS). pub repo_url: String, /// Commit SHA to check out. pub commit_sha: String, /// Optional path to the workflow file within the repo (KDL). pub workflow_path: Option, /// Optional specific job id from the workflow to run. pub workflow_job_id: Option, /// Optional scheduling hint selecting a base image or host group. pub runs_on: Option, /// Submission timestamp (UTC). pub submitted_at: OffsetDateTime, } fn default_schema_version() -> String { "jobrequest.v1".to_string() } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum SourceSystem { Github, Forgejo, Manual, } impl JobRequest { pub fn new(source: SourceSystem, repo_url: impl Into, commit_sha: impl Into) -> Self { Self { schema_version: default_schema_version(), request_id: Uuid::new_v4(), source, repo_url: repo_url.into(), commit_sha: commit_sha.into(), workflow_path: None, workflow_job_id: None, runs_on: None, submitted_at: OffsetDateTime::now_utc(), } } }