refactor(cli): extract stage_spinner to shared progress module
Moves stage_spinner() from a private function in sync.rs to a pub function in cli/progress.rs so it can be reused by the timeline and search commands. The function creates a numbered spinner (e.g. [1/3]) for pipeline stages, returning a hidden no-op bar in robot mode to keep caller code path-uniform. sync.rs now imports from crate::cli::progress::stage_spinner instead of defining its own copy. Adds unit tests for robot mode (hidden bar), human mode (prefix/message properties), and prefix formatting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ use tracing::Instrument;
|
|||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use crate::Config;
|
use crate::Config;
|
||||||
|
use crate::cli::progress::stage_spinner;
|
||||||
use crate::core::error::Result;
|
use crate::core::error::Result;
|
||||||
use crate::core::metrics::{MetricsLayer, StageTiming};
|
use crate::core::metrics::{MetricsLayer, StageTiming};
|
||||||
use crate::core::shutdown::ShutdownSignal;
|
use crate::core::shutdown::ShutdownSignal;
|
||||||
@@ -42,22 +43,6 @@ pub struct SyncResult {
|
|||||||
pub status_enrichment_errors: usize,
|
pub status_enrichment_errors: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stage_spinner(stage: u8, total: u8, msg: &str, robot_mode: bool) -> ProgressBar {
|
|
||||||
if robot_mode {
|
|
||||||
return ProgressBar::hidden();
|
|
||||||
}
|
|
||||||
let pb = crate::cli::progress::multi().add(ProgressBar::new_spinner());
|
|
||||||
pb.set_style(
|
|
||||||
ProgressStyle::default_spinner()
|
|
||||||
.template("{spinner:.blue} {prefix} {msg}")
|
|
||||||
.expect("valid template"),
|
|
||||||
);
|
|
||||||
pb.enable_steady_tick(std::time::Duration::from_millis(80));
|
|
||||||
pb.set_prefix(format!("[{stage}/{total}]"));
|
|
||||||
pb.set_message(msg.to_string());
|
|
||||||
pb
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run_sync(
|
pub async fn run_sync(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
options: SyncOptions,
|
options: SyncOptions,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use indicatif::MultiProgress;
|
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
use tracing_subscriber::fmt::MakeWriter;
|
use tracing_subscriber::fmt::MakeWriter;
|
||||||
@@ -9,6 +9,26 @@ pub fn multi() -> &'static MultiProgress {
|
|||||||
&MULTI
|
&MULTI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a spinner for a numbered pipeline stage.
|
||||||
|
///
|
||||||
|
/// Returns a hidden (no-op) bar in robot mode so callers can use
|
||||||
|
/// the same code path regardless of output mode.
|
||||||
|
pub fn stage_spinner(stage: u8, total: u8, msg: &str, robot_mode: bool) -> ProgressBar {
|
||||||
|
if robot_mode {
|
||||||
|
return ProgressBar::hidden();
|
||||||
|
}
|
||||||
|
let pb = multi().add(ProgressBar::new_spinner());
|
||||||
|
pb.set_style(
|
||||||
|
ProgressStyle::default_spinner()
|
||||||
|
.template("{spinner:.blue} {prefix} {msg}")
|
||||||
|
.expect("valid template"),
|
||||||
|
);
|
||||||
|
pb.enable_steady_tick(std::time::Duration::from_millis(80));
|
||||||
|
pb.set_prefix(format!("[{stage}/{total}]"));
|
||||||
|
pb.set_message(msg.to_string());
|
||||||
|
pb
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SuspendingWriter;
|
pub struct SuspendingWriter;
|
||||||
|
|
||||||
@@ -50,7 +70,6 @@ impl<'a> MakeWriter<'a> for SuspendingWriter {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use indicatif::ProgressBar;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multi_returns_same_instance() {
|
fn multi_returns_same_instance() {
|
||||||
@@ -88,4 +107,35 @@ mod tests {
|
|||||||
let w = MakeWriter::make_writer(&writer);
|
let w = MakeWriter::make_writer(&writer);
|
||||||
drop(w);
|
drop(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stage_spinner_robot_mode_returns_hidden() {
|
||||||
|
let pb = stage_spinner(1, 3, "Testing...", true);
|
||||||
|
assert!(pb.is_hidden());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stage_spinner_human_mode_sets_properties() {
|
||||||
|
// In non-TTY test environments, MultiProgress may report bars as
|
||||||
|
// hidden. Verify the human-mode code path by checking that prefix
|
||||||
|
// and message are configured (robot-mode returns a bare hidden bar).
|
||||||
|
let pb = stage_spinner(1, 3, "Testing...", false);
|
||||||
|
assert_eq!(pb.prefix(), "[1/3]");
|
||||||
|
assert_eq!(pb.message(), "Testing...");
|
||||||
|
pb.finish_and_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stage_spinner_sets_prefix_format() {
|
||||||
|
let pb = stage_spinner(2, 5, "Working...", false);
|
||||||
|
assert_eq!(pb.prefix(), "[2/5]");
|
||||||
|
pb.finish_and_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stage_spinner_sets_message() {
|
||||||
|
let pb = stage_spinner(1, 3, "Seeding timeline...", false);
|
||||||
|
assert_eq!(pb.message(), "Seeding timeline...");
|
||||||
|
pb.finish_and_clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user