Compare commits
No commits in common. "f3bc16d701292c5e4e4d48a65e32b5fd2572a060" and "421e85cb0b56081d09ca680ee085b75801d18786" have entirely different histories.
f3bc16d701
...
421e85cb0b
18 changed files with 163 additions and 239 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -945,6 +945,8 @@ dependencies = [
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert2",
|
"assert2",
|
||||||
|
"async-trait",
|
||||||
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
"clap",
|
"clap",
|
||||||
"derive-with",
|
"derive-with",
|
||||||
|
@ -962,6 +964,7 @@ dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"secrecy",
|
"secrecy",
|
||||||
"sendmail",
|
"sendmail",
|
||||||
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"standardwebhooks",
|
"standardwebhooks",
|
||||||
"test-log",
|
"test-log",
|
||||||
|
@ -979,6 +982,7 @@ name = "git-next-core"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix",
|
"actix",
|
||||||
|
"actix-rt",
|
||||||
"assert2",
|
"assert2",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"derive-with",
|
"derive-with",
|
||||||
|
@ -995,9 +999,9 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"test-log",
|
"test-log",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
|
||||||
"toml",
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
"ulid",
|
"ulid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1007,6 +1011,9 @@ version = "0.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert2",
|
"assert2",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"base64 0.22.1",
|
||||||
|
"bytes",
|
||||||
|
"derive_more",
|
||||||
"git-next-core",
|
"git-next-core",
|
||||||
"kxio",
|
"kxio",
|
||||||
"rand",
|
"rand",
|
||||||
|
@ -1014,7 +1021,9 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"ulid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1023,6 +1032,8 @@ version = "0.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert2",
|
"assert2",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"base64 0.22.1",
|
||||||
|
"bytes",
|
||||||
"clap",
|
"clap",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"git-next-core",
|
"git-next-core",
|
||||||
|
@ -1035,7 +1046,9 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"ulid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -31,12 +31,18 @@ kxio = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true }
|
||||||
|
|
||||||
|
# git
|
||||||
|
async-trait = { workspace = true }
|
||||||
|
|
||||||
# Conventional Commit check
|
# Conventional Commit check
|
||||||
git-conventional = { workspace = true }
|
git-conventional = { workspace = true }
|
||||||
|
|
||||||
# TOML parsing
|
# TOML parsing
|
||||||
toml = { workspace = true }
|
toml = { workspace = true }
|
||||||
|
|
||||||
|
# base64 decoding
|
||||||
|
base64 = { workspace = true }
|
||||||
|
|
||||||
# Actors
|
# Actors
|
||||||
actix = { workspace = true }
|
actix = { workspace = true }
|
||||||
actix-rt = { workspace = true }
|
actix-rt = { workspace = true }
|
||||||
|
@ -48,6 +54,7 @@ anyhow = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
|
||||||
# Webhooks
|
# Webhooks
|
||||||
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
ulid = { workspace = true }
|
ulid = { workspace = true }
|
||||||
time = { workspace = true }
|
time = { workspace = true }
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
//
|
//
|
||||||
use crate::alerts::short_message;
|
use crate::alerts::{messages::NotifyUser, short_message};
|
||||||
use git_next_core::git::UserNotification;
|
|
||||||
|
|
||||||
pub(super) fn send_desktop_notification(user_notification: &UserNotification) {
|
pub(super) fn send_desktop_notification(msg: &NotifyUser) {
|
||||||
let message = short_message(user_notification);
|
let message = short_message(msg);
|
||||||
if let Err(err) = notifica::notify("git-next", &message) {
|
if let Err(err) = notifica::notify("git-next", &message) {
|
||||||
tracing::warn!(?err, "failed to send desktop notification");
|
tracing::warn!(?err, "failed to send desktop notification");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{
|
use git_next_core::server::{EmailConfig, SmtpConfig};
|
||||||
git::UserNotification,
|
|
||||||
server::{EmailConfig, SmtpConfig},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::alerts::{full_message, short_message};
|
use crate::alerts::{full_message, messages::NotifyUser, short_message};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct EmailMessage {
|
struct EmailMessage {
|
||||||
|
@ -14,12 +11,12 @@ struct EmailMessage {
|
||||||
body: String,
|
body: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn send_email(user_notification: &UserNotification, email_config: &EmailConfig) {
|
pub(super) fn send_email(msg: &NotifyUser, email_config: &EmailConfig) {
|
||||||
let email_message = EmailMessage {
|
let email_message = EmailMessage {
|
||||||
from: email_config.from().to_string(),
|
from: email_config.from().to_string(),
|
||||||
to: email_config.to().to_string(),
|
to: email_config.to().to_string(),
|
||||||
subject: short_message(user_notification),
|
subject: short_message(msg),
|
||||||
body: full_message(user_notification),
|
body: full_message(msg),
|
||||||
};
|
};
|
||||||
match email_config.smtp() {
|
match email_config.smtp() {
|
||||||
Some(smtp) => send_email_smtp(email_message, smtp),
|
Some(smtp) => send_email_smtp(email_message, smtp),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//
|
//
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
use tracing::{info, instrument, Instrument as _};
|
use tracing::{info, instrument, Instrument as _};
|
||||||
|
|
||||||
use crate::alerts::{
|
use crate::alerts::{
|
||||||
|
@ -19,21 +18,19 @@ impl Handler<NotifyUser> for AlertsActor {
|
||||||
};
|
};
|
||||||
let net = self.net.clone();
|
let net = self.net.clone();
|
||||||
let shout = shout.clone();
|
let shout = shout.clone();
|
||||||
if let Some(user_notification) = self.history.sendable(msg.unwrap()) {
|
|
||||||
async move {
|
async move {
|
||||||
if let Some(webhook_config) = shout.webhook() {
|
if let Some(webhook_config) = shout.webhook() {
|
||||||
send_webhook(&user_notification, webhook_config, &net).await;
|
send_webhook(&msg, webhook_config, &net).await;
|
||||||
}
|
}
|
||||||
if let Some(email_config) = shout.email() {
|
if let Some(email_config) = shout.email() {
|
||||||
send_email(&user_notification, email_config);
|
send_email(&msg, email_config);
|
||||||
}
|
}
|
||||||
if shout.desktop() {
|
if shout.desktop() {
|
||||||
send_desktop_notification(&user_notification);
|
send_desktop_notification(&msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.in_current_span()
|
.in_current_span()
|
||||||
.into_actor(self)
|
.into_actor(self)
|
||||||
.wait(ctx);
|
.wait(ctx);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +1,2 @@
|
||||||
//
|
|
||||||
use git_next_core::git::UserNotification;
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
collections::HashMap,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct History {
|
pub struct History {}
|
||||||
/// The maximum age of an item in the history.
|
|
||||||
///
|
|
||||||
/// Items older than this will be dropped.
|
|
||||||
max_age_seconds: Duration,
|
|
||||||
|
|
||||||
/// Maps a user notification to when it was last seen.
|
|
||||||
///
|
|
||||||
/// The user notification will not be sent until after max_age_seconds from last seen.
|
|
||||||
///
|
|
||||||
/// Each time we see a given user notification, the last seen time will be updated.
|
|
||||||
items: HashMap<UserNotification, Instant>,
|
|
||||||
}
|
|
||||||
impl History {
|
|
||||||
pub fn new(max_age_seconds: Duration) -> Self {
|
|
||||||
Self {
|
|
||||||
max_age_seconds,
|
|
||||||
items: HashMap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sendable(&mut self, user_notification: UserNotification) -> Option<UserNotification> {
|
|
||||||
let now = Instant::now();
|
|
||||||
self.prune(&now); // remove expired items first
|
|
||||||
let contains_key = self.items.contains_key(&user_notification);
|
|
||||||
self.items.insert(user_notification.clone(), now);
|
|
||||||
if contains_key {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(user_notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prune(&mut self, now: &Instant) {
|
|
||||||
if let Some(threshold) = now.checked_sub(self.max_age_seconds) {
|
|
||||||
self.items.retain(|_, last_seen| *last_seen > threshold)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,86 @@
|
||||||
//
|
//
|
||||||
|
use derive_more::Deref as _;
|
||||||
use git_next_core::{git::UserNotification, message, server::Shout};
|
use git_next_core::{git::UserNotification, message, server::Shout};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
message!(UpdateShout: Shout: "Updated Shout configuration");
|
message!(UpdateShout: Shout: "Updated Shout configuration");
|
||||||
|
|
||||||
message!(NotifyUser: UserNotification: "Request to send the message payload to the notification webhook");
|
message!(NotifyUser: UserNotification: "Request to send the message payload to the notification webhook");
|
||||||
|
impl NotifyUser {
|
||||||
|
pub fn as_json(&self, timestamp: time::OffsetDateTime) -> serde_json::Value {
|
||||||
|
let timestamp = timestamp.unix_timestamp().to_string();
|
||||||
|
match self.deref() {
|
||||||
|
UserNotification::CICheckFailed {
|
||||||
|
forge_alias,
|
||||||
|
repo_alias,
|
||||||
|
commit,
|
||||||
|
} => json!({
|
||||||
|
"type": "cicheck.failed",
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"data": {
|
||||||
|
"forge_alias": forge_alias,
|
||||||
|
"repo_alias": repo_alias,
|
||||||
|
"commit": {
|
||||||
|
"sha": commit.sha(),
|
||||||
|
"message": commit.message()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UserNotification::RepoConfigLoadFailure {
|
||||||
|
forge_alias,
|
||||||
|
repo_alias,
|
||||||
|
reason,
|
||||||
|
} => json!({
|
||||||
|
"type": "config.load.failed",
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"data": {
|
||||||
|
"forge_alias": forge_alias,
|
||||||
|
"repo_alias": repo_alias,
|
||||||
|
"reason": reason
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UserNotification::WebhookRegistration {
|
||||||
|
forge_alias,
|
||||||
|
repo_alias,
|
||||||
|
reason,
|
||||||
|
} => json!({
|
||||||
|
"type": "webhook.registration.failed",
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"data": {
|
||||||
|
"forge_alias": forge_alias,
|
||||||
|
"repo_alias": repo_alias,
|
||||||
|
"reason": reason
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UserNotification::DevNotBasedOnMain {
|
||||||
|
forge_alias,
|
||||||
|
repo_alias,
|
||||||
|
dev_branch,
|
||||||
|
main_branch,
|
||||||
|
dev_commit,
|
||||||
|
main_commit,
|
||||||
|
} => json!({
|
||||||
|
"type": "branch.dev.not-on-main",
|
||||||
|
"timestamp": timestamp,
|
||||||
|
"data": {
|
||||||
|
"forge_alias": forge_alias,
|
||||||
|
"repo_alias": repo_alias,
|
||||||
|
"branches": {
|
||||||
|
"dev": dev_branch,
|
||||||
|
"main": main_branch
|
||||||
|
},
|
||||||
|
"commits": {
|
||||||
|
"dev": {
|
||||||
|
"sha": dev_commit.sha(),
|
||||||
|
"message": dev_commit.message()
|
||||||
|
},
|
||||||
|
"main": {
|
||||||
|
"sha": main_commit.sha(),
|
||||||
|
"message": main_commit.message()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::ops::Deref as _;
|
||||||
|
|
||||||
//
|
//
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
@ -6,6 +8,7 @@ use derive_more::derive::Constructor;
|
||||||
use git_next_core::{git::UserNotification, server::Shout};
|
use git_next_core::{git::UserNotification, server::Shout};
|
||||||
|
|
||||||
pub use history::History;
|
pub use history::History;
|
||||||
|
use messages::NotifyUser;
|
||||||
|
|
||||||
mod desktop;
|
mod desktop;
|
||||||
mod email;
|
mod email;
|
||||||
|
@ -14,12 +17,10 @@ mod history;
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
mod webhook;
|
mod webhook;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
#[derive(Debug, Constructor)]
|
#[derive(Debug, Constructor)]
|
||||||
pub struct AlertsActor {
|
pub struct AlertsActor {
|
||||||
shout: Option<Shout>, // config for sending alerts to users
|
shout: Option<Shout>, // config for sending alerts to users
|
||||||
|
#[allow(dead_code)] // TODO (#128) Prevent duplicate user notifications
|
||||||
history: History, // record of alerts sent recently (e.g. 24 hours)
|
history: History, // record of alerts sent recently (e.g. 24 hours)
|
||||||
net: kxio::network::Network,
|
net: kxio::network::Network,
|
||||||
}
|
}
|
||||||
|
@ -28,8 +29,8 @@ impl Actor for AlertsActor {
|
||||||
type Context = Context<Self>;
|
type Context = Context<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn short_message(user_notification: &UserNotification) -> String {
|
fn short_message(msg: &NotifyUser) -> String {
|
||||||
let tail = match user_notification {
|
let tail = match msg.deref() {
|
||||||
UserNotification::CICheckFailed {
|
UserNotification::CICheckFailed {
|
||||||
forge_alias,
|
forge_alias,
|
||||||
repo_alias,
|
repo_alias,
|
||||||
|
@ -57,8 +58,8 @@ fn short_message(user_notification: &UserNotification) -> String {
|
||||||
format!("[git-next] {tail}")
|
format!("[git-next] {tail}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_message(user_notification: &UserNotification) -> String {
|
fn full_message(msg: &NotifyUser) -> String {
|
||||||
match user_notification {
|
match msg.deref() {
|
||||||
UserNotification::CICheckFailed {
|
UserNotification::CICheckFailed {
|
||||||
forge_alias,
|
forge_alias,
|
||||||
repo_alias,
|
repo_alias,
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use assert2::let_assert;
|
|
||||||
use git_next_core::git::UserNotification;
|
|
||||||
|
|
||||||
use crate::{alerts::History, repo::tests::given};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn when_history_is_empty_then_message_is_passed() {
|
|
||||||
let mut history = History::new(Duration::from_millis(1));
|
|
||||||
|
|
||||||
let user_notification = UserNotification::RepoConfigLoadFailure {
|
|
||||||
forge_alias: given::a_forge_alias(),
|
|
||||||
repo_alias: given::a_repo_alias(),
|
|
||||||
reason: given::a_name(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = history.sendable(user_notification);
|
|
||||||
|
|
||||||
assert!(result.is_some());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn when_history_has_expired_then_message_is_passed() {
|
|
||||||
let dur = Duration::from_millis(1);
|
|
||||||
let mut history = History::new(dur);
|
|
||||||
|
|
||||||
let user_notification = UserNotification::RepoConfigLoadFailure {
|
|
||||||
forge_alias: given::a_forge_alias(),
|
|
||||||
repo_alias: given::a_repo_alias(),
|
|
||||||
reason: given::a_name(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// add message to history
|
|
||||||
let result = history.sendable(user_notification);
|
|
||||||
let_assert!(Some(user_notification) = result);
|
|
||||||
|
|
||||||
std::thread::sleep(dur);
|
|
||||||
|
|
||||||
// after dur, message has expired, so is still valid
|
|
||||||
let result = history.sendable(user_notification);
|
|
||||||
assert!(result.is_some());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn when_history_has_unexpired_then_message_is_blocked() {
|
|
||||||
let dur = Duration::from_millis(1);
|
|
||||||
let mut history = History::new(dur);
|
|
||||||
|
|
||||||
let user_notification = UserNotification::RepoConfigLoadFailure {
|
|
||||||
forge_alias: given::a_forge_alias(),
|
|
||||||
repo_alias: given::a_repo_alias(),
|
|
||||||
reason: given::a_name(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// add message to history
|
|
||||||
let result = history.sendable(user_notification);
|
|
||||||
let_assert!(Some(user_notification) = result);
|
|
||||||
|
|
||||||
// no time passed
|
|
||||||
// std::thread::sleep(dur);
|
|
||||||
|
|
||||||
// after dur, message has expired, so is still valid
|
|
||||||
let result = history.sendable(user_notification);
|
|
||||||
assert!(result.is_none());
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
mod history;
|
|
|
@ -1,10 +1,12 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{git::UserNotification, server::OutboundWebhook};
|
use git_next_core::server::OutboundWebhook;
|
||||||
use secrecy::ExposeSecret as _;
|
use secrecy::ExposeSecret as _;
|
||||||
use standardwebhooks::Webhook;
|
use standardwebhooks::Webhook;
|
||||||
|
|
||||||
|
use crate::alerts::messages::NotifyUser;
|
||||||
|
|
||||||
pub(super) async fn send_webhook(
|
pub(super) async fn send_webhook(
|
||||||
user_notification: &UserNotification,
|
msg: &NotifyUser,
|
||||||
webhook_config: &OutboundWebhook,
|
webhook_config: &OutboundWebhook,
|
||||||
net: &kxio::network::Network,
|
net: &kxio::network::Network,
|
||||||
) {
|
) {
|
||||||
|
@ -14,18 +16,18 @@ pub(super) async fn send_webhook(
|
||||||
tracing::warn!("Invalid notification configuration (signer) - can't sent notification");
|
tracing::warn!("Invalid notification configuration (signer) - can't sent notification");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
do_send_webhook(user_notification, webhook, webhook_config, net).await;
|
do_send_webhook(msg, webhook, webhook_config, net).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn do_send_webhook(
|
async fn do_send_webhook(
|
||||||
user_notification: &UserNotification,
|
msg: &NotifyUser,
|
||||||
webhook: Webhook,
|
webhook: Webhook,
|
||||||
webhook_config: &OutboundWebhook,
|
webhook_config: &OutboundWebhook,
|
||||||
net: &kxio::network::Network,
|
net: &kxio::network::Network,
|
||||||
) {
|
) {
|
||||||
let message_id = format!("msg_{}", ulid::Ulid::new());
|
let message_id = format!("msg_{}", ulid::Ulid::new());
|
||||||
let timestamp = time::OffsetDateTime::now_utc();
|
let timestamp = time::OffsetDateTime::now_utc();
|
||||||
let payload = user_notification.as_json(timestamp);
|
let payload = msg.as_json(timestamp);
|
||||||
let timestamp = timestamp.unix_timestamp();
|
let timestamp = timestamp.unix_timestamp();
|
||||||
let to_sign = format!("{message_id}.{timestamp}.{payload}");
|
let to_sign = format!("{message_id}.{timestamp}.{payload}");
|
||||||
tracing::info!(?to_sign, "");
|
tracing::info!(?to_sign, "");
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub mod messages;
|
||||||
mod notifications;
|
mod notifications;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests;
|
mod tests;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct RepoActorLog(std::sync::Arc<std::sync::RwLock<Vec<String>>>);
|
pub struct RepoActorLog(std::sync::Arc<std::sync::RwLock<Vec<String>>>);
|
||||||
|
|
|
@ -14,12 +14,14 @@ github = []
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# logging
|
# logging
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
tracing-subscriber = { workspace = true }
|
||||||
|
|
||||||
# fs/network
|
# fs/network
|
||||||
kxio = { workspace = true }
|
kxio = { workspace = true }
|
||||||
|
|
||||||
# Actors
|
# Actors
|
||||||
actix = { workspace = true }
|
actix = { workspace = true }
|
||||||
|
actix-rt = { workspace = true }
|
||||||
|
|
||||||
# TOML parsing
|
# TOML parsing
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
@ -35,7 +37,6 @@ async-trait = { workspace = true }
|
||||||
|
|
||||||
# Webhooks
|
# Webhooks
|
||||||
ulid = { workspace = true }
|
ulid = { workspace = true }
|
||||||
time = { workspace = true }
|
|
||||||
|
|
||||||
# boilerplate
|
# boilerplate
|
||||||
derive_more = { workspace = true }
|
derive_more = { workspace = true }
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use derive_more::derive::Display;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
crate::newtype!(BranchName: String, Display, Default, Hash, Serialize: "The name of a Git branch");
|
crate::newtype!(BranchName: String, derive_more::Display, Default, Serialize: "The name of a Git branch");
|
||||||
|
|
|
@ -3,6 +3,6 @@ use serde::Serialize;
|
||||||
|
|
||||||
use crate::newtype;
|
use crate::newtype;
|
||||||
|
|
||||||
newtype!(RepoAlias: String, Display, Default, Hash, PartialOrd, Ord, Serialize: r#"The alias of a repo.
|
newtype!(RepoAlias: String, Display, Default, PartialOrd, Ord, Serialize: r#"The alias of a repo.
|
||||||
|
|
||||||
This is the alias for the repo within `git-next-server.toml`."#);
|
This is the alias for the repo within `git-next-server.toml`."#);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
//
|
//
|
||||||
use crate::{git::Commit, BranchName, ForgeAlias, RepoAlias};
|
use crate::{git::Commit, BranchName, ForgeAlias, RepoAlias};
|
||||||
use serde_json::json;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum UserNotification {
|
pub enum UserNotification {
|
||||||
CICheckFailed {
|
CICheckFailed {
|
||||||
forge_alias: ForgeAlias,
|
forge_alias: ForgeAlias,
|
||||||
|
@ -28,81 +27,3 @@ pub enum UserNotification {
|
||||||
main_commit: Commit,
|
main_commit: Commit,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
impl UserNotification {
|
|
||||||
pub fn as_json(&self, timestamp: time::OffsetDateTime) -> serde_json::Value {
|
|
||||||
let timestamp = timestamp.unix_timestamp().to_string();
|
|
||||||
match self {
|
|
||||||
Self::CICheckFailed {
|
|
||||||
forge_alias,
|
|
||||||
repo_alias,
|
|
||||||
commit,
|
|
||||||
} => json!({
|
|
||||||
"type": "cicheck.failed",
|
|
||||||
"timestamp": timestamp,
|
|
||||||
"data": {
|
|
||||||
"forge_alias": forge_alias,
|
|
||||||
"repo_alias": repo_alias,
|
|
||||||
"commit": {
|
|
||||||
"sha": commit.sha(),
|
|
||||||
"message": commit.message()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
Self::RepoConfigLoadFailure {
|
|
||||||
forge_alias,
|
|
||||||
repo_alias,
|
|
||||||
reason,
|
|
||||||
} => json!({
|
|
||||||
"type": "config.load.failed",
|
|
||||||
"timestamp": timestamp,
|
|
||||||
"data": {
|
|
||||||
"forge_alias": forge_alias,
|
|
||||||
"repo_alias": repo_alias,
|
|
||||||
"reason": reason
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
Self::WebhookRegistration {
|
|
||||||
forge_alias,
|
|
||||||
repo_alias,
|
|
||||||
reason,
|
|
||||||
} => json!({
|
|
||||||
"type": "webhook.registration.failed",
|
|
||||||
"timestamp": timestamp,
|
|
||||||
"data": {
|
|
||||||
"forge_alias": forge_alias,
|
|
||||||
"repo_alias": repo_alias,
|
|
||||||
"reason": reason
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
Self::DevNotBasedOnMain {
|
|
||||||
forge_alias,
|
|
||||||
repo_alias,
|
|
||||||
dev_branch,
|
|
||||||
main_branch,
|
|
||||||
dev_commit,
|
|
||||||
main_commit,
|
|
||||||
} => json!({
|
|
||||||
"type": "branch.dev.not-on-main",
|
|
||||||
"timestamp": timestamp,
|
|
||||||
"data": {
|
|
||||||
"forge_alias": forge_alias,
|
|
||||||
"repo_alias": repo_alias,
|
|
||||||
"branches": {
|
|
||||||
"dev": dev_branch,
|
|
||||||
"main": main_branch
|
|
||||||
},
|
|
||||||
"commits": {
|
|
||||||
"dev": {
|
|
||||||
"sha": dev_commit.sha(),
|
|
||||||
"message": dev_commit.message()
|
|
||||||
},
|
|
||||||
"main": {
|
|
||||||
"sha": main_commit.sha(),
|
|
||||||
"message": main_commit.message()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,6 +12,9 @@ git-next-core = { workspace = true }
|
||||||
# logging
|
# logging
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|
||||||
|
# base64 decoding
|
||||||
|
base64 = { workspace = true }
|
||||||
|
|
||||||
# git
|
# git
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
|
|
||||||
|
@ -21,10 +24,18 @@ kxio = { workspace = true }
|
||||||
# TOML parsing
|
# TOML parsing
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
toml = { workspace = true }
|
||||||
|
|
||||||
# Secrets and Password
|
# Secrets and Password
|
||||||
secrecy = { workspace = true }
|
secrecy = { workspace = true }
|
||||||
|
|
||||||
|
# Webhooks
|
||||||
|
bytes = { workspace = true }
|
||||||
|
ulid = { workspace = true }
|
||||||
|
|
||||||
|
# boilerplate
|
||||||
|
derive_more = { workspace = true }
|
||||||
|
|
||||||
# # Actors
|
# # Actors
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ hmac = { workspace = true }
|
||||||
sha2 = { workspace = true }
|
sha2 = { workspace = true }
|
||||||
hex = { workspace = true }
|
hex = { workspace = true }
|
||||||
|
|
||||||
|
# base64 decoding
|
||||||
|
base64 = { workspace = true }
|
||||||
|
|
||||||
# git
|
# git
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
|
|
||||||
|
@ -29,10 +32,15 @@ kxio = { workspace = true }
|
||||||
# TOML parsing
|
# TOML parsing
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
toml = { workspace = true }
|
||||||
|
|
||||||
# Secrets and Password
|
# Secrets and Password
|
||||||
secrecy = { workspace = true }
|
secrecy = { workspace = true }
|
||||||
|
|
||||||
|
# Webhooks
|
||||||
|
bytes = { workspace = true }
|
||||||
|
ulid = { workspace = true }
|
||||||
|
|
||||||
# boilerplate
|
# boilerplate
|
||||||
derive_more = { workspace = true }
|
derive_more = { workspace = true }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue