this derivation will be built: /nix/store/3zycv7p6p3i3whyivmsb6a1nhs5lkcfs-treefmt-check.drv treefmt-check> treefmt v2.5.0traversed 220 files treefmt-check> emitted 171 files for processing treefmt-check> formatted 171 files (8 changed) in 994ms treefmt-check> M Cargo.toml treefmt-check> M argunix-config/src/schema.rs treefmt-check> M argunix-daemon/src/worker.rs treefmt-check> M argunix-forge/src/forgejo.rs treefmt-check> M argunix-forge/src/github.rs treefmt-check> M argunix-forge/src/gitlab.rs treefmt-check> M argunix-notify/src/lib.rs treefmt-check> M argunix-web/src/webhook.rs treefmt-check> diff --git a/Cargo.toml b/Cargo.toml treefmt-check> index 83962f8..ae7c3f1 100644 treefmt-check> --- a/Cargo.toml treefmt-check> +++ b/Cargo.toml treefmt-check> @@ -16,7 +16,8 @@ members = [ treefmt-check> "argunix-builders", treefmt-check> "argunix-builder", treefmt-check> "argunix-daemon", treefmt-check> - "argunixctl", "argunix-notify", treefmt-check> + "argunixctl", treefmt-check> + "argunix-notify", treefmt-check> ] treefmt-check> treefmt-check> [workspace.package] treefmt-check> @@ -46,7 +47,11 @@ chrono = { version = "0.4", default-features = false, features = [ treefmt-check> "clock", treefmt-check> "std", treefmt-check> ] } treefmt-check> -lettre = { version = "0.11", default-features = false, features = ["builder", "tokio1-rustls-tls", "smtp-transport"] } treefmt-check> +lettre = { version = "0.11", default-features = false, features = [ treefmt-check> + "builder", treefmt-check> + "tokio1-rustls-tls", treefmt-check> + "smtp-transport", treefmt-check> +] } treefmt-check> treefmt-check> tokio = { version = "1", features = [ treefmt-check> "macros", treefmt-check> diff --git a/argunix-config/src/schema.rs b/argunix-config/src/schema.rs treefmt-check> index c603ea1..c016088 100644 treefmt-check> --- a/argunix-config/src/schema.rs treefmt-check> +++ b/argunix-config/src/schema.rs treefmt-check> @@ -492,7 +492,10 @@ impl Notification { treefmt-check> Some(allowed) => allowed.contains(event), treefmt-check> // Default: if `events` is not specified, alert on failures, but not successes. treefmt-check> // Wait, what's a good sensible default? Typically alerts are sent on failures. treefmt-check> - None => matches!(event, NotificationEvent::EvalFailed | NotificationEvent::JobFailed), treefmt-check> + None => matches!( treefmt-check> + event, treefmt-check> + NotificationEvent::EvalFailed | NotificationEvent::JobFailed treefmt-check> + ), treefmt-check> } treefmt-check> } treefmt-check> } treefmt-check> @@ -738,11 +741,8 @@ impl TryFrom for Config { treefmt-check> &wire_forge.push_to_registries, treefmt-check> &wire_repo.push_to_registries, treefmt-check> ]); treefmt-check> - let notify = merge_dedup(&[ treefmt-check> - &wire.defaults.notify, treefmt-check> - &wire_forge.notify, treefmt-check> - &wire_repo.notify, treefmt-check> - ]); treefmt-check> + let notify = treefmt-check> + merge_dedup(&[&wire.defaults.notify, &wire_forge.notify, &wire_repo.notify]); treefmt-check> repos.push(Repo { treefmt-check> slug, treefmt-check> forge: forge_name.clone(), treefmt-check> diff --git a/argunix-daemon/src/worker.rs b/argunix-daemon/src/worker.rs treefmt-check> index add98c8..4169382 100644 treefmt-check> --- a/argunix-daemon/src/worker.rs treefmt-check> +++ b/argunix-daemon/src/worker.rs treefmt-check> @@ -21,14 +21,14 @@ use argunix_builders::{ treefmt-check> BuildLifecycle, BuildOutcomeStatus, BuildPhase, BuilderDispatcher, NixCopyDirection, treefmt-check> nix_copy_over_pool, treefmt-check> }; treefmt-check> +use argunix_config::NotificationEvent; treefmt-check> use argunix_domain::{EvalId, EvalStatus, ImageFormat, JobId, JobStatus, RepoId, Sha, Slug}; treefmt-check> use argunix_effects::{Effect, EffectStatus, OutputContext, Severity}; treefmt-check> use argunix_forge::{CheckPost, CheckState, ForgeError, Provider}; treefmt-check> +use argunix_notify::{NotifyContext, send_notification}; treefmt-check> use argunix_sched::ScheduleStrategy; treefmt-check> use argunix_store::{EvalStore, JobPhaseMetrics, JobStore, RepoStore, SqlxStore}; treefmt-check> use argunix_web::{CancelRegistry, ConfigSnapshot, PauseRegistry, eval_target_url, job_target_url}; treefmt-check> -use argunix_notify::{send_notification, NotifyContext}; treefmt-check> -use argunix_config::NotificationEvent; treefmt-check> use chrono::Utc; treefmt-check> use std::path::{Path, PathBuf}; treefmt-check> use std::process::Stdio; treefmt-check> @@ -325,10 +325,12 @@ pub fn spawn( treefmt-check> Utc::now(), treefmt-check> ) treefmt-check> .await; treefmt-check> - treefmt-check> + treefmt-check> // Attempt to notify. We must fetch repo/eval because process failed. treefmt-check> if let Ok(Some(eval)) = ::get(&ctx.store, eval_id).await { treefmt-check> - if let Ok(Some(repo)) = ::get(&ctx.store, eval.repo_id).await { treefmt-check> + if let Ok(Some(repo)) = treefmt-check> + ::get(&ctx.store, eval.repo_id).await treefmt-check> + { treefmt-check> fire_notifications( treefmt-check> &ctx, treefmt-check> &repo, treefmt-check> @@ -1076,7 +1078,7 @@ async fn run_build_phase( treefmt-check> } treefmt-check> } treefmt-check> tally.record(final_status); treefmt-check> - treefmt-check> + treefmt-check> let job_event = match final_status { treefmt-check> JobStatus::Success | JobStatus::Cached => Some(NotificationEvent::JobSuccess), treefmt-check> JobStatus::Failure | JobStatus::Interrupted => Some(NotificationEvent::JobFailed), treefmt-check> @@ -1265,7 +1267,7 @@ async fn handle_cascade_skip( treefmt-check> ); treefmt-check> } treefmt-check> tally.record(JobStatus::Failure); treefmt-check> - treefmt-check> + treefmt-check> fire_notifications( treefmt-check> ctx, treefmt-check> repo, treefmt-check> @@ -1273,7 +1275,10 @@ async fn handle_cascade_skip( treefmt-check> NotificationEvent::JobFailed, treefmt-check> Some(spec.attr_path.as_str()), treefmt-check> Some(skip.job_id), treefmt-check> - Some(&format!("skipped because a dependency ({}) failed", skip.reason_drv)), treefmt-check> + Some(&format!( treefmt-check> + "skipped because a dependency ({}) failed", treefmt-check> + skip.reason_drv treefmt-check> + )), treefmt-check> ); treefmt-check> treefmt-check> if !collapsed_mode { treefmt-check> @@ -2568,7 +2573,7 @@ async fn try_publish_docker_image( treefmt-check> system, treefmt-check> git_ref: &eval.git_ref, treefmt-check> sha: &eval.sha, treefmt-check> - output_path, treefmt-check> + output_path, treefmt-check> }; treefmt-check> if let Err(e) = argunix_registry::publish(req).await { treefmt-check> tracing::warn!( treefmt-check> @@ -2591,7 +2596,7 @@ fn fire_notifications( treefmt-check> ) { treefmt-check> let snap = ctx.current.load(); treefmt-check> let external_url = snap.config.external_url.clone(); treefmt-check> - treefmt-check> + treefmt-check> // Find the notify bindings for this repo treefmt-check> let notify_targets = snap treefmt-check> .config treefmt-check> @@ -2627,7 +2632,7 @@ fn fire_notifications( treefmt-check> ); treefmt-check> } treefmt-check> } treefmt-check> - treefmt-check> + treefmt-check> drop(snap); treefmt-check> treefmt-check> tokio::spawn(async move { treefmt-check> @@ -2644,7 +2649,9 @@ fn fire_notifications( treefmt-check> }; treefmt-check> treefmt-check> for config in notification_configs { treefmt-check> - if let Err(e) = send_notification(&req_client, &config, &event, &nctx, detail_str.as_deref()).await { treefmt-check> + if let Err(e) = treefmt-check> + send_notification(&req_client, &config, &event, &nctx, detail_str.as_deref()).await treefmt-check> + { treefmt-check> tracing::warn!( treefmt-check> error = %e, treefmt-check> "Failed to send notification", treefmt-check> diff --git a/argunix-forge/src/forgejo.rs b/argunix-forge/src/forgejo.rs treefmt-check> index f600940..28708d9 100644 treefmt-check> --- a/argunix-forge/src/forgejo.rs treefmt-check> +++ b/argunix-forge/src/forgejo.rs treefmt-check> @@ -480,7 +480,14 @@ fn parse_push(body: &[u8]) -> Result { treefmt-check> repo_web_url: view.repository.html_url.filter(|s| !s.is_empty()), treefmt-check> repo_default_branch: view.repository.default_branch.filter(|s| !s.is_empty()), treefmt-check> committer_email: view.commits.and_then(|commits| { treefmt-check> - commits.into_iter().find(|c| c.id == sha.as_str()).and_then(|c| c.committer.and_then(|a| a.email).or_else(|| c.author.and_then(|a| a.email))) treefmt-check> + commits treefmt-check> + .into_iter() treefmt-check> + .find(|c| c.id == sha.as_str()) treefmt-check> + .and_then(|c| { treefmt-check> + c.committer treefmt-check> + .and_then(|a| a.email) treefmt-check> + .or_else(|| c.author.and_then(|a| a.email)) treefmt-check> + }) treefmt-check> }), treefmt-check> }) treefmt-check> } treefmt-check> @@ -550,7 +557,12 @@ fn parse_pull_request(body: &[u8]) -> Result { treefmt-check> head_sha, treefmt-check> head_ref: view.pull_request.head.git_ref, treefmt-check> base_ref: view.pull_request.base.git_ref, treefmt-check> - author: view.pull_request.user.username.or(view.pull_request.user.login).unwrap_or_default(), treefmt-check> + author: view treefmt-check> + .pull_request treefmt-check> + .user treefmt-check> + .username treefmt-check> + .or(view.pull_request.user.login) treefmt-check> + .unwrap_or_default(), treefmt-check> action: PullRequestAction::from_str(map_forgejo_action(&view.action)), treefmt-check> is_fork, treefmt-check> repo_name: view.repository.name, treefmt-check> diff --git a/argunix-forge/src/github.rs b/argunix-forge/src/github.rs treefmt-check> index dfa7ebc..236f0b5 100644 treefmt-check> --- a/argunix-forge/src/github.rs treefmt-check> +++ b/argunix-forge/src/github.rs treefmt-check> @@ -444,9 +444,11 @@ fn parse_push(body: &[u8]) -> Result { treefmt-check> repo_description: view.repository.description.filter(|s| !s.is_empty()), treefmt-check> repo_web_url: view.repository.html_url.filter(|s| !s.is_empty()), treefmt-check> repo_default_branch: view.repository.default_branch.filter(|s| !s.is_empty()), treefmt-check> - committer_email: view treefmt-check> - .head_commit treefmt-check> - .and_then(|c| c.committer.and_then(|a| a.email).or_else(|| c.author.and_then(|a| a.email))), treefmt-check> + committer_email: view.head_commit.and_then(|c| { treefmt-check> + c.committer treefmt-check> + .and_then(|a| a.email) treefmt-check> + .or_else(|| c.author.and_then(|a| a.email)) treefmt-check> + }), treefmt-check> }) treefmt-check> } treefmt-check> treefmt-check> diff --git a/argunix-forge/src/gitlab.rs b/argunix-forge/src/gitlab.rs treefmt-check> index 905daa9..430797a 100644 treefmt-check> --- a/argunix-forge/src/gitlab.rs treefmt-check> +++ b/argunix-forge/src/gitlab.rs treefmt-check> @@ -535,7 +535,10 @@ fn parse_push(body: &[u8]) -> Result { treefmt-check> repo_web_url: view.project.web_url.filter(|s| !s.is_empty()), treefmt-check> repo_default_branch: view.project.default_branch.filter(|s| !s.is_empty()), treefmt-check> committer_email: view.commits.and_then(|commits| { treefmt-check> - commits.into_iter().find(|c| c.id == sha.as_str()).and_then(|c| c.author.and_then(|a| a.email)) treefmt-check> + commits treefmt-check> + .into_iter() treefmt-check> + .find(|c| c.id == sha.as_str()) treefmt-check> + .and_then(|c| c.author.and_then(|a| a.email)) treefmt-check> }), treefmt-check> }) treefmt-check> } treefmt-check> @@ -616,7 +619,9 @@ fn parse_merge_request(body: &[u8]) -> Result { treefmt-check> head_ref: view.object_attributes.source_branch, treefmt-check> base_ref: view.object_attributes.target_branch, treefmt-check> author: view.user.username, treefmt-check> - action: PullRequestAction::from_str(map_gitlab_action(&view.object_attributes.action.unwrap_or_default())), treefmt-check> + action: PullRequestAction::from_str(map_gitlab_action( treefmt-check> + &view.object_attributes.action.unwrap_or_default(), treefmt-check> + )), treefmt-check> is_fork, treefmt-check> repo_name: view.project.name, treefmt-check> repo_description: view.project.description.filter(|s| !s.is_empty()), treefmt-check> diff --git a/argunix-notify/src/lib.rs b/argunix-notify/src/lib.rs treefmt-check> index b5fdffd..23e4ead 100644 treefmt-check> --- a/argunix-notify/src/lib.rs treefmt-check> +++ b/argunix-notify/src/lib.rs treefmt-check> @@ -32,7 +32,11 @@ impl<'a> NotifyContext<'a> { treefmt-check> self.attr_path.unwrap_or("Job") treefmt-check> } treefmt-check> }; treefmt-check> - format!("{scope} {status} for {} ({})", self.slug.as_str(), self.sha.short()) treefmt-check> + format!( treefmt-check> + "{scope} {status} for {} ({})", treefmt-check> + self.slug.as_str(), treefmt-check> + self.sha.short() treefmt-check> + ) treefmt-check> } treefmt-check> treefmt-check> fn url(&self) -> String { treefmt-check> @@ -89,7 +93,9 @@ pub async fn send_notification( treefmt-check> } treefmt-check> treefmt-check> match config { treefmt-check> - Notification::Slack { webhook_url_path, .. } => { treefmt-check> + Notification::Slack { treefmt-check> + webhook_url_path, .. treefmt-check> + } => { treefmt-check> let url = tokio::fs::read_to_string(webhook_url_path.path()).await?; treefmt-check> let url = url.trim(); treefmt-check> let text = ctx.markdown_body(event, detail); treefmt-check> @@ -100,7 +106,9 @@ pub async fn send_notification( treefmt-check> .await? treefmt-check> .error_for_status()?; treefmt-check> } treefmt-check> - Notification::Discord { webhook_url_path, .. } => { treefmt-check> + Notification::Discord { treefmt-check> + webhook_url_path, .. treefmt-check> + } => { treefmt-check> let url = tokio::fs::read_to_string(webhook_url_path.path()).await?; treefmt-check> let url = url.trim(); treefmt-check> let text = ctx.markdown_body(event, detail); treefmt-check> @@ -111,7 +119,9 @@ pub async fn send_notification( treefmt-check> .await? treefmt-check> .error_for_status()?; treefmt-check> } treefmt-check> - Notification::Teams { webhook_url_path, .. } => { treefmt-check> + Notification::Teams { treefmt-check> + webhook_url_path, .. treefmt-check> + } => { treefmt-check> let url = tokio::fs::read_to_string(webhook_url_path.path()).await?; treefmt-check> let url = url.trim(); treefmt-check> let text = ctx.markdown_body(event, detail); treefmt-check> @@ -129,7 +139,9 @@ pub async fn send_notification( treefmt-check> .await? treefmt-check> .error_for_status()?; treefmt-check> } treefmt-check> - Notification::Matrix { webhook_url_path, .. } => { treefmt-check> + Notification::Matrix { treefmt-check> + webhook_url_path, .. treefmt-check> + } => { treefmt-check> let url = tokio::fs::read_to_string(webhook_url_path.path()).await?; treefmt-check> let url = url.trim(); treefmt-check> let html = ctx.html_body(event, detail); treefmt-check> @@ -146,7 +158,9 @@ pub async fn send_notification( treefmt-check> .await? treefmt-check> .error_for_status()?; treefmt-check> } treefmt-check> - Notification::Webhook { url, secret_path, .. } => { treefmt-check> + Notification::Webhook { treefmt-check> + url, secret_path, .. treefmt-check> + } => { treefmt-check> let payload = json!({ treefmt-check> "event": event, treefmt-check> "forge": ctx.forge, treefmt-check> @@ -159,7 +173,7 @@ pub async fn send_notification( treefmt-check> "detail": detail, treefmt-check> }); treefmt-check> let body = serde_json::to_vec(&payload)?; treefmt-check> - treefmt-check> + treefmt-check> let mut req = client.post(url).header("Content-Type", "application/json"); treefmt-check> if let Some(secret_path) = secret_path { treefmt-check> let secret = tokio::fs::read_to_string(secret_path.path()).await?; treefmt-check> @@ -188,7 +202,7 @@ pub async fn send_notification( treefmt-check> use lettre::message::header::ContentType; treefmt-check> use lettre::transport::smtp::authentication::Credentials; treefmt-check> use lettre::{AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor}; treefmt-check> - treefmt-check> + treefmt-check> let mut builder = Message::builder() treefmt-check> .subject(ctx.format_title(event)) treefmt-check> .header(ContentType::TEXT_HTML); treefmt-check> @@ -198,22 +212,26 @@ pub async fn send_notification( treefmt-check> if let Some(email) = ctx.committer_email { treefmt-check> builder = builder.to(email.parse()?); treefmt-check> } else { treefmt-check> - tracing::info!("to_committer is true but no committer_email is available. skipping."); treefmt-check> + tracing::info!( treefmt-check> + "to_committer is true but no committer_email is available. skipping." treefmt-check> + ); treefmt-check> return Ok(()); treefmt-check> } treefmt-check> } else { treefmt-check> - tracing::warn!("email notification without a 'to' address or 'to_committer=true'. skipping."); treefmt-check> + tracing::warn!( treefmt-check> + "email notification without a 'to' address or 'to_committer=true'. skipping." treefmt-check> + ); treefmt-check> return Ok(()); treefmt-check> } treefmt-check> - treefmt-check> + treefmt-check> if let Some(f) = from { treefmt-check> builder = builder.from(f.parse()?); treefmt-check> } else { treefmt-check> builder = builder.from("argunix@localhost".parse()?); treefmt-check> } treefmt-check> - treefmt-check> + treefmt-check> let msg = builder.body(ctx.html_body(event, detail))?; treefmt-check> - treefmt-check> + treefmt-check> let mut transport_builder = AsyncSmtpTransport::::relay(smtp_host)?; treefmt-check> if let (Some(user), Some(pass_path)) = (smtp_user, smtp_password_path) { treefmt-check> let pass = tokio::fs::read_to_string(pass_path.path()).await?; treefmt-check> @@ -224,6 +242,6 @@ pub async fn send_notification( treefmt-check> transport.send(msg).await?; treefmt-check> } treefmt-check> } treefmt-check> - treefmt-check> + treefmt-check> Ok(()) treefmt-check> } treefmt-check> diff --git a/argunix-web/src/webhook.rs b/argunix-web/src/webhook.rs treefmt-check> index d15c4ef..dd6fbea 100644 treefmt-check> --- a/argunix-web/src/webhook.rs treefmt-check> +++ b/argunix-web/src/webhook.rs treefmt-check> @@ -297,7 +297,11 @@ async fn persist( treefmt-check> let _ = forge_name; treefmt-check> let (slug, git_ref, sha, trigger, pr_number, committer_email) = match &event { treefmt-check> NormalizedEvent::Push(PushEvent { treefmt-check> - slug, git_ref, sha, committer_email, .. treefmt-check> + slug, treefmt-check> + git_ref, treefmt-check> + sha, treefmt-check> + committer_email, treefmt-check> + .. treefmt-check> }) => ( treefmt-check> slug.clone(), treefmt-check> // Strip the `refs/heads/` prefix on storage so the UI can error: Cannot build '/nix/store/3zycv7p6p3i3whyivmsb6a1nhs5lkcfs-treefmt-check.drv'. Reason: builder failed with exit code 1. Output paths: /nix/store/05lyf8av3h1f1h0d1ki1fz0c25ishr0h-treefmt-check Last 25 log lines: > @@ -224,6 +242,6 @@ pub async fn send_notification( > transport.send(msg).await?; > } > } > -  > + > Ok(()) > } > diff --git a/argunix-web/src/webhook.rs b/argunix-web/src/webhook.rs > index d15c4ef..dd6fbea 100644 > --- a/argunix-web/src/webhook.rs > +++ b/argunix-web/src/webhook.rs > @@ -297,7 +297,11 @@ async fn persist( > let _ = forge_name; > let (slug, git_ref, sha, trigger, pr_number, committer_email) = match &event { > NormalizedEvent::Push(PushEvent { > - slug, git_ref, sha, committer_email, .. > + slug, > + git_ref, > + sha, > + committer_email, > + .. > }) => ( > slug.clone(), > // Strip the `refs/heads/` prefix on storage so the UI can For full logs, run: nix log /nix/store/3zycv7p6p3i3whyivmsb6a1nhs5lkcfs-treefmt-check.drv