From ce0dbf6b249956700c6a1705bf4ad85a09d53e8c Mon Sep 17 00:00:00 2001 From: Dawid Rycerz Date: Sun, 15 Feb 2026 21:27:00 +0100 Subject: feat: witryna 0.2.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch, cleanup, and status CLI commands. Persistent build state via state.json. Post-deploy hooks on success and failure with WITRYNA_BUILD_STATUS. Dependency diet (axum→tiny_http, clap→argh, tracing→log). Drop built-in rate limiting. Nix flake with NixOS module. Arch Linux PKGBUILD. Centralized version management. Co-Authored-By: Claude Opus 4.6 --- src/config.rs | 73 ++++++++++++++--------------------------------------------- 1 file changed, 17 insertions(+), 56 deletions(-) (limited to 'src/config.rs') diff --git a/src/config.rs b/src/config.rs index 63f3447..d79e91c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,20 +1,16 @@ use crate::repo_config; use anyhow::{Context as _, Result, bail}; +use log::LevelFilter; use serde::{Deserialize, Deserializer}; use std::collections::{HashMap, HashSet}; use std::net::SocketAddr; use std::path::{Component, PathBuf}; use std::time::Duration; -use tracing::level_filters::LevelFilter; fn default_log_dir() -> PathBuf { PathBuf::from("/var/log/witryna") } -const fn default_rate_limit() -> u32 { - 10 -} - const fn default_max_builds_to_keep() -> u32 { 5 } @@ -50,8 +46,6 @@ pub struct Config { #[serde(default = "default_log_dir")] pub log_dir: PathBuf, pub log_level: String, - #[serde(default = "default_rate_limit")] - pub rate_limit_per_minute: u32, #[serde(default = "default_max_builds_to_keep")] pub max_builds_to_keep: u32, /// Optional global git operation timeout (e.g., "2m", "5m"). @@ -109,7 +103,7 @@ pub struct SiteConfig { #[serde(default)] pub cache_dirs: Option>, /// Optional post-deploy hook command (array form, no shell). - /// Runs after successful symlink switch. Non-fatal on failure. + /// Runs after every build (success or failure). Non-fatal on failure. #[serde(default)] pub post_deploy: Option>, /// Optional environment variables passed to container builds and post-deploy hooks. @@ -265,17 +259,14 @@ impl Config { ) })?; } else if let Some(path) = &site.webhook_token_file { - site.webhook_token = tokio::fs::read_to_string(path) - .await - .with_context(|| { - format!( - "site '{}': failed to read webhook_token_file '{}'", - site.name, - path.display() - ) - })? - .trim() - .to_owned(); + let token_content = tokio::fs::read_to_string(path).await.with_context(|| { + format!( + "site '{}': failed to read webhook_token_file '{}'", + site.name, + path.display() + ) + })?; + token_content.trim().clone_into(&mut site.webhook_token); } } Ok(()) @@ -284,7 +275,6 @@ impl Config { fn validate(&self) -> Result<()> { self.validate_listen_address()?; self.validate_log_level()?; - self.validate_rate_limit()?; self.validate_git_timeout()?; self.validate_container_runtime()?; self.validate_sites()?; @@ -295,13 +285,12 @@ impl Config { if let Some(timeout) = self.git_timeout { if timeout < MIN_GIT_TIMEOUT { bail!( - "git_timeout is too short ({:?}): minimum is {}s", - timeout, + "git_timeout is too short ({timeout:?}): minimum is {}s", MIN_GIT_TIMEOUT.as_secs() ); } if timeout > MAX_GIT_TIMEOUT { - bail!("git_timeout is too long ({:?}): maximum is 1h", timeout,); + bail!("git_timeout is too long ({timeout:?}): maximum is 1h"); } } Ok(()) @@ -333,13 +322,6 @@ impl Config { Ok(()) } - fn validate_rate_limit(&self) -> Result<()> { - if self.rate_limit_per_minute == 0 { - bail!("rate_limit_per_minute must be greater than 0"); - } - Ok(()) - } - fn validate_sites(&self) -> Result<()> { let mut seen_names = HashSet::new(); @@ -369,12 +351,12 @@ impl Config { #[must_use] pub fn log_level_filter(&self) -> LevelFilter { match self.log_level.to_lowercase().as_str() { - "trace" => LevelFilter::TRACE, - "debug" => LevelFilter::DEBUG, - "warn" => LevelFilter::WARN, - "error" => LevelFilter::ERROR, + "trace" => LevelFilter::Trace, + "debug" => LevelFilter::Debug, + "warn" => LevelFilter::Warn, + "error" => LevelFilter::Error, // Catch-all: covers "info" and the unreachable default after validation. - _ => LevelFilter::INFO, + _ => LevelFilter::Info, } } @@ -920,27 +902,6 @@ sites = [] } } - #[test] - fn zero_rate_limit_rejected() { - let toml = r#" -listen_address = "127.0.0.1:8080" -container_runtime = "podman" -base_dir = "/var/lib/witryna" -log_level = "info" -rate_limit_per_minute = 0 -sites = [] -"#; - let config: Config = toml::from_str(toml).unwrap(); - let result = config.validate(); - assert!(result.is_err()); - assert!( - result - .unwrap_err() - .to_string() - .contains("rate_limit_per_minute") - ); - } - #[test] fn duplicate_site_names() { let toml = r#" -- cgit v1.2.3