From 36112c671d4dd3562c02405e44e6763c44b63e76 Mon Sep 17 00:00:00 2001 From: Catty Steve <4795515+Catty2014@user.noreply.gitee.com> Date: Thu, 23 Apr 2026 18:34:26 +0800 Subject: [PATCH] style: apply rustfmt and clippy fixes across codebase --- .github/workflows/ci.yml | 8 +- workshop-baker/benches/parser_bench.rs | 2 +- workshop-baker/src/bake.rs | 39 +++-- workshop-baker/src/bake/parser.rs | 2 +- workshop-baker/src/bake/schedule.rs | 6 +- workshop-baker/src/daemon.rs | 4 +- workshop-baker/src/engine/executor.rs | 38 +++-- workshop-baker/src/engine/pm/pacman.rs | 26 ++-- workshop-baker/src/engine/repology/local.rs | 5 +- workshop-baker/src/engine/types.rs | 2 +- workshop-baker/src/engine/upm.rs | 4 +- workshop-baker/src/engine/upm/custom.rs | 4 +- workshop-baker/src/error.rs | 2 +- workshop-baker/src/finalize.rs | 11 +- workshop-baker/src/finalize/config.rs | 16 +- workshop-baker/src/finalize/error.rs | 16 +- workshop-baker/src/finalize/event.rs | 30 +++- workshop-baker/src/finalize/plugin/dylib.rs | 2 +- workshop-baker/src/finalize/plugin/fetch.rs | 15 +- .../src/finalize/plugin/fetch/extract.rs | 53 ++++--- .../src/finalize/plugin/fetch/git.rs | 28 ++-- .../src/finalize/plugin/fetch/http.rs | 62 ++++---- .../src/finalize/plugin/internal.rs | 2 +- .../finalize/plugin/internal/insitenotify.rs | 5 +- .../src/finalize/plugin/internal/mail.rs | 87 ++++++----- .../src/finalize/plugin/internal/satori.rs | 2 +- .../src/finalize/plugin/internal/webhook.rs | 2 +- workshop-baker/src/finalize/plugin/rhai.rs | 2 +- workshop-baker/src/finalize/plugin/shell.rs | 145 +++++++++++++----- workshop-baker/src/finalize/stage/hook.rs | 4 +- workshop-baker/src/lib.rs | 6 +- workshop-baker/src/main.rs | 37 +++-- workshop-baker/src/notify.rs | 11 +- workshop-baker/src/notify/error.rs | 2 +- workshop-baker/src/prebake.rs | 63 ++++++-- workshop-baker/src/prebake/event.rs | 30 +++- workshop-baker/src/prebake/stage.rs | 4 +- workshop-baker/src/prebake/stage/bootstrap.rs | 5 +- .../src/prebake/stage/depssystem.rs | 13 +- workshop-baker/src/prebake/stage/depsuser.rs | 5 +- .../src/prebake/stage/environment.rs | 2 +- workshop-baker/src/prebake/stage/hook.rs | 2 +- workshop-baker/src/types.rs | 2 +- workshop-baker/src/types/memsize.rs | 4 +- workshop-baker/src/types/time.rs | 2 +- .../tests/finalize_hook_integration.rs | 12 +- .../tests/finalize_pipeline_integration.rs | 34 ++-- 47 files changed, 532 insertions(+), 326 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 298a25a..c5b9068 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: - components: clippy + components: clippy, rustfmt - name: Cache cargo dependencies uses: actions/cache@v4 @@ -43,8 +43,14 @@ jobs: restore-keys: | ${{ runner.os }}-cargo- + - name: Check formatting + run: cargo fmt -- --check + - name: Check code (cargo check) run: cargo check --all-features - name: Run Clippy lints run: cargo clippy --all-features -- -D warnings + + - name: Run tests + run: cargo test --all-features diff --git a/workshop-baker/benches/parser_bench.rs b/workshop-baker/benches/parser_bench.rs index 87ccb27..743ef6b 100644 --- a/workshop-baker/benches/parser_bench.rs +++ b/workshop-baker/benches/parser_bench.rs @@ -1,4 +1,4 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, black_box, criterion_group, criterion_main}; use std::fs; use std::path::Path; diff --git a/workshop-baker/src/bake.rs b/workshop-baker/src/bake.rs index 29da906..b3a3032 100644 --- a/workshop-baker/src/bake.rs +++ b/workshop-baker/src/bake.rs @@ -1,16 +1,16 @@ +use crate::ExecutionContext; use crate::bake::parser::Function; use crate::cli::Cli; use crate::constant::{DEFAULT_WORKSPACE, STANDALONE_STATUS_DIR, TRIVIAL_SCRIPT_NAME}; use crate::engine::EventSender; use crate::error::BakeError; -use crate::ExecutionContext; use crate::prebake::PrebakeConfig; use crate::prebake::security::get_drop_after; use crate::prebake::stage::PrebakeStage; -use crate::types::buildstatus::{write_stage_status, StageInfo, StagePhase, StageResult}; +use crate::types::buildstatus::{StageInfo, StagePhase, StageResult, write_stage_status}; use crate::{Engine, prebake}; -use std::path::{PathBuf, Path}; use chrono::Utc; +use std::path::{Path, PathBuf}; mod builder; mod decorator; @@ -52,20 +52,19 @@ pub async fn bake( if !has_pipeline || trivial { let stage_start = Utc::now(); - let function = Function{ + let function = Function { name: TRIVIAL_SCRIPT_NAME.to_string(), decorators: vec![], body: script_content, }; - let script = builder::build_script( - &function, - bake_base_path, - &workspace, - None, - use_template, - )?; + let script = + builder::build_script(&function, bake_base_path, &workspace, None, use_template)?; let result = engine.execute_script(&script, &ctx, &event_tx).await; - let stage_result = if result.is_ok() { StageResult::Success } else { StageResult::Failure }; + let stage_result = if result.is_ok() { + StageResult::Success + } else { + StageResult::Failure + }; let _ = write_stage_status( STANDALONE_STATUS_DIR, StageInfo { @@ -73,7 +72,9 @@ pub async fn bake( phase: StagePhase::Bake, substage: "trivial".to_string(), result: stage_result, - duration_ms: Utc::now().signed_duration_since(stage_start).num_milliseconds() as u64, + duration_ms: Utc::now() + .signed_duration_since(stage_start) + .num_milliseconds() as u64, started_at: stage_start, finished_at: Utc::now(), error_message: result.as_ref().err().map(|e| e.to_string()), @@ -95,7 +96,11 @@ pub async fn bake( use_template, )?; let result = engine.execute_script(&script, &ctx, &event_tx).await; - let stage_result = if result.is_ok() { StageResult::Success } else { StageResult::Failure }; + let stage_result = if result.is_ok() { + StageResult::Success + } else { + StageResult::Failure + }; let _ = write_stage_status( STANDALONE_STATUS_DIR, StageInfo { @@ -103,7 +108,9 @@ pub async fn bake( phase: StagePhase::Bake, substage: func.name.clone(), result: stage_result, - duration_ms: Utc::now().signed_duration_since(stage_start).num_milliseconds() as u64, + duration_ms: Utc::now() + .signed_duration_since(stage_start) + .num_milliseconds() as u64, started_at: stage_start, finished_at: Utc::now(), error_message: result.as_ref().err().map(|e| e.to_string()), @@ -141,7 +148,6 @@ fn privileged(prebake_config: &PrebakeConfig) -> bool { PrebakeStage::Never == drop_after } - type TaskResult = Result<(), BakeError>; type TaskFn = Box TaskResult + Send>; @@ -154,5 +160,4 @@ type TaskFn = Box TaskResult + Send>; // fn with_timeout(f: F, duration: i32) -> TaskFn { - // } diff --git a/workshop-baker/src/bake/parser.rs b/workshop-baker/src/bake/parser.rs index 686a2d1..f3b543e 100644 --- a/workshop-baker/src/bake/parser.rs +++ b/workshop-baker/src/bake/parser.rs @@ -1,4 +1,4 @@ -use super::decorator::{parse_decorator, Decorator}; +use super::decorator::{Decorator, parse_decorator}; use crate::bake::BakeError; use lazy_static::lazy_static; use regex::Regex; diff --git a/workshop-baker/src/bake/schedule.rs b/workshop-baker/src/bake/schedule.rs index 550cdbc..0cf72e0 100644 --- a/workshop-baker/src/bake/schedule.rs +++ b/workshop-baker/src/bake/schedule.rs @@ -28,10 +28,8 @@ pub fn sort_function(functions: Vec) -> Result, BakeErro // Add implicit @after for pipeline functions that don't have explicit @after if is_pipeline { - if !has_after { - if let Some(ref last) = last_pipeline { - ts.add_dependency(last, function.name.clone()); - } + if !has_after && let Some(ref last) = last_pipeline { + ts.add_dependency(last, function.name.clone()); } last_pipeline = Some(function.name.clone()); } diff --git a/workshop-baker/src/daemon.rs b/workshop-baker/src/daemon.rs index bd550b0..300ec97 100644 --- a/workshop-baker/src/daemon.rs +++ b/workshop-baker/src/daemon.rs @@ -1,10 +1,10 @@ -use crate::cli::{Cli}; +use crate::cli::Cli; // use serde::Serialize; use serde_json::Value; // use std::path::PathBuf; // use std::sync::Arc; use tokio::io::{AsyncBufReadExt, BufReader}; -use tokio::net::{UnixStream}; +use tokio::net::UnixStream; // use tokio::process::{Child, Command}; // use tokio::signal; // use tokio::sync::RwLock; diff --git a/workshop-baker/src/engine/executor.rs b/workshop-baker/src/engine/executor.rs index ffbdf4e..a8a5907 100644 --- a/workshop-baker/src/engine/executor.rs +++ b/workshop-baker/src/engine/executor.rs @@ -8,8 +8,8 @@ use tokio::time::timeout; use super::pm::PackageManager; use super::types::{ - CgroupManager, EventSender, ExecutionContext, ExecutionError, ExecutionEvent, ExecutionResult, - ResourceLimits, DeltaExecutionContext, StreamType + CgroupManager, DeltaExecutionContext, EventSender, ExecutionContext, ExecutionError, + ExecutionEvent, ExecutionResult, ResourceLimits, StreamType, }; impl super::types::Engine { @@ -68,7 +68,7 @@ impl super::types::Engine { }; if !abs_path.exists() { - return Err(ExecutionError::ScriptNotFound(abs_path)) + return Err(ExecutionError::ScriptNotFound(abs_path)); } let mut command = Command::new(ctx.shell.as_str()); @@ -94,8 +94,8 @@ impl super::types::Engine { cmd: &str, ctx: &ExecutionContext, event_tx: &EventSender, - delta_ctx: &DeltaExecutionContext - ) -> Result { + delta_ctx: &DeltaExecutionContext, + ) -> Result { let mut local_ctx = ctx.clone(); if let Some(working_dir) = &delta_ctx.working_dir { log::debug!("Updating working directory to {}", working_dir.display()); @@ -222,7 +222,7 @@ impl super::types::Engine { return Err(ExecutionError::IoError(format!( "Failed to wait for process: {}", e - ))) + ))); } Err(_) => { log::warn!( @@ -267,21 +267,25 @@ impl super::types::Engine { while let Some(data) = stdout_rx.recv().await { stdout_buf.push_str(&data); if let Some(tx) = event_tx { - let _ = tx.send(ExecutionEvent::OutputChunk { - task_id: task_id.clone(), - stream: StreamType::Stdout, - data: data.clone(), - }).await; + let _ = tx + .send(ExecutionEvent::OutputChunk { + task_id: task_id.clone(), + stream: StreamType::Stdout, + data: data.clone(), + }) + .await; } } while let Some(data) = stderr_rx.recv().await { stderr_buf.push_str(&data); if let Some(tx) = event_tx { - let _ = tx.send(ExecutionEvent::OutputChunk { - task_id: task_id.clone(), - stream: StreamType::Stderr, - data: data.clone(), - }).await; + let _ = tx + .send(ExecutionEvent::OutputChunk { + task_id: task_id.clone(), + stream: StreamType::Stderr, + data: data.clone(), + }) + .await; } } @@ -328,7 +332,7 @@ impl super::types::Engine { package: &[String], pkgman: &dyn PackageManager, ctx: &ExecutionContext, - event_tx: &EventSender + event_tx: &EventSender, ) -> Result { let cmds = pkgman.install(package); let mut combined_result = ExecutionResult { diff --git a/workshop-baker/src/engine/pm/pacman.rs b/workshop-baker/src/engine/pm/pacman.rs index 254813d..7cebd97 100644 --- a/workshop-baker/src/engine/pm/pacman.rs +++ b/workshop-baker/src/engine/pm/pacman.rs @@ -127,7 +127,7 @@ impl PackageManager for Pacman { )); let mut keyring_cmd = Command::new("sh"); - keyring_cmd.arg("-c").arg("pacman-key --init"); + keyring_cmd.arg("-c").arg("pacman-key --init"); vec![cmd, keyring_cmd] } @@ -446,18 +446,22 @@ mod tests { .map(|a| a.to_string_lossy().into_owned()) .collect(); - assert!(recv_args - .join(" ") - .contains("pacman-key --recv-keys ABCDEF123456")); + assert!( + recv_args + .join(" ") + .contains("pacman-key --recv-keys ABCDEF123456") + ); let lsign_cmd = cmds[2].as_std(); let lsign_args: Vec = lsign_cmd .get_args() .map(|a| a.to_string_lossy().into_owned()) .collect(); - assert!(lsign_args - .join(" ") - .contains("pacman-key --lsign-key ABCDEF123456")); + assert!( + lsign_args + .join(" ") + .contains("pacman-key --lsign-key ABCDEF123456") + ); } #[test] @@ -493,9 +497,11 @@ mod tests { .get_args() .map(|a| a.to_string_lossy().into_owned()) .collect(); - assert!(install_args - .join(" ") - .contains("pacman -Sy gnupg --needed --noconfirm")); + assert!( + install_args + .join(" ") + .contains("pacman -Sy gnupg --needed --noconfirm") + ); } #[test] diff --git a/workshop-baker/src/engine/repology/local.rs b/workshop-baker/src/engine/repology/local.rs index 7457d12..ba3ec69 100644 --- a/workshop-baker/src/engine/repology/local.rs +++ b/workshop-baker/src/engine/repology/local.rs @@ -81,10 +81,7 @@ lazy_static::lazy_static! { }; } -pub async fn resolve( - packages: &[String], - target_pm: &str, -) -> Vec { +pub async fn resolve(packages: &[String], target_pm: &str) -> Vec { let mut result = Vec::new(); for pkg in packages { if let Some(mappings) = MAPPING.get(pkg.as_str()) { diff --git a/workshop-baker/src/engine/types.rs b/workshop-baker/src/engine/types.rs index bfe689c..9923a95 100644 --- a/workshop-baker/src/engine/types.rs +++ b/workshop-baker/src/engine/types.rs @@ -5,7 +5,7 @@ use std::time::Duration; use tokio::sync::mpsc; pub use super::cgroups::CgroupManager; -pub use crate::error::{ExecutionError, EXITCODE_EXECUTION_ERROR, EXITCODE_IO_ERROR}; +pub use crate::error::{EXITCODE_EXECUTION_ERROR, EXITCODE_IO_ERROR, ExecutionError}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ResourceUsage { diff --git a/workshop-baker/src/engine/upm.rs b/workshop-baker/src/engine/upm.rs index 5a4f89e..1294fbc 100644 --- a/workshop-baker/src/engine/upm.rs +++ b/workshop-baker/src/engine/upm.rs @@ -34,9 +34,7 @@ pub trait UserPackageManager { } pub fn all_managers() -> Vec> { - vec![ - Box::new(custom::Custom), - ] + vec![Box::new(custom::Custom)] } pub fn select(manager: &str) -> Option> { diff --git a/workshop-baker/src/engine/upm/custom.rs b/workshop-baker/src/engine/upm/custom.rs index bd3798d..5dbee90 100644 --- a/workshop-baker/src/engine/upm/custom.rs +++ b/workshop-baker/src/engine/upm/custom.rs @@ -1,6 +1,6 @@ -use std::path::PathBuf; use async_trait::async_trait; use serde::{Deserialize, Serialize}; +use std::path::PathBuf; use crate::Engine; use crate::engine::types::DeltaExecutionContext; @@ -55,7 +55,7 @@ impl UserPackageManager for Custom { log::error!("Custom command {} failed: {:?}", index, e); return Err(DependencyError::CustomFailed(e)); } - }; + } Ok(()) } } diff --git a/workshop-baker/src/error.rs b/workshop-baker/src/error.rs index c7278c2..12a2c83 100644 --- a/workshop-baker/src/error.rs +++ b/workshop-baker/src/error.rs @@ -14,7 +14,7 @@ pub const EXITCODE_PRIV_DROP_FAILED: i32 = 201; #[derive(Error, Debug)] pub enum BakeError { #[error("Failed to generate staged script {script}: {reason}")] - ScriptGenerationFailed{script: String, reason: String}, + ScriptGenerationFailed { script: String, reason: String }, #[error("Template error: {0}")] TemplateError(#[from] minijinja::Error), diff --git a/workshop-baker/src/finalize.rs b/workshop-baker/src/finalize.rs index 2de64a8..438ebb0 100644 --- a/workshop-baker/src/finalize.rs +++ b/workshop-baker/src/finalize.rs @@ -5,15 +5,15 @@ pub mod plugin; pub mod stage; pub mod template; +use crate::cli::Cli; use crate::constant::FINALIZE_STANDALONE_PLUGIN_PATH; use crate::constant::STANDALONE_STATUS_DIR; -use std::path::PathBuf; -use crate::finalize::plugin::fetch::{self, FetchArgument}; -use crate::cli::Cli; use crate::engine::EventSender; -use crate::types::buildstatus::{read_build_status, BuildStatus, StageResult}; +use crate::finalize::plugin::fetch::{self, FetchArgument}; +use crate::types::buildstatus::{BuildStatus, StageResult, read_build_status}; use crate::types::buildstatus::{StageInfo, StagePhase}; use chrono::Utc; +use std::path::PathBuf; // use crate::finalize::error::PluginError; pub use config::*; pub use error::FinalizeError; @@ -77,8 +77,7 @@ pub async fn finalize( .await; // Read build status from prior stages - let build_status = read_build_status(STANDALONE_STATUS_DIR) - .unwrap_or_default(); + let build_status = read_build_status(STANDALONE_STATUS_DIR).unwrap_or_default(); let final_result = build_status.final_result(); // Determine if we should continue with artifacts/latehook diff --git a/workshop-baker/src/finalize/config.rs b/workshop-baker/src/finalize/config.rs index fe22d33..4c55b75 100644 --- a/workshop-baker/src/finalize/config.rs +++ b/workshop-baker/src/finalize/config.rs @@ -406,9 +406,11 @@ plugin: let result = config.validate(); assert!(result.is_err()); let errors = result.unwrap_err(); - assert!(errors - .iter() - .any(|e| e.contains("show_file_list") && e.contains("no URL"))); + assert!( + errors + .iter() + .any(|e| e.contains("show_file_list") && e.contains("no URL")) + ); } #[test] @@ -444,8 +446,10 @@ plugin: let result = config.validate(); assert!(result.is_err()); let errors = result.unwrap_err(); - assert!(errors - .iter() - .any(|e| e.contains("show_file_list") && e.contains("2 URL definitions"))); + assert!( + errors + .iter() + .any(|e| e.contains("show_file_list") && e.contains("2 URL definitions")) + ); } } diff --git a/workshop-baker/src/finalize/error.rs b/workshop-baker/src/finalize/error.rs index a57188d..337694a 100644 --- a/workshop-baker/src/finalize/error.rs +++ b/workshop-baker/src/finalize/error.rs @@ -1,9 +1,12 @@ use std::path::PathBuf; use thiserror::Error; -use crate::{ExecutionError, error::{ - EXITCODE_EXECUTION_ERROR, EXITCODE_GENERAL_ERROR, EXITCODE_IO_ERROR, EXITCODE_PARSE_ERROR, -}}; +use crate::{ + ExecutionError, + error::{ + EXITCODE_EXECUTION_ERROR, EXITCODE_GENERAL_ERROR, EXITCODE_IO_ERROR, EXITCODE_PARSE_ERROR, + }, +}; #[derive(Error, Debug)] pub enum FinalizeError { @@ -60,16 +63,13 @@ pub enum PluginError { GeneralError(String), #[error("Plugin {name} is not available: {reason}")] - PluginUnavailable{ - name: String, - reason: String, - }, + PluginUnavailable { name: String, reason: String }, #[error("Plugin execution failed: {0}")] ExecutionError(#[from] ExecutionError), #[error("Failed to fetch plugin({name}:{url}): {reason}")] - FetchError{ + FetchError { name: String, url: String, reason: String, diff --git a/workshop-baker/src/finalize/event.rs b/workshop-baker/src/finalize/event.rs index 384bf69..3115e01 100644 --- a/workshop-baker/src/finalize/event.rs +++ b/workshop-baker/src/finalize/event.rs @@ -10,25 +10,39 @@ pub async fn event_receiver( ExecutionEvent::TaskStarted { task_id, timestamp } => { log::debug!( "[{}] [{}] [{}] Task started: {}", - pipeline_name, build_id, timestamp, task_id + pipeline_name, + build_id, + timestamp, + task_id ); } - ExecutionEvent::OutputChunk { task_id, stream, data } => { - match stream { - StreamType::Stdout => print!("[{}] [{}] [stdout] {}", pipeline_name, task_id, data), - StreamType::Stderr => eprint!("[{}] [{}] [stderr] {}", pipeline_name, task_id, data), + ExecutionEvent::OutputChunk { + task_id, + stream, + data, + } => match stream { + StreamType::Stdout => print!("[{}] [{}] [stdout] {}", pipeline_name, task_id, data), + StreamType::Stderr => { + eprint!("[{}] [{}] [stderr] {}", pipeline_name, task_id, data) } - } + }, ExecutionEvent::TaskCompleted { task_id, result } => { log::debug!( "[{}] [{}] Task completed: {} (exit_code={}, duration={:?})", - pipeline_name, build_id, task_id, result.exit_code, result.duration + pipeline_name, + build_id, + task_id, + result.exit_code, + result.duration ); } ExecutionEvent::TaskFailed { task_id, error } => { log::error!( "[{}] [{}] Task failed: {} (error={})", - pipeline_name, build_id, task_id, error + pipeline_name, + build_id, + task_id, + error ); } } diff --git a/workshop-baker/src/finalize/plugin/dylib.rs b/workshop-baker/src/finalize/plugin/dylib.rs index 97aa0d2..14baa56 100644 --- a/workshop-baker/src/finalize/plugin/dylib.rs +++ b/workshop-baker/src/finalize/plugin/dylib.rs @@ -1,5 +1,5 @@ -use crate::finalize::plugin::PluginMetadata; use crate::finalize::plugin::PluginError; +use crate::finalize::plugin::PluginMetadata; use crate::{EventSender, ExecutionContext, finalize::plugin::AsyncPluginFn}; use async_trait::async_trait; diff --git a/workshop-baker/src/finalize/plugin/fetch.rs b/workshop-baker/src/finalize/plugin/fetch.rs index 19e151a..8df628d 100644 --- a/workshop-baker/src/finalize/plugin/fetch.rs +++ b/workshop-baker/src/finalize/plugin/fetch.rs @@ -1,10 +1,10 @@ // Code in this module PARTIALLY OR FULLY utilized AI Coding Agent. -use std::collections::HashSet; use crate::finalize::fetch; use crate::finalize::{ PluginConfig, plugin::{PluginError, RawPluginMap}, }; +use std::collections::HashSet; use std::path::Path; mod checksum; @@ -93,12 +93,13 @@ pub async fn fetch_plugins( _ => {} } log::debug!("Downloading plugin {}", name); - let (source, config) = data.iter_mut().next().ok_or_else(|| { - PluginError::PluginUnavailable { - name: name.clone(), - reason: "no source configured".to_string(), - } - })?; + let (source, config) = + data.iter_mut() + .next() + .ok_or_else(|| PluginError::PluginUnavailable { + name: name.clone(), + reason: "no source configured".to_string(), + })?; let fetch_argument = FetchArgument { checksum: config.checksum.clone(), shallow: config.shallow, diff --git a/workshop-baker/src/finalize/plugin/fetch/extract.rs b/workshop-baker/src/finalize/plugin/fetch/extract.rs index 6a4fdbf..e3c12c9 100644 --- a/workshop-baker/src/finalize/plugin/fetch/extract.rs +++ b/workshop-baker/src/finalize/plugin/fetch/extract.rs @@ -1,6 +1,6 @@ // Code in this module PARTIALLY OR FULLY utilized AI Coding Agent. -use std::path::PathBuf; use crate::finalize::plugin::PluginError; +use std::path::PathBuf; use tokio::task; #[derive(Debug, Clone, Copy)] @@ -12,14 +12,18 @@ pub enum CompressionType { impl CompressionType { pub fn from_path(path: &std::path::Path) -> Result { - let name = path.file_name() + let name = path + .file_name() .and_then(|n| n.to_str()) .unwrap_or("") .to_lowercase(); - + if name.ends_with(".tar.gz") || name.ends_with(".tgz") { Ok(CompressionType::Gzip) - } else if name.ends_with(".tar.zst") || name.ends_with(".tar.zstd") || name.ends_with(".tzst") { + } else if name.ends_with(".tar.zst") + || name.ends_with(".tar.zstd") + || name.ends_with(".tzst") + { Ok(CompressionType::Zstd) } else if name.ends_with(".tar") { Ok(CompressionType::None) @@ -38,51 +42,50 @@ pub async fn extract_tar( compression: CompressionType, ) -> Result<(), PluginError> { if destdir.exists() { - tokio::fs::remove_dir_all(destdir).await.map_err(|e| + tokio::fs::remove_dir_all(destdir).await.map_err(|e| { PluginError::GeneralError(format!("Failed to remove existing directory: {}", e)) - )?; + })?; } - tokio::fs::create_dir_all(destdir).await.map_err(|e| - PluginError::GeneralError(format!("Failed to create directory: {}", e)) - )?; - + tokio::fs::create_dir_all(destdir) + .await + .map_err(|e| PluginError::GeneralError(format!("Failed to create directory: {}", e)))?; + let archive = archive.clone(); let destdir = destdir.clone(); - + task::spawn_blocking(move || { - let file = std::fs::File::open(&archive).map_err(|e| - PluginError::GeneralError(format!("Failed to open archive: {}", e)) - )?; - + let file = std::fs::File::open(&archive) + .map_err(|e| PluginError::GeneralError(format!("Failed to open archive: {}", e)))?; + match compression { CompressionType::Gzip => { let decoder = flate2::read::GzDecoder::new(file); let mut archive = tar::Archive::new(decoder); - archive.unpack(&destdir).map_err(|e| + archive.unpack(&destdir).map_err(|e| { PluginError::GeneralError(format!("Failed to unpack archive: {}", e)) - )?; + })?; } CompressionType::Zstd => { - let decoder = zstd::stream::read::Decoder::new(file).map_err(|e| + let decoder = zstd::stream::read::Decoder::new(file).map_err(|e| { PluginError::GeneralError(format!("Failed to create zstd decoder: {}", e)) - )?; + })?; let mut archive = tar::Archive::new(decoder); - archive.unpack(&destdir).map_err(|e| + archive.unpack(&destdir).map_err(|e| { PluginError::GeneralError(format!("Failed to unpack archive: {}", e)) - )?; + })?; } CompressionType::None => { let mut archive = tar::Archive::new(file); - archive.unpack(&destdir).map_err(|e| + archive.unpack(&destdir).map_err(|e| { PluginError::GeneralError(format!("Failed to unpack archive: {}", e)) - )?; + })?; } }; - + Ok::<(), PluginError>(()) }) .await .map_err(|e| PluginError::GeneralError(format!("Task join error: {}", e)))??; - + Ok(()) } diff --git a/workshop-baker/src/finalize/plugin/fetch/git.rs b/workshop-baker/src/finalize/plugin/fetch/git.rs index 89afdd0..95ce1b3 100644 --- a/workshop-baker/src/finalize/plugin/fetch/git.rs +++ b/workshop-baker/src/finalize/plugin/fetch/git.rs @@ -1,7 +1,7 @@ // Code in this module PARTIALLY OR FULLY utilized AI Coding Agent. +use crate::finalize::plugin::PluginError; use std::path::Path; use tokio::process::Command; -use crate::finalize::plugin::PluginError; #[derive(PartialEq)] pub enum GitVersion { @@ -106,24 +106,16 @@ pub async fn fetch_git_plugin( GitVersion::Mixed(tag, commit) => { log::debug!("Fetching git plugin: {}@{}/{}", name, tag, commit); let shallow_flag = shallow.unwrap_or(false); - let result = git_clone_and_checkout( - &baseurl, - &tag, - &basedir.join(name), - name, - shallow_flag, - ) - .await; + let result = + git_clone_and_checkout(&baseurl, &tag, &basedir.join(name), name, shallow_flag) + .await; if result.is_err() { - log::warn!("Failed to clone with tag, trying commit hash. URL: {}", path); - return git_clone_and_checkout( - &baseurl, - &commit, - &basedir.join(name), - name, - false, - ) - .await; + log::warn!( + "Failed to clone with tag, trying commit hash. URL: {}", + path + ); + return git_clone_and_checkout(&baseurl, &commit, &basedir.join(name), name, false) + .await; } result } diff --git a/workshop-baker/src/finalize/plugin/fetch/http.rs b/workshop-baker/src/finalize/plugin/fetch/http.rs index 781e2d9..55e90a0 100644 --- a/workshop-baker/src/finalize/plugin/fetch/http.rs +++ b/workshop-baker/src/finalize/plugin/fetch/http.rs @@ -1,14 +1,10 @@ // Code in this module PARTIALLY OR FULLY utilized AI Coding Agent. -use std::path::Path; -use crate::finalize::plugin::PluginError; use super::checksum::{detect_checksum_type, verify_checksum}; -use super::extract::{extract_tar, CompressionType}; +use super::extract::{CompressionType, extract_tar}; +use crate::finalize::plugin::PluginError; +use std::path::Path; -pub async fn download_to_file( - url: &str, - dest: &Path, - name: &str, -) -> Result<(), PluginError> { +pub async fn download_to_file(url: &str, dest: &Path, name: &str) -> Result<(), PluginError> { let client = reqwest::Client::builder() .timeout(std::time::Duration::from_secs(300)) .build() @@ -33,28 +29,42 @@ pub async fn download_to_file( }); } - let bytes = response.bytes().await.map_err(|e| PluginError::FetchError { - name: name.to_string(), - url: url.to_string(), - reason: format!("Failed to read response body: {}", e), - })?; + let bytes = response + .bytes() + .await + .map_err(|e| PluginError::FetchError { + name: name.to_string(), + url: url.to_string(), + reason: format!("Failed to read response body: {}", e), + })?; - tokio::fs::write(dest, &bytes).await.map_err(|e| PluginError::FetchError { - name: name.to_string(), - url: url.to_string(), - reason: format!("Failed to write file: {}", e), - })?; + tokio::fs::write(dest, &bytes) + .await + .map_err(|e| PluginError::FetchError { + name: name.to_string(), + url: url.to_string(), + reason: format!("Failed to write file: {}", e), + })?; Ok(()) } fn extract_archive_extension(url: &str) -> &str { - let path_part = url.split('?').next().unwrap_or(url).split('#').next().unwrap_or(url); + let path_part = url + .split('?') + .next() + .unwrap_or(url) + .split('#') + .next() + .unwrap_or(url); let file_part = path_part.rsplit('/').next().unwrap_or(""); let lower = file_part.to_lowercase(); if lower.ends_with(".tar.gz") || lower.ends_with(".tgz") { ".tar.gz" - } else if lower.ends_with(".tar.zst") || lower.ends_with(".tar.zstd") || lower.ends_with(".tzst") { + } else if lower.ends_with(".tar.zst") + || lower.ends_with(".tar.zstd") + || lower.ends_with(".tzst") + { ".tar.zst" } else if lower.ends_with(".tar") { ".tar" @@ -82,19 +92,17 @@ pub async fn fetch_http_plugin( PluginError::GeneralError(format!("Failed to read downloaded file: {}", e)) })?; - let checksum_type = detect_checksum_type(checksum) - .map_err(|e| PluginError::GeneralError(e))?; + let checksum_type = + detect_checksum_type(checksum).map_err(|e| PluginError::GeneralError(e))?; if let Some(ct) = checksum_type { - verify_checksum(&bytes, checksum, ct).map_err(|e| { - PluginError::GeneralError(e) - })?; + verify_checksum(&bytes, checksum, ct).map_err(|e| PluginError::GeneralError(e))?; } } } - let compression = CompressionType::from_path(&temp_file) - .map_err(|e| PluginError::GeneralError(e))?; + let compression = + CompressionType::from_path(&temp_file).map_err(|e| PluginError::GeneralError(e))?; let destdir = basedir.join(name); extract_tar(&temp_file, &destdir, compression).await?; diff --git a/workshop-baker/src/finalize/plugin/internal.rs b/workshop-baker/src/finalize/plugin/internal.rs index 5df4680..189126e 100644 --- a/workshop-baker/src/finalize/plugin/internal.rs +++ b/workshop-baker/src/finalize/plugin/internal.rs @@ -1,9 +1,9 @@ use crate::finalize::plugin::AsyncPluginFn; +pub mod dummy; mod insitenotify; mod mail; mod satori; mod webhook; -pub mod dummy; pub struct InternalPlugin { pub name: &'static str, pub entry: Box, diff --git a/workshop-baker/src/finalize/plugin/internal/insitenotify.rs b/workshop-baker/src/finalize/plugin/internal/insitenotify.rs index db64ba6..2db7222 100644 --- a/workshop-baker/src/finalize/plugin/internal/insitenotify.rs +++ b/workshop-baker/src/finalize/plugin/internal/insitenotify.rs @@ -1,5 +1,8 @@ use crate::finalize::plugin::PluginMetadata; -use crate::{EventSender, ExecutionContext, finalize::{error::PluginError, plugin::AsyncPluginFn}}; +use crate::{ + EventSender, ExecutionContext, + finalize::{error::PluginError, plugin::AsyncPluginFn}, +}; use async_trait::async_trait; pub struct InsiteNotify; diff --git a/workshop-baker/src/finalize/plugin/internal/mail.rs b/workshop-baker/src/finalize/plugin/internal/mail.rs index 11633a1..8ee2971 100644 --- a/workshop-baker/src/finalize/plugin/internal/mail.rs +++ b/workshop-baker/src/finalize/plugin/internal/mail.rs @@ -1,11 +1,11 @@ // Code in this module PARTIALLY OR FULLY utilized AI Coding Agent. -use crate::finalize::plugin::PluginMetadata; use crate::finalize::plugin::PluginError; +use crate::finalize::plugin::PluginMetadata; use crate::{EventSender, ExecutionContext, finalize::plugin::AsyncPluginFn}; use async_trait::async_trait; -use std::time::Duration; +use lettre::message::{MultiPart, SinglePart, header}; use lettre::{AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor}; -use lettre::message::{header, MultiPart, SinglePart}; +use std::time::Duration; use tokio::time::timeout; mod config; @@ -29,20 +29,29 @@ impl AsyncPluginFn for Mail { .map_err(|e| PluginError::GeneralError(format!("Invalid mail config: {}", e)))?; if let Err(errors) = config.validate() { - return Err(PluginError::GeneralError( - format!("Mail config validation failed: {:?}", errors) - )); + return Err(PluginError::GeneralError(format!( + "Mail config validation failed: {:?}", + errors + ))); } let template_data = prepare_template_data(ctx); let (subject_template, body_template_html, body_template_text) = match config.schema { Schema::Default => { - let subject = config.subject.as_deref() + let subject = config + .subject + .as_deref() .unwrap_or(DefaultTemplates::SUBJECT); - let body_html = config.body.as_deref() + let body_html = config + .body + .as_deref() .unwrap_or(DefaultTemplates::BODY_HTML); - (subject.to_string(), body_html.to_string(), DefaultTemplates::BODY_TEXT.to_string()) + ( + subject.to_string(), + body_html.to_string(), + DefaultTemplates::BODY_TEXT.to_string(), + ) } Schema::Custom => { let subject = config.subject.clone().unwrap(); @@ -55,8 +64,9 @@ impl AsyncPluginFn for Mail { .map_err(|e| PluginError::GeneralError(format!("Failed to render subject: {}", e)))?; let body_html = render_template(&body_template_html, &template_data) .map_err(|e| PluginError::GeneralError(format!("Failed to render body_html: {}", e)))?; - let body_text = render_template(&body_template_text, &template_data) - .map_err(|e| PluginError::GeneralError(format!("Failed to render body_text(?): {}", e)))?; + let body_text = render_template(&body_template_text, &template_data).map_err(|e| { + PluginError::GeneralError(format!("Failed to render body_text(?): {}", e)) + })?; let email = build_email(&config, subject, body_html, body_text)?; @@ -71,43 +81,48 @@ fn build_email( body_text: String, ) -> Result { let from_str = config.from.to_string(); - let from: lettre::message::Mailbox = from_str.parse() - .map_err(|e| PluginError::GeneralError(format!("Invalid from address '{}': {}", from_str, e)))?; + let from: lettre::message::Mailbox = from_str.parse().map_err(|e| { + PluginError::GeneralError(format!("Invalid from address '{}': {}", from_str, e)) + })?; let to_addrs: Vec = config.to.to_vec(); if to_addrs.is_empty() { - return Err(PluginError::GeneralError("No recipients specified".to_string())); + return Err(PluginError::GeneralError( + "No recipients specified".to_string(), + )); } - let mut message_builder = Message::builder() - .from(from) - .subject(subject); + let mut message_builder = Message::builder().from(from).subject(subject); for addr in &to_addrs { - let mailbox: lettre::message::Mailbox = addr.parse() - .map_err(|e| PluginError::GeneralError(format!("Invalid to address '{}': {}", addr, e)))?; + let mailbox: lettre::message::Mailbox = addr.parse().map_err(|e| { + PluginError::GeneralError(format!("Invalid to address '{}': {}", addr, e)) + })?; message_builder = message_builder.to(mailbox); } if let Some(cc) = &config.cc { for addr in cc.to_vec() { - let mailbox: lettre::message::Mailbox = addr.parse() - .map_err(|e| PluginError::GeneralError(format!("Invalid cc address '{}': {}", addr, e)))?; + let mailbox: lettre::message::Mailbox = addr.parse().map_err(|e| { + PluginError::GeneralError(format!("Invalid cc address '{}': {}", addr, e)) + })?; message_builder = message_builder.cc(mailbox); } } if let Some(bcc) = &config.bcc { for addr in bcc.to_vec() { - let mailbox: lettre::message::Mailbox = addr.parse() - .map_err(|e| PluginError::GeneralError(format!("Invalid bcc address '{}': {}", addr, e)))?; + let mailbox: lettre::message::Mailbox = addr.parse().map_err(|e| { + PluginError::GeneralError(format!("Invalid bcc address '{}': {}", addr, e)) + })?; message_builder = message_builder.bcc(mailbox); } } if let Some(reply_to) = &config.reply_to { - let mailbox: lettre::message::Mailbox = reply_to.parse() - .map_err(|e| PluginError::GeneralError(format!("Invalid reply-to address '{}': {}", reply_to, e)))?; + let mailbox: lettre::message::Mailbox = reply_to.parse().map_err(|e| { + PluginError::GeneralError(format!("Invalid reply-to address '{}': {}", reply_to, e)) + })?; message_builder = message_builder.reply_to(mailbox); } @@ -117,23 +132,20 @@ fn build_email( .singlepart( SinglePart::builder() .header(header::ContentType::TEXT_PLAIN) - .body(body_text) + .body(body_text), ) .singlepart( SinglePart::builder() .header(header::ContentType::TEXT_HTML) - .body(body_html) - ) + .body(body_html), + ), ) .map_err(|e| PluginError::GeneralError(format!("Failed to build email: {}", e)))?; Ok(message) } -async fn send_email( - config: &MailConfig, - email: Message, -) -> Result<(), PluginError> { +async fn send_email(config: &MailConfig, email: Message) -> Result<(), PluginError> { let connect_timeout = if config.smtp.connect_timeout_ms == 0 { None } else { @@ -162,10 +174,13 @@ async fn send_email( match config.smtp.auth.auth_type { AuthType::Password => { log::debug!("Using password auth"); - transport_builder = transport_builder.credentials(( - config.smtp.auth.username.clone(), - config.smtp.auth.password.clone() - ).into()); + transport_builder = transport_builder.credentials( + ( + config.smtp.auth.username.clone(), + config.smtp.auth.password.clone(), + ) + .into(), + ); } AuthType::None => { log::debug!("Using no auth"); diff --git a/workshop-baker/src/finalize/plugin/internal/satori.rs b/workshop-baker/src/finalize/plugin/internal/satori.rs index d20ce6e..3474a84 100644 --- a/workshop-baker/src/finalize/plugin/internal/satori.rs +++ b/workshop-baker/src/finalize/plugin/internal/satori.rs @@ -1,5 +1,5 @@ -use crate::finalize::plugin::PluginMetadata; use crate::finalize::plugin::PluginError; +use crate::finalize::plugin::PluginMetadata; use crate::{EventSender, ExecutionContext, finalize::plugin::AsyncPluginFn}; use async_trait::async_trait; diff --git a/workshop-baker/src/finalize/plugin/internal/webhook.rs b/workshop-baker/src/finalize/plugin/internal/webhook.rs index 77ec508..fdb2945 100644 --- a/workshop-baker/src/finalize/plugin/internal/webhook.rs +++ b/workshop-baker/src/finalize/plugin/internal/webhook.rs @@ -1,5 +1,5 @@ -use crate::finalize::plugin::PluginMetadata; use crate::finalize::plugin::PluginError; +use crate::finalize::plugin::PluginMetadata; use crate::{EventSender, ExecutionContext, finalize::plugin::AsyncPluginFn}; use async_trait::async_trait; diff --git a/workshop-baker/src/finalize/plugin/rhai.rs b/workshop-baker/src/finalize/plugin/rhai.rs index 0333ace..164461c 100644 --- a/workshop-baker/src/finalize/plugin/rhai.rs +++ b/workshop-baker/src/finalize/plugin/rhai.rs @@ -1,5 +1,5 @@ -use crate::finalize::plugin::PluginMetadata; use crate::finalize::plugin::PluginError; +use crate::finalize::plugin::PluginMetadata; use crate::{EventSender, ExecutionContext, finalize::plugin::AsyncPluginFn}; use async_trait::async_trait; diff --git a/workshop-baker/src/finalize/plugin/shell.rs b/workshop-baker/src/finalize/plugin/shell.rs index 3c973ba..0926969 100644 --- a/workshop-baker/src/finalize/plugin/shell.rs +++ b/workshop-baker/src/finalize/plugin/shell.rs @@ -1,5 +1,5 @@ -use crate::constant::FINALIZE_SHELL_ENVPREFIX; use crate::Engine; +use crate::constant::FINALIZE_SHELL_ENVPREFIX; use crate::finalize::plugin::PluginError; use crate::finalize::plugin::PluginMetadata; use crate::{EventSender, ExecutionContext, finalize::plugin::AsyncPluginFn}; @@ -8,7 +8,6 @@ use std::collections::HashMap; pub struct Shell; - /// Parses a YAML value used as a mapping key into a string. /// /// Since YAML keys can be strings, numbers, or booleans, this function @@ -72,7 +71,11 @@ fn parse_key(key: serde_yaml::Value) -> String { /// let result = convert_argument("PLUGIN", yaml, false); /// // Yields: {"PLUGIN_HOST" => "\"docker.io\"", "PLUGIN_USER" => "\"admin\""} /// ``` -fn convert_argument(prefix: &str, argument: serde_yaml::Value, in_sequence: bool) -> HashMap { +fn convert_argument( + prefix: &str, + argument: serde_yaml::Value, + in_sequence: bool, +) -> HashMap { let mut envvars: HashMap = HashMap::new(); match argument { serde_yaml::Value::Mapping(mapping) => { @@ -95,14 +98,17 @@ fn convert_argument(prefix: &str, argument: serde_yaml::Value, in_sequence: bool } serde_yaml::Value::Number(value) => { envvars.insert(prefix.to_string(), value.to_string()); - }, + } serde_yaml::Value::Tagged(tagged_value) => { let subenvvars = convert_argument(prefix, tagged_value.value, in_sequence); envvars.extend(subenvvars); } serde_yaml::Value::Sequence(seq) => { if in_sequence { - log::warn!("Nested sequence in sequence is not supported, skipping: {}", prefix); + log::warn!( + "Nested sequence in sequence is not supported, skipping: {}", + prefix + ); return envvars; } let mut array = String::new(); @@ -117,16 +123,19 @@ fn convert_argument(prefix: &str, argument: serde_yaml::Value, in_sequence: bool let subenvvars = convert_argument(new_prefix.as_str(), item.clone(), true); if item.is_mapping() { has_mapping = true; - } - else { - array.push_str(subenvvars.get(new_prefix.as_str()).map(|v| v.as_str()).unwrap_or_default()); + } else { + array.push_str( + subenvvars + .get(new_prefix.as_str()) + .map(|v| v.as_str()) + .unwrap_or_default(), + ); } _envvars.extend(subenvvars); } if has_mapping { envvars.extend(_envvars); - } - else { + } else { array.push_str(")"); envvars.insert(prefix.to_string(), array); } @@ -148,7 +157,13 @@ impl AsyncPluginFn for Shell { let envvars = convert_argument(FINALIZE_SHELL_ENVPREFIX, argument, false); let mut local_ctx = ctx.clone(); local_ctx.env_vars.extend(envvars); - engine.execute_script(&metadata.fspath.join(&metadata.entrypoint), &local_ctx, event_tx).await?; + engine + .execute_script( + &metadata.fspath.join(&metadata.entrypoint), + &local_ctx, + event_tx, + ) + .await?; Ok(()) } } @@ -205,27 +220,36 @@ mod tests { #[test] fn test_convert_argument_nested_mapping() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " from: host: smtp.example.com port: 587 -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("CFG", yaml, false); // Nested keys use uppercase format: CFG_FROM_HOST - assert_eq!(result.get("CFG_FROM_HOST"), Some(&"smtp.example.com".to_string())); + assert_eq!( + result.get("CFG_FROM_HOST"), + Some(&"smtp.example.com".to_string()) + ); assert_eq!(result.get("CFG_FROM_PORT"), Some(&"587".to_string())); } #[test] fn test_convert_argument_different_types() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " enabled: true count: 42 ratio: 3.14 name: test empty: ~ -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("VAR", yaml, false); assert_eq!(result.get("VAR_ENABLED"), Some(&"true".to_string())); @@ -240,18 +264,24 @@ empty: ~ let yaml = serde_yaml::from_str("tags:\n - latest\n - v1.0\n - stable").unwrap(); let result = convert_argument("CFG", yaml, false); - assert_eq!(result.get("CFG_TAGS"), Some(&"(latest v1.0 stable)".to_string())); + assert_eq!( + result.get("CFG_TAGS"), + Some(&"(latest v1.0 stable)".to_string()) + ); } #[test] fn test_convert_argument_sequence_with_mapping() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " env: - name: KEY1 value: val1 - name: KEY2 value: val2 -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("CFG", yaml, false); assert_eq!(result.get("CFG_ENV_0_NAME"), Some(&"KEY1".to_string())); @@ -263,13 +293,16 @@ env: #[test] fn test_convert_argument_nested_sequence() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " matrix: - - a - b - - c - d -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("CFG", yaml, false); // Nested sequences are not supported (line 50-52 logs warning and skips) @@ -297,10 +330,13 @@ matrix: #[test] fn test_convert_argument_null_value() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " host: docker.io token: ~ -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("CFG", yaml, false); // Keys are uppercased: CFG_HOST @@ -311,10 +347,13 @@ token: ~ #[test] fn test_convert_argument_number_keys() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " 0: first 1: second -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("CFG", yaml, false); // Number keys are preserved but prefixed: CFG_0, CFG_1 @@ -324,7 +363,8 @@ token: ~ #[test] fn test_convert_argument_complex_nested() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " plugin: docker-push: host: docker.io @@ -335,38 +375,67 @@ plugin: tags: - latest - v1.0 -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("CFG", yaml, false); // All keys uppercased for shell environment variables - assert_eq!(result.get("CFG_PLUGIN_DOCKER-PUSH_HOST"), Some(&"docker.io".to_string())); - assert_eq!(result.get("CFG_PLUGIN_DOCKER-PUSH_IMAGE"), Some(&"user/app:tag".to_string())); - assert_eq!(result.get("CFG_PLUGIN_DOCKER-PUSH_OPTIONS_FORCE"), Some(&"true".to_string())); - assert_eq!(result.get("CFG_PLUGIN_DOCKER-PUSH_OPTIONS_RETRIES"), Some(&"3".to_string())); - assert_eq!(result.get("CFG_PLUGIN_DOCKER-PUSH_TAGS"), Some(&"(latest v1.0)".to_string())); + assert_eq!( + result.get("CFG_PLUGIN_DOCKER-PUSH_HOST"), + Some(&"docker.io".to_string()) + ); + assert_eq!( + result.get("CFG_PLUGIN_DOCKER-PUSH_IMAGE"), + Some(&"user/app:tag".to_string()) + ); + assert_eq!( + result.get("CFG_PLUGIN_DOCKER-PUSH_OPTIONS_FORCE"), + Some(&"true".to_string()) + ); + assert_eq!( + result.get("CFG_PLUGIN_DOCKER-PUSH_OPTIONS_RETRIES"), + Some(&"3".to_string()) + ); + assert_eq!( + result.get("CFG_PLUGIN_DOCKER-PUSH_TAGS"), + Some(&"(latest v1.0)".to_string()) + ); } #[test] fn test_convert_argument_special_chars_in_values() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " url: https://example.com/path?query=value path: /workspace/output.tar.gz token: 'Bearer abc123' -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("CFG", yaml, false); // Keys uppercased: CFG_URL, CFG_PATH, CFG_TOKEN - assert_eq!(result.get("CFG_URL"), Some(&"https://example.com/path?query=value".to_string())); - assert_eq!(result.get("CFG_PATH"), Some(&"/workspace/output.tar.gz".to_string())); + assert_eq!( + result.get("CFG_URL"), + Some(&"https://example.com/path?query=value".to_string()) + ); + assert_eq!( + result.get("CFG_PATH"), + Some(&"/workspace/output.tar.gz".to_string()) + ); assert_eq!(result.get("CFG_TOKEN"), Some(&"Bearer abc123".to_string())); } #[test] fn test_convert_argument_quoted_strings_preserved() { - let yaml = serde_yaml::from_str(" + let yaml = serde_yaml::from_str( + " msg: 'Hello World' cmd: \"echo 'test'\" -").unwrap(); +", + ) + .unwrap(); let result = convert_argument("CFG", yaml, false); // Keys uppercased: CFG_MSG, CFG_CMD diff --git a/workshop-baker/src/finalize/stage/hook.rs b/workshop-baker/src/finalize/stage/hook.rs index 53a032b..f17d2f9 100644 --- a/workshop-baker/src/finalize/stage/hook.rs +++ b/workshop-baker/src/finalize/stage/hook.rs @@ -45,7 +45,9 @@ pub async fn hook( hook_cmd.argument.clone(), &plugin_ctx, &event_tx, - ).await.map_err(|e| { + ) + .await + .map_err(|e| { log::error!("Plugin hook {} failed: {:?}", index, e); ExecutionError::ExecutionFailed(e.to_string()) })?; diff --git a/workshop-baker/src/lib.rs b/workshop-baker/src/lib.rs index 41e1583..a0b6176 100644 --- a/workshop-baker/src/lib.rs +++ b/workshop-baker/src/lib.rs @@ -1,17 +1,17 @@ // Library crate for workshop-executor // Selective exports: only modules used by external callers or tests +pub mod bake; +pub mod constant; pub mod daemon; pub mod engine; pub mod error; pub mod finalize; pub mod monitor; +pub mod notify; pub mod prebake; -pub mod bake; pub mod socket; pub mod types; -pub mod constant; -pub mod notify; // External crates re-exports pub use config; diff --git a/workshop-baker/src/main.rs b/workshop-baker/src/main.rs index 2d8843d..b533398 100644 --- a/workshop-baker/src/main.rs +++ b/workshop-baker/src/main.rs @@ -1,14 +1,13 @@ use std::path::Path; -use env_logger; use workshop_baker::{ + bake::bake, cli::{Cli, Commands, Parser}, daemon, engine::{EventSender, ExecutionContext}, error::PrebakeError, - prebake::prebake, - bake::bake, finalize::finalize, + prebake::prebake, }; #[tokio::main] @@ -22,7 +21,7 @@ async fn main() { Some(Commands::Monitor { group: _ }) => { unimplemented!("executor-monitor should be moved to daemon instead.") } - Some(Commands::Client { config:_ }) => { + Some(Commands::Client { config: _ }) => { unimplemented!("Client mode not yet implemented.") } Some(Commands::Prebake { config }) => { @@ -40,9 +39,11 @@ async fn main() { let event_tx: EventSender = Some(tx); let pipeline_name = cli.pipeline.clone(); let build_id = cli.build_id.clone(); - let receiver_handle = tokio::spawn( - workshop_baker::prebake::event::event_receiver(event_rx, pipeline_name, build_id) - ); + let receiver_handle = tokio::spawn(workshop_baker::prebake::event::event_receiver( + event_rx, + pipeline_name, + build_id, + )); let result = prebake(config, &cli, None, &mut ctx, event_tx).await; drop(ctx); let _ = receiver_handle.await; @@ -52,12 +53,14 @@ async fn main() { std::process::exit( e.downcast_ref::() .map(|pe| pe.exit_code()) - .unwrap_or(1) + .unwrap_or(1), ); } } Some(Commands::Bake { - script, bake_base, prebake + script, + bake_base, + prebake, }) => { log::info!("Running in standalone mode."); let mut ctx = ExecutionContext { @@ -73,9 +76,11 @@ async fn main() { let event_tx: EventSender = Some(tx); let pipeline_name = cli.pipeline.clone(); let build_id = cli.build_id.clone(); - let receiver_handle = tokio::spawn( - workshop_baker::prebake::event::event_receiver(event_rx, pipeline_name, build_id) - ); + let receiver_handle = tokio::spawn(workshop_baker::prebake::event::event_receiver( + event_rx, + pipeline_name, + build_id, + )); let result = bake(script, bake_base, prebake, &cli, &mut ctx, event_tx).await; drop(ctx); let _ = receiver_handle.await; @@ -100,9 +105,11 @@ async fn main() { let event_tx: EventSender = Some(tx); let pipeline_name = cli.pipeline.clone(); let build_id = cli.build_id.clone(); - let receiver_handle = tokio::spawn( - workshop_baker::prebake::event::event_receiver(event_rx, pipeline_name, build_id) - ); + let receiver_handle = tokio::spawn(workshop_baker::prebake::event::event_receiver( + event_rx, + pipeline_name, + build_id, + )); let result = finalize(Path::new(config), &cli, &mut ctx, event_tx).await; drop(ctx); let _ = receiver_handle.await; diff --git a/workshop-baker/src/notify.rs b/workshop-baker/src/notify.rs index fd7a07b..d559a13 100644 --- a/workshop-baker/src/notify.rs +++ b/workshop-baker/src/notify.rs @@ -190,13 +190,20 @@ fn wait_time(group_period: u32, group_watermark: u32, count: u32) -> f32 { fn notify_delay(event: &NotifyEvent) -> std::time::Duration { let exponent = (event.max_lives - event.lives) as i32; if exponent < 0 { - log::warn!("Unexpected lives in notification: lives({}) > max_lives({})", event.lives, event.max_lives); + log::warn!( + "Unexpected lives in notification: lives({}) > max_lives({})", + event.lives, + event.max_lives + ); return std::time::Duration::from_secs_f64(NOTIFY_TEMPORARY_MAX_TIME); } let multiplier = NOTIFY_TEMPORARY_DELAY_FACTOR.powi(exponent); let delay = multiplier * NOTIFY_TEMPORARY_DELAY_TIME; if !delay.is_finite() || delay < 0.0 { - log::warn!("Unexpected calculated delay: {}, treating as infinite", delay); + log::warn!( + "Unexpected calculated delay: {}, treating as infinite", + delay + ); return std::time::Duration::from_secs_f64(NOTIFY_TEMPORARY_MAX_TIME); } std::time::Duration::from_secs_f64(delay) diff --git a/workshop-baker/src/notify/error.rs b/workshop-baker/src/notify/error.rs index f45b41c..02dc745 100644 --- a/workshop-baker/src/notify/error.rs +++ b/workshop-baker/src/notify/error.rs @@ -1,7 +1,7 @@ use thiserror::Error; #[derive(Error, Debug)] -pub enum NotifyError{ +pub enum NotifyError { #[error("Finalize config validation failed: {0:?}")] FinalizeValidationError(Vec), diff --git a/workshop-baker/src/prebake.rs b/workshop-baker/src/prebake.rs index f1aa651..5686ebd 100644 --- a/workshop-baker/src/prebake.rs +++ b/workshop-baker/src/prebake.rs @@ -27,16 +27,16 @@ pub mod security; pub mod stage; use crate::{ + ExecutionContext, cli::Cli, + constant::STANDALONE_STATUS_DIR, engine::EventSender, error::PrebakeError, - ExecutionContext, prebake::{security::get_drop_after, stage::PrebakeStage}, - types::buildstatus::{write_stage_status, StageInfo, StagePhase, StageResult}, - constant::STANDALONE_STATUS_DIR, + types::buildstatus::{StageInfo, StagePhase, StageResult, write_stage_status}, }; -use std::path::Path; use chrono::Utc; +use std::path::Path; pub use config::PrebakeConfig; pub use security::prebake_drop_privilege; @@ -92,7 +92,7 @@ pub async fn prebake( prebake_path: &Path, cli: &Cli, stage: Option, -mut ctx: &mut ExecutionContext, + mut ctx: &mut ExecutionContext, event_tx: EventSender, ) -> anyhow::Result<()> { // Initialize @@ -131,7 +131,11 @@ mut ctx: &mut ExecutionContext, ctx.task_id = format!("{}-{}-bootstrap", cli.pipeline, cli.build_id); let osinfo = os_info::get(); let result = stage::bootstrap::bootstrap(&prebake, &osinfo, &ctx, &event_tx).await; - let stage_result = if result.is_ok() { StageResult::Success } else { StageResult::Failure }; + let stage_result = if result.is_ok() { + StageResult::Success + } else { + StageResult::Failure + }; let _ = write_stage_status( STANDALONE_STATUS_DIR, StageInfo { @@ -139,7 +143,9 @@ mut ctx: &mut ExecutionContext, phase: StagePhase::Prebake, substage: "bootstrap".to_string(), result: stage_result, - duration_ms: Utc::now().signed_duration_since(stage_start).num_milliseconds() as u64, + duration_ms: Utc::now() + .signed_duration_since(stage_start) + .num_milliseconds() as u64, started_at: stage_start, finished_at: Utc::now(), error_message: result.as_ref().err().map(|e| e.to_string()), @@ -159,7 +165,11 @@ mut ctx: &mut ExecutionContext, None => None, }; let result = stage::hook::hook(earlyhook, &ctx, event_tx.clone()).await; - let stage_result = if result.is_ok() { StageResult::Success } else { StageResult::Failure }; + let stage_result = if result.is_ok() { + StageResult::Success + } else { + StageResult::Failure + }; let _ = write_stage_status( STANDALONE_STATUS_DIR, StageInfo { @@ -167,7 +177,9 @@ mut ctx: &mut ExecutionContext, phase: StagePhase::Prebake, substage: "earlyhook".to_string(), result: stage_result, - duration_ms: Utc::now().signed_duration_since(stage_start).num_milliseconds() as u64, + duration_ms: Utc::now() + .signed_duration_since(stage_start) + .num_milliseconds() as u64, started_at: stage_start, finished_at: Utc::now(), error_message: result.as_ref().err().map(|e| e.to_string()), @@ -240,8 +252,13 @@ mut ctx: &mut ExecutionContext, log::info!("Running PBStage: DepsSystem"); prebake_drop_privilege(PrebakeStage::DepsSystem, dropafter, target_user, &mut ctx)?; ctx.task_id = format!("{}-{}-depssystem", cli.pipeline, cli.build_id); - let result = stage::depssystem::depssystem(&system_config, &ctx, event_tx.clone()).await; - let stage_result = if result.is_ok() { StageResult::Success } else { StageResult::Failure }; + let result = + stage::depssystem::depssystem(&system_config, &ctx, event_tx.clone()).await; + let stage_result = if result.is_ok() { + StageResult::Success + } else { + StageResult::Failure + }; let _ = write_stage_status( STANDALONE_STATUS_DIR, StageInfo { @@ -249,7 +266,9 @@ mut ctx: &mut ExecutionContext, phase: StagePhase::Prebake, substage: "depssystem".to_string(), result: stage_result, - duration_ms: Utc::now().signed_duration_since(stage_start).num_milliseconds() as u64, + duration_ms: Utc::now() + .signed_duration_since(stage_start) + .num_milliseconds() as u64, started_at: stage_start, finished_at: Utc::now(), error_message: result.as_ref().err().map(|e| e.to_string()), @@ -266,7 +285,11 @@ mut ctx: &mut ExecutionContext, prebake_drop_privilege(PrebakeStage::DepsUser, dropafter, target_user, &mut ctx)?; ctx.task_id = format!("{}-{}-depsuser", cli.pipeline, cli.build_id); let result = stage::depsuser::depsuser(&user, &ctx, event_tx.clone(), &endpoint).await; - let stage_result = if result.is_ok() { StageResult::Success } else { StageResult::Failure }; + let stage_result = if result.is_ok() { + StageResult::Success + } else { + StageResult::Failure + }; let _ = write_stage_status( STANDALONE_STATUS_DIR, StageInfo { @@ -274,7 +297,9 @@ mut ctx: &mut ExecutionContext, phase: StagePhase::Prebake, substage: "depsuser".to_string(), result: stage_result, - duration_ms: Utc::now().signed_duration_since(stage_start).num_milliseconds() as u64, + duration_ms: Utc::now() + .signed_duration_since(stage_start) + .num_milliseconds() as u64, started_at: stage_start, finished_at: Utc::now(), error_message: result.as_ref().err().map(|e| e.to_string()), @@ -295,7 +320,11 @@ mut ctx: &mut ExecutionContext, None => None, }; let result = stage::hook::hook(latehook, &ctx, event_tx.clone()).await; - let stage_result = if result.is_ok() { StageResult::Success } else { StageResult::Failure }; + let stage_result = if result.is_ok() { + StageResult::Success + } else { + StageResult::Failure + }; let _ = write_stage_status( STANDALONE_STATUS_DIR, StageInfo { @@ -303,7 +332,9 @@ mut ctx: &mut ExecutionContext, phase: StagePhase::Prebake, substage: "latehook".to_string(), result: stage_result, - duration_ms: Utc::now().signed_duration_since(stage_start).num_milliseconds() as u64, + duration_ms: Utc::now() + .signed_duration_since(stage_start) + .num_milliseconds() as u64, started_at: stage_start, finished_at: Utc::now(), error_message: result.as_ref().err().map(|e| e.to_string()), diff --git a/workshop-baker/src/prebake/event.rs b/workshop-baker/src/prebake/event.rs index 384bf69..3115e01 100644 --- a/workshop-baker/src/prebake/event.rs +++ b/workshop-baker/src/prebake/event.rs @@ -10,25 +10,39 @@ pub async fn event_receiver( ExecutionEvent::TaskStarted { task_id, timestamp } => { log::debug!( "[{}] [{}] [{}] Task started: {}", - pipeline_name, build_id, timestamp, task_id + pipeline_name, + build_id, + timestamp, + task_id ); } - ExecutionEvent::OutputChunk { task_id, stream, data } => { - match stream { - StreamType::Stdout => print!("[{}] [{}] [stdout] {}", pipeline_name, task_id, data), - StreamType::Stderr => eprint!("[{}] [{}] [stderr] {}", pipeline_name, task_id, data), + ExecutionEvent::OutputChunk { + task_id, + stream, + data, + } => match stream { + StreamType::Stdout => print!("[{}] [{}] [stdout] {}", pipeline_name, task_id, data), + StreamType::Stderr => { + eprint!("[{}] [{}] [stderr] {}", pipeline_name, task_id, data) } - } + }, ExecutionEvent::TaskCompleted { task_id, result } => { log::debug!( "[{}] [{}] Task completed: {} (exit_code={}, duration={:?})", - pipeline_name, build_id, task_id, result.exit_code, result.duration + pipeline_name, + build_id, + task_id, + result.exit_code, + result.duration ); } ExecutionEvent::TaskFailed { task_id, error } => { log::error!( "[{}] [{}] Task failed: {} (error={})", - pipeline_name, build_id, task_id, error + pipeline_name, + build_id, + task_id, + error ); } } diff --git a/workshop-baker/src/prebake/stage.rs b/workshop-baker/src/prebake/stage.rs index b01cbf9..dbbdbc7 100644 --- a/workshop-baker/src/prebake/stage.rs +++ b/workshop-baker/src/prebake/stage.rs @@ -1,10 +1,10 @@ use std::str::FromStr; pub mod bootstrap; -pub mod environment; -pub mod hook; pub mod depssystem; pub mod depsuser; +pub mod environment; +pub mod hook; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] pub enum PrebakeStage { diff --git a/workshop-baker/src/prebake/stage/bootstrap.rs b/workshop-baker/src/prebake/stage/bootstrap.rs index a71c08f..41a7a92 100644 --- a/workshop-baker/src/prebake/stage/bootstrap.rs +++ b/workshop-baker/src/prebake/stage/bootstrap.rs @@ -62,7 +62,10 @@ pub async fn bootstrap( log::debug!("Generated bootstrap script:\n{}", script); let mut file = File::create(&bootstrap_path)?; file.write_all(script.as_bytes())?; - std::fs::set_permissions(&bootstrap_path, std::os::unix::fs::PermissionsExt::from_mode(0o755))?; + std::fs::set_permissions( + &bootstrap_path, + std::os::unix::fs::PermissionsExt::from_mode(0o755), + )?; } else { // Requires PIP(Pipeline Implicit Parameters) to be implemented unimplemented!("Not supporting custom bootstrap.sh at this time"); diff --git a/workshop-baker/src/prebake/stage/depssystem.rs b/workshop-baker/src/prebake/stage/depssystem.rs index 88ab93f..dd3db5d 100644 --- a/workshop-baker/src/prebake/stage/depssystem.rs +++ b/workshop-baker/src/prebake/stage/depssystem.rs @@ -41,13 +41,12 @@ pub async fn depssystem( log::info!("Changing mirror to: {}", mirror); let cmds = package_manager.change_mirror(mirror, Some(&osinfo)); for cmd in cmds { - log::debug!("Executing: {:?}", &cmd); - engine - .execute(cmd, ctx, &event_tx) - .await - .map_err(|e| DependencyError::StageFailed { - stage: "MirrorChange", - source: e, + log::debug!("Executing: {:?}", &cmd); + engine.execute(cmd, ctx, &event_tx).await.map_err(|e| { + DependencyError::StageFailed { + stage: "MirrorChange", + source: e, + } })?; } } diff --git a/workshop-baker/src/prebake/stage/depsuser.rs b/workshop-baker/src/prebake/stage/depsuser.rs index 1318232..5a9ef3b 100644 --- a/workshop-baker/src/prebake/stage/depsuser.rs +++ b/workshop-baker/src/prebake/stage/depsuser.rs @@ -32,7 +32,10 @@ pub async fn collect_upm_sysdeps( let package_manager = match upm::select(name) { Some(pm) => pm, None => { - log::warn!("Unknown user package manager: {}, skipping sysdep collection", name); + log::warn!( + "Unknown user package manager: {}, skipping sysdep collection", + name + ); continue; } }; diff --git a/workshop-baker/src/prebake/stage/environment.rs b/workshop-baker/src/prebake/stage/environment.rs index 5a97422..05c0e36 100644 --- a/workshop-baker/src/prebake/stage/environment.rs +++ b/workshop-baker/src/prebake/stage/environment.rs @@ -1,4 +1,4 @@ -use crate::prebake::config::{PrebakeConfig}; +use crate::prebake::config::PrebakeConfig; use crate::types::builderconfig::BuilderType; use config::Config; diff --git a/workshop-baker/src/prebake/stage/hook.rs b/workshop-baker/src/prebake/stage/hook.rs index a7957c6..33e1e7d 100644 --- a/workshop-baker/src/prebake/stage/hook.rs +++ b/workshop-baker/src/prebake/stage/hook.rs @@ -12,8 +12,8 @@ //! Each hook command supports custom working directories, environment variables, //! and timeout configurations. -use crate::engine::types::DeltaExecutionContext; use crate::ExecutionContext; +use crate::engine::types::DeltaExecutionContext; use crate::engine::{Engine, EventSender, ExecutionError}; use crate::types::command::CustomCommand; use std::path::PathBuf; diff --git a/workshop-baker/src/types.rs b/workshop-baker/src/types.rs index a523cd5..a963889 100644 --- a/workshop-baker/src/types.rs +++ b/workshop-baker/src/types.rs @@ -1,6 +1,6 @@ pub mod architecture; -pub mod buildstatus; pub mod builderconfig; +pub mod buildstatus; pub mod cache; pub mod command; pub mod memsize; diff --git a/workshop-baker/src/types/memsize.rs b/workshop-baker/src/types/memsize.rs index c7661b6..2f770f4 100644 --- a/workshop-baker/src/types/memsize.rs +++ b/workshop-baker/src/types/memsize.rs @@ -153,11 +153,11 @@ pub fn parse_mem_size(s: &str) -> Result { "k" | "K" => 1000, "m" | "M" => 1000 * 1000, "g" | "G" => 1000 * 1000 * 1000, - "t" | "T" => 1000 as u64 * 1000 * 1000 * 1000, + "t" | "T" => 1000_u64 * 1000 * 1000 * 1000, "ki" | "kI" | "Ki" | "KI" => 1024, "mi" | "mI" | "Mi" | "MI" => 1024 * 1024, "gi" | "gI" | "Gi" | "GI" => 1024 * 1024 * 1024, - "ti" | "tI" | "Ti" | "TI" => 1024 as u64 * 1024 * 1024 * 1024, + "ti" | "tI" | "Ti" | "TI" => 1024_u64 * 1024 * 1024 * 1024, _ => return Err(format!("unknown unit: {}", unit_raw)), }; diff --git a/workshop-baker/src/types/time.rs b/workshop-baker/src/types/time.rs index d110c04..4f32faf 100644 --- a/workshop-baker/src/types/time.rs +++ b/workshop-baker/src/types/time.rs @@ -1,4 +1,4 @@ -use serde::{de::Visitor, Deserializer}; +use serde::{Deserializer, de::Visitor}; pub const INT_MAX_MS: u64 = i32::MAX as u64; diff --git a/workshop-baker/tests/finalize_hook_integration.rs b/workshop-baker/tests/finalize_hook_integration.rs index fcd594f..7e0b25c 100644 --- a/workshop-baker/tests/finalize_hook_integration.rs +++ b/workshop-baker/tests/finalize_hook_integration.rs @@ -6,8 +6,8 @@ use std::collections::HashMap; use std::time::Duration; use workshop_baker::engine::{ExecutionContext, ExecutionEvent}; +use workshop_baker::finalize::plugin::PluginMap; use workshop_baker::finalize::stage::hook::hook; -use workshop_baker::finalize::plugin::{PluginMap}; use workshop_baker::types::command::CustomCommand; fn create_test_context() -> ExecutionContext { @@ -26,7 +26,10 @@ fn create_test_context() -> ExecutionContext { } } -fn create_test_event_channel() -> (Option>, tokio::sync::mpsc::Receiver) { +fn create_test_event_channel() -> ( + Option>, + tokio::sync::mpsc::Receiver, +) { let (tx, rx) = tokio::sync::mpsc::channel(64); (Some(tx), rx) } @@ -146,7 +149,10 @@ async fn test_multiple_hooks_execute_sequentially() { ]; let result = hook(Some(&cmds), &ctx, event_tx, &plugins).await; - assert!(result.is_ok(), "Multiple hooks should execute sequentially and succeed"); + assert!( + result.is_ok(), + "Multiple hooks should execute sequentially and succeed" + ); } #[tokio::test] diff --git a/workshop-baker/tests/finalize_pipeline_integration.rs b/workshop-baker/tests/finalize_pipeline_integration.rs index 5873533..db72e23 100644 --- a/workshop-baker/tests/finalize_pipeline_integration.rs +++ b/workshop-baker/tests/finalize_pipeline_integration.rs @@ -5,9 +5,9 @@ use std::collections::HashMap; use std::time::Duration; +use workshop_baker::cli::Cli; use workshop_baker::engine::{ExecutionContext, ExecutionEvent}; use workshop_baker::finalize::finalize; -use workshop_baker::cli::Cli; fn create_test_context() -> ExecutionContext { ExecutionContext { @@ -35,7 +35,10 @@ fn create_test_cli() -> Cli { } } -fn create_test_event_channel() -> (Option>, tokio::sync::mpsc::Receiver) { +fn create_test_event_channel() -> ( + Option>, + tokio::sync::mpsc::Receiver, +) { let (tx, rx) = tokio::sync::mpsc::channel(64); (Some(tx), rx) } @@ -76,7 +79,11 @@ hooks: let _ = consumer_handle.await; std::fs::remove_file(&finalize_path).ok(); - assert!(result.is_ok(), "Full finalize pipeline should succeed: {:?}", result); + assert!( + result.is_ok(), + "Full finalize pipeline should succeed: {:?}", + result + ); } #[tokio::test] @@ -94,16 +101,19 @@ version: "0.0.1" let mut ctx = create_test_context(); let (event_tx, mut event_rx) = create_test_event_channel(); - let consumer_handle = tokio::spawn(async move { - while let Some(_event) = event_rx.recv().await {} - }); + let consumer_handle = + tokio::spawn(async move { while let Some(_event) = event_rx.recv().await {} }); let result = finalize(&finalize_path, &cli, &mut ctx, event_tx).await; let _ = consumer_handle.await; std::fs::remove_file(&finalize_path).ok(); - assert!(result.is_ok(), "Finalize with empty hooks should succeed: {:?}", result); + assert!( + result.is_ok(), + "Finalize with empty hooks should succeed: {:?}", + result + ); } #[tokio::test] @@ -130,9 +140,8 @@ hooks: let mut ctx = create_test_context(); let (event_tx, mut event_rx) = create_test_event_channel(); - let consumer_handle = tokio::spawn(async move { - while let Some(_event) = event_rx.recv().await {} - }); + let consumer_handle = + tokio::spawn(async move { while let Some(_event) = event_rx.recv().await {} }); let result = finalize(&finalize_path, &cli, &mut ctx, event_tx).await; @@ -141,5 +150,8 @@ hooks: // With the notification subsystem, prior stage failures cause finalize to // send a failure notification and then return Ok (skipping artifacts/latehook) - assert!(result.is_ok(), "Finalize with failing early hook should return Ok after sending failure notification"); + assert!( + result.is_ok(), + "Finalize with failing early hook should return Ok after sending failure notification" + ); }