1use serde::{Deserialize, Serialize};
2
3use crate::outcome::Outcome;
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6pub struct TicketSnapshot {
7 pub id: String,
8 pub name: String,
9 pub blocked_by: Vec<String>,
10 pub worktree: Option<String>,
11 pub target: Option<String>,
12 pub model: Option<String>,
13 pub effort: Option<String>,
14 pub body: String,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum TicketState {
19 Ready,
20 Held,
21 Claimed,
22 Merged,
23 Failed,
24 NeedsReview,
25}
26
27impl TicketState {
28 pub fn as_str(self) -> &'static str {
29 match self {
30 Self::Ready => "ready",
31 Self::Held => "held",
32 Self::Claimed => "claimed",
33 Self::Merged => "merged",
34 Self::Failed => "failed",
35 Self::NeedsReview => "needs_review",
36 }
37 }
38
39 pub fn after_outcome(outcome: Outcome) -> Self {
40 match outcome {
41 Outcome::Merged => Self::Merged,
42 Outcome::Failed => Self::Failed,
43 Outcome::NeedsReview => Self::NeedsReview,
44 Outcome::Cancelled | Outcome::RateLimited | Outcome::Orphaned => Self::Ready,
45 }
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::TicketState;
52 use crate::outcome::Outcome;
53
54 #[test]
55 fn outcomes_determine_the_next_ticket_state() {
56 for (outcome, expected) in [
57 (Outcome::Merged, TicketState::Merged),
58 (Outcome::Failed, TicketState::Failed),
59 (Outcome::NeedsReview, TicketState::NeedsReview),
60 (Outcome::Cancelled, TicketState::Ready),
61 (Outcome::RateLimited, TicketState::Ready),
62 (Outcome::Orphaned, TicketState::Ready),
63 ] {
64 assert_eq!(TicketState::after_outcome(outcome), expected);
65 }
66 }
67}