Skip to main content

jj_ryu/submit/
progress.rs

1//! Progress callback trait for interface-agnostic updates
2//!
3//! This trait allows different interfaces (CLI, web server, etc.) to receive
4//! progress updates during submission operations.
5
6use crate::error::Error;
7use crate::types::PullRequest;
8use async_trait::async_trait;
9
10/// Submission phase
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Phase {
13    /// Analyzing the change graph
14    Analyzing,
15    /// Planning what to submit
16    Planning,
17    /// Executing submission operations (push, create, update, publish)
18    Executing,
19    /// Adding/updating stack comments
20    AddingComments,
21    /// Submission complete
22    Complete,
23}
24
25impl std::fmt::Display for Phase {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        match self {
28            Self::Analyzing => write!(f, "Analyzing"),
29            Self::Planning => write!(f, "Planning"),
30            Self::Executing => write!(f, "Executing"),
31            Self::AddingComments => write!(f, "Updating stack comments"),
32            Self::Complete => write!(f, "Done"),
33        }
34    }
35}
36
37/// Push operation status
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub enum PushStatus {
40    /// Push started
41    Started,
42    /// Push succeeded
43    Success,
44    /// Bookmark already synced with remote
45    AlreadySynced,
46    /// Push failed with error message
47    Failed(String),
48}
49
50impl std::fmt::Display for PushStatus {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        match self {
53            Self::Started => write!(f, "started"),
54            Self::Success => write!(f, "success"),
55            Self::AlreadySynced => write!(f, "already synced"),
56            Self::Failed(msg) => write!(f, "failed: {msg}"),
57        }
58    }
59}
60
61/// Progress callback trait
62///
63/// Implement this trait to receive progress updates during submission.
64/// - CLI implementations can print to terminal
65/// - Web servers can send SSE or WebSocket messages
66#[async_trait]
67pub trait ProgressCallback: Send + Sync {
68    /// Called when entering a new phase
69    async fn on_phase(&self, phase: Phase);
70
71    /// Called when a bookmark is being pushed
72    async fn on_bookmark_push(&self, bookmark: &str, status: PushStatus);
73
74    /// Called when a PR is created
75    async fn on_pr_created(&self, bookmark: &str, pr: &PullRequest);
76
77    /// Called when a PR is updated
78    async fn on_pr_updated(&self, bookmark: &str, pr: &PullRequest);
79
80    /// Called when an error occurs (non-fatal)
81    async fn on_error(&self, error: &Error);
82
83    /// Called with a general status message
84    async fn on_message(&self, message: &str);
85}
86
87/// No-op progress callback for testing or when progress isn't needed
88pub struct NoopProgress;
89
90#[async_trait]
91impl ProgressCallback for NoopProgress {
92    async fn on_phase(&self, _phase: Phase) {}
93    async fn on_bookmark_push(&self, _bookmark: &str, _status: PushStatus) {}
94    async fn on_pr_created(&self, _bookmark: &str, _pr: &PullRequest) {}
95    async fn on_pr_updated(&self, _bookmark: &str, _pr: &PullRequest) {}
96    async fn on_error(&self, _error: &Error) {}
97    async fn on_message(&self, _message: &str) {}
98}