mirror of
https://codeberg.org/Mo8it/git-webhook-client
synced 2024-11-21 11:06:32 +00:00
Use task instead of thread
This commit is contained in:
parent
3b853060d0
commit
3ac410372f
13 changed files with 89 additions and 66 deletions
|
@ -29,7 +29,7 @@ The program looks for the configuration file configured with the environment var
|
||||||
1. `secret`: The secret of the webhook.
|
1. `secret`: The secret of the webhook.
|
||||||
1. `base_url`: The base_url of the webhook client.
|
1. `base_url`: The base_url of the webhook client.
|
||||||
1. `hooks`: List of webhooks.
|
1. `hooks`: List of webhooks.
|
||||||
1. `repo_url`: Repository url.
|
1. `clone_url`: Repository url.
|
||||||
1. `current_dir`: The directory to run the command in.
|
1. `current_dir`: The directory to run the command in.
|
||||||
1. `command`: The command without any arguments.
|
1. `command`: The command without any arguments.
|
||||||
1. `args`: List of arguments separated by a comma.
|
1. `args`: List of arguments separated by a comma.
|
||||||
|
@ -43,7 +43,7 @@ secret: CHANGE_ME!
|
||||||
base_url: https://webhook.mo8it.com
|
base_url: https://webhook.mo8it.com
|
||||||
|
|
||||||
hooks:
|
hooks:
|
||||||
repo_url: https://codeberg.org/Mo8it/git-webhook-client
|
clone_url: https://codeberg.org/Mo8it/git-webhook-client
|
||||||
current_dir: .
|
current_dir: .
|
||||||
command: ls
|
command: ls
|
||||||
args: ["-l", "-a", "test_directory"]
|
args: ["-l", "-a", "test_directory"]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
CREATE TABLE hooklog (
|
CREATE TABLE hooklog (
|
||||||
id INTEGER NOT NULL PRIMARY KEY,
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
datetime TEXT NOT NULL,
|
datetime TEXT NOT NULL,
|
||||||
repo_url TEXT NOT NULL,
|
clone_url TEXT NOT NULL,
|
||||||
command_with_args TEXT NOT NULL,
|
command_with_args TEXT NOT NULL,
|
||||||
current_dir TEXT NOT NULL,
|
current_dir TEXT NOT NULL,
|
||||||
stdout TEXT,
|
stdout TEXT,
|
||||||
|
|
|
@ -28,10 +28,10 @@ pub struct Logging {
|
||||||
pub filename: String,
|
pub filename: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Clone, Deserialize)]
|
||||||
pub struct Hook {
|
pub struct Hook {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub repo_url: String,
|
pub clone_url: String,
|
||||||
pub current_dir: String,
|
pub current_dir: String,
|
||||||
pub command: String,
|
pub command: String,
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub fn add_hook_log(pool: &DBPool, hook: &Hook) -> Result<HookLog> {
|
||||||
|
|
||||||
let new_hook_log = NewHookLog {
|
let new_hook_log = NewHookLog {
|
||||||
datetime: &Local::now().format("%d.%m.%Y %T").to_string(),
|
datetime: &Local::now().format("%d.%m.%Y %T").to_string(),
|
||||||
repo_url: &hook.repo_url,
|
clone_url: &hook.clone_url,
|
||||||
command_with_args: &command_with_args,
|
command_with_args: &command_with_args,
|
||||||
current_dir: &hook.current_dir,
|
current_dir: &hook.current_dir,
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,7 +44,7 @@ impl Mailer {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&self, hook_name: &str, hook_log_link: &str, status: &str) -> Result<()> {
|
pub async fn send(&self, hook_name: &str, hook_log_link: &str, status: &str) -> Result<()> {
|
||||||
let email = self
|
let email = self
|
||||||
.message_builder
|
.message_builder
|
||||||
.clone()
|
.clone()
|
||||||
|
|
|
@ -9,6 +9,7 @@ mod routes;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod states;
|
mod states;
|
||||||
mod templates;
|
mod templates;
|
||||||
|
mod webhook;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::{
|
use axum::{
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::schema::hooklog;
|
||||||
pub struct HookLog {
|
pub struct HookLog {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub datetime: String,
|
pub datetime: String,
|
||||||
pub repo_url: String,
|
pub clone_url: String,
|
||||||
pub command_with_args: String,
|
pub command_with_args: String,
|
||||||
pub current_dir: String,
|
pub current_dir: String,
|
||||||
pub stdout: Option<String>,
|
pub stdout: Option<String>,
|
||||||
|
@ -19,7 +19,7 @@ pub struct HookLog {
|
||||||
#[diesel(table_name = hooklog)]
|
#[diesel(table_name = hooklog)]
|
||||||
pub struct NewHookLog<'a> {
|
pub struct NewHookLog<'a> {
|
||||||
pub datetime: &'a str,
|
pub datetime: &'a str,
|
||||||
pub repo_url: &'a str,
|
pub clone_url: &'a str,
|
||||||
pub command_with_args: &'a str,
|
pub command_with_args: &'a str,
|
||||||
pub current_dir: &'a str,
|
pub current_dir: &'a str,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,11 @@ use axum::{
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::{process::Command, sync::Arc, thread};
|
use std::sync::Arc;
|
||||||
use tracing::{error, info};
|
use tokio::task;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{db, errors, extractors, mailer, states, templates};
|
use crate::{db, errors, extractors, mailer, states, templates, webhook};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct IndexQuery {
|
pub struct IndexQuery {
|
||||||
|
@ -66,55 +67,18 @@ pub async fn trigger(
|
||||||
|
|
||||||
let hook_log_link = format!("{}/?id={}", state_config.base_url, hook_log_id);
|
let hook_log_link = format!("{}/?id={}", state_config.base_url, hook_log_id);
|
||||||
|
|
||||||
{
|
let webhook_task_context = webhook::TaskContext {
|
||||||
// Spawn and detach a thread that runs the command and fills the output in the log.
|
hook: hook.clone(),
|
||||||
|
hook_log_id,
|
||||||
|
hook_log_link: hook_log_link.clone(),
|
||||||
|
db: db.clone(),
|
||||||
|
mailer: mailer.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Spawn and detach a task that runs the command and fills the output in the log.
|
||||||
// This is useful to give a quick response to the git server in case that the command has a long
|
// This is useful to give a quick response to the git server in case that the command has a long
|
||||||
// execution time. It prevents reaching the webhook timeout of the git server.
|
// execution time. It prevents reaching the webhook timeout of the git server.
|
||||||
|
task::spawn(async move { webhook::run(webhook_task_context).await });
|
||||||
let command = hook.command.clone();
|
|
||||||
let args = hook.args.clone();
|
|
||||||
let current_dir = hook.current_dir.clone();
|
|
||||||
let db_pool = db.pool.clone();
|
|
||||||
let clone_url = clone_url.to_string();
|
|
||||||
let hook_name = hook.name.clone();
|
|
||||||
let hook_log_link = hook_log_link.clone();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
info!("Running webhook for Repo: {clone_url}");
|
|
||||||
|
|
||||||
let stdout: Vec<u8>;
|
|
||||||
let stderr: Vec<u8>;
|
|
||||||
let status_code: Option<i32>;
|
|
||||||
|
|
||||||
match Command::new(command)
|
|
||||||
.args(args)
|
|
||||||
.current_dir(current_dir)
|
|
||||||
.output()
|
|
||||||
{
|
|
||||||
Ok(output) => {
|
|
||||||
stdout = output.stdout;
|
|
||||||
stderr = output.stderr;
|
|
||||||
status_code = output.status.code();
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
stdout = Vec::new();
|
|
||||||
stderr = format!("Error while running the hook command: {e}")
|
|
||||||
.as_bytes()
|
|
||||||
.to_vec();
|
|
||||||
status_code = Some(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let status = if status_code == Some(0) { "Ok" } else { "Err" };
|
|
||||||
|
|
||||||
db::fill_hook_log(&db_pool, hook_log_id, &stdout, &stderr, status_code);
|
|
||||||
|
|
||||||
match mailer.send(&hook_name, &hook_log_link, status) {
|
|
||||||
Ok(_) => info!("Sent email with hook name {hook_name}"),
|
|
||||||
Err(e) => error!("{e:?}"),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(hook_log_link.into_response())
|
Ok(hook_log_link.into_response())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ diesel::table! {
|
||||||
hooklog (id) {
|
hooklog (id) {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
datetime -> Text,
|
datetime -> Text,
|
||||||
repo_url -> Text,
|
clone_url -> Text,
|
||||||
command_with_args -> Text,
|
command_with_args -> Text,
|
||||||
current_dir -> Text,
|
current_dir -> Text,
|
||||||
stdout -> Nullable<Text>,
|
stdout -> Nullable<Text>,
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl From<config::Config> for StateConfig {
|
||||||
|
|
||||||
impl StateConfig {
|
impl StateConfig {
|
||||||
pub fn get_hook(&self, clone_url: &str) -> Option<&config::Hook> {
|
pub fn get_hook(&self, clone_url: &str) -> Option<&config::Hook> {
|
||||||
self.hooks.iter().find(|&hook| hook.repo_url == clone_url)
|
self.hooks.iter().find(|&hook| hook.clone_url == clone_url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::models;
|
||||||
pub struct HookLog {
|
pub struct HookLog {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub datetime: String,
|
pub datetime: String,
|
||||||
pub repo_url: String,
|
pub clone_url: String,
|
||||||
pub command_with_args: String,
|
pub command_with_args: String,
|
||||||
pub current_dir: String,
|
pub current_dir: String,
|
||||||
pub stdout: String,
|
pub stdout: String,
|
||||||
|
@ -20,7 +20,7 @@ impl From<models::HookLog> for HookLog {
|
||||||
Self {
|
Self {
|
||||||
id: hook_log.id,
|
id: hook_log.id,
|
||||||
datetime: hook_log.datetime,
|
datetime: hook_log.datetime,
|
||||||
repo_url: hook_log.repo_url,
|
clone_url: hook_log.clone_url,
|
||||||
command_with_args: hook_log.command_with_args,
|
command_with_args: hook_log.command_with_args,
|
||||||
current_dir: hook_log.current_dir,
|
current_dir: hook_log.current_dir,
|
||||||
stdout: hook_log.stdout.unwrap_or_default(),
|
stdout: hook_log.stdout.unwrap_or_default(),
|
||||||
|
|
58
src/webhook.rs
Normal file
58
src/webhook.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
use std::{process::Command, sync::Arc};
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
|
use crate::{config, db, mailer, states};
|
||||||
|
|
||||||
|
pub struct TaskContext {
|
||||||
|
pub hook: config::Hook,
|
||||||
|
pub hook_log_id: i32,
|
||||||
|
pub hook_log_link: String,
|
||||||
|
pub db: Arc<states::DB>,
|
||||||
|
pub mailer: Arc<mailer::Mailer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(context: TaskContext) {
|
||||||
|
info!("Running webhook for repo: {}", context.hook.clone_url);
|
||||||
|
|
||||||
|
let stdout: Vec<u8>;
|
||||||
|
let stderr: Vec<u8>;
|
||||||
|
let status_code: Option<i32>;
|
||||||
|
|
||||||
|
match Command::new(&context.hook.command)
|
||||||
|
.args(&context.hook.args)
|
||||||
|
.current_dir(&context.hook.current_dir)
|
||||||
|
.output()
|
||||||
|
{
|
||||||
|
Ok(output) => {
|
||||||
|
stdout = output.stdout;
|
||||||
|
stderr = output.stderr;
|
||||||
|
status_code = output.status.code();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
stdout = Vec::new();
|
||||||
|
stderr = format!("Error while running the hook command: {e}")
|
||||||
|
.as_bytes()
|
||||||
|
.to_vec();
|
||||||
|
status_code = Some(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = if status_code == Some(0) { "Ok" } else { "Err" };
|
||||||
|
|
||||||
|
db::fill_hook_log(
|
||||||
|
&context.db.pool,
|
||||||
|
context.hook_log_id,
|
||||||
|
&stdout,
|
||||||
|
&stderr,
|
||||||
|
status_code,
|
||||||
|
);
|
||||||
|
|
||||||
|
match context
|
||||||
|
.mailer
|
||||||
|
.send(&context.hook.name, &context.hook_log_link, status)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => info!("Sent email with hook name {}", context.hook.name),
|
||||||
|
Err(e) => error!("{e:?}"),
|
||||||
|
};
|
||||||
|
}
|
|
@ -4,8 +4,8 @@ Hook log id:
|
||||||
Datetime:
|
Datetime:
|
||||||
{{ datetime }}
|
{{ datetime }}
|
||||||
|
|
||||||
Repository url:
|
Clone url:
|
||||||
{{ repo_url }}
|
{{ clone_url }}
|
||||||
|
|
||||||
Command with arguments:
|
Command with arguments:
|
||||||
{{ command_with_args }}
|
{{ command_with_args }}
|
||||||
|
|
Loading…
Reference in a new issue