Skip to main content

cbtop/regression_pipeline/
types.rs

1//! Core types for the regression pipeline.
2
3/// Result type for pipeline operations
4pub type PipelineResult<T> = Result<T, PipelineError>;
5
6/// Errors in pipeline operations
7#[derive(Debug, Clone, PartialEq)]
8pub enum PipelineError {
9    /// Git operation failed
10    GitError { reason: String },
11    /// Benchmark execution failed
12    BenchmarkFailed { reason: String },
13    /// Baseline not found
14    BaselineNotFound { commit: String },
15    /// Invalid configuration
16    InvalidConfig { reason: String },
17    /// Timeout waiting for results
18    Timeout { timeout_sec: u64 },
19    /// PR status update failed
20    StatusUpdateFailed { reason: String },
21    /// Artifact storage failed
22    ArtifactError { reason: String },
23}
24
25impl std::fmt::Display for PipelineError {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        match self {
28            Self::GitError { reason } => write!(f, "Git error: {}", reason),
29            Self::BenchmarkFailed { reason } => write!(f, "Benchmark failed: {}", reason),
30            Self::BaselineNotFound { commit } => write!(f, "Baseline not found for {}", commit),
31            Self::InvalidConfig { reason } => write!(f, "Invalid config: {}", reason),
32            Self::Timeout { timeout_sec } => write!(f, "Timeout after {}s", timeout_sec),
33            Self::StatusUpdateFailed { reason } => write!(f, "Status update failed: {}", reason),
34            Self::ArtifactError { reason } => write!(f, "Artifact error: {}", reason),
35        }
36    }
37}
38
39impl std::error::Error for PipelineError {}
40
41/// Pipeline execution status
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum PipelineStatus {
44    /// Pipeline not started
45    Pending,
46    /// Pipeline is running
47    Running,
48    /// Pipeline completed successfully (no regressions)
49    Passed,
50    /// Pipeline completed with warnings (minor regressions)
51    Warning,
52    /// Pipeline failed (significant regressions)
53    Failed,
54    /// Pipeline was cancelled
55    Cancelled,
56    /// Pipeline encountered an error
57    Error,
58}
59
60impl PipelineStatus {
61    /// Check if status is terminal
62    pub fn is_terminal(&self) -> bool {
63        matches!(
64            self,
65            Self::Passed | Self::Warning | Self::Failed | Self::Cancelled | Self::Error
66        )
67    }
68
69    /// Get status name for GitHub
70    pub fn github_state(&self) -> &'static str {
71        match self {
72            Self::Pending => "pending",
73            Self::Running => "pending",
74            Self::Passed => "success",
75            Self::Warning => "success",
76            Self::Failed => "failure",
77            Self::Cancelled => "error",
78            Self::Error => "error",
79        }
80    }
81}
82
83/// Git reference type
84#[derive(Debug, Clone)]
85pub enum GitRef {
86    /// Branch name
87    Branch(String),
88    /// Commit SHA
89    Commit(String),
90    /// Tag name
91    Tag(String),
92    /// Pull request number
93    PullRequest(u64),
94}
95
96impl GitRef {
97    /// Get ref string for git commands
98    pub fn as_ref_str(&self) -> String {
99        match self {
100            Self::Branch(name) => name.clone(),
101            Self::Commit(sha) => sha.clone(),
102            Self::Tag(name) => format!("refs/tags/{}", name),
103            Self::PullRequest(num) => format!("refs/pull/{}/head", num),
104        }
105    }
106}
107
108/// Configuration for the regression pipeline
109#[derive(Debug, Clone)]
110pub struct PipelineConfig {
111    /// Base branch for comparison (default: main)
112    pub base_branch: String,
113    /// Benchmark command to run
114    pub benchmark_command: String,
115    /// Working directory
116    pub work_dir: String,
117    /// Maximum execution time in seconds
118    pub timeout_sec: u64,
119    /// Regression threshold (percent)
120    pub regression_threshold_percent: f64,
121    /// Warning threshold (percent)
122    pub warning_threshold_percent: f64,
123    /// GitHub token for status updates (optional)
124    pub github_token: Option<String>,
125    /// Repository name (owner/repo)
126    pub repository: Option<String>,
127    /// Artifact storage path
128    pub artifact_path: String,
129    /// Number of benchmark iterations
130    pub iterations: u32,
131    /// Warmup iterations
132    pub warmup_iterations: u32,
133}
134
135impl Default for PipelineConfig {
136    fn default() -> Self {
137        Self {
138            base_branch: "main".to_string(),
139            benchmark_command: "cargo bench --no-fail-fast".to_string(),
140            work_dir: ".".to_string(),
141            timeout_sec: 600,
142            regression_threshold_percent: 5.0,
143            warning_threshold_percent: 2.0,
144            github_token: None,
145            repository: None,
146            artifact_path: "./benchmark-artifacts".to_string(),
147            iterations: 10,
148            warmup_iterations: 3,
149        }
150    }
151}
152
153/// PR status check result
154#[derive(Debug, Clone)]
155pub struct StatusCheck {
156    /// Check name
157    pub name: String,
158    /// Status state
159    pub state: PipelineStatus,
160    /// Description
161    pub description: String,
162    /// Target URL for details
163    pub target_url: Option<String>,
164    /// Context (e.g., "cbtop/regression")
165    pub context: String,
166}