forked from kemitix/git-next
chore(logging): clean up and reformat logging
This commit is contained in:
parent
5ba5a126c3
commit
7516ec1dc1
18 changed files with 209 additions and 118 deletions
|
@ -1,5 +1,4 @@
|
|||
steps:
|
||||
|
||||
todo_check:
|
||||
# INFO: https://woodpecker-ci.org/plugins/TODO-Checker
|
||||
image: codeberg.org/epsilon_02/todo-checker:1.1
|
||||
|
@ -8,8 +7,8 @@ steps:
|
|||
branch: next
|
||||
settings:
|
||||
# git-next-woodpecker-todo-checker - read:issue
|
||||
repository_token: '776a3b928b852472c2af727a360c85c00af64b9f'
|
||||
prefix_regex: "(#|//) (TODO|FIXME): "
|
||||
repository_token: "776a3b928b852472c2af727a360c85c00af64b9f"
|
||||
prefix_regex: "(#|//) (TODO|FIXME): "
|
||||
debug: false
|
||||
|
||||
lint_and_build:
|
||||
|
@ -21,7 +20,7 @@ steps:
|
|||
CARGO_TERM_COLOR: always
|
||||
commands:
|
||||
- cargo fmt --all -- --check
|
||||
- cargo clippy -- -D warnings -W clippy::nursery -W clippy::unwrap_used -W clippy::expect_used
|
||||
- cargo clippy -- -D warnings
|
||||
- cargo build
|
||||
|
||||
test:
|
||||
|
|
|
@ -75,7 +75,7 @@ anyhow = "1.0"
|
|||
cc-cli = { version = "0.1" }
|
||||
|
||||
[lints.clippy]
|
||||
nursery = "warn"
|
||||
nursery = { level = "warn", priority = -1 }
|
||||
# pedantic = "warn"
|
||||
unwrap_used = "warn"
|
||||
expect_used = "warn"
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
use actix::prelude::*;
|
||||
use tracing::error;
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::server::{config::RepoDetails, gitforge};
|
||||
use crate::server::{config, gitforge};
|
||||
|
||||
use super::{LoadedConfig, RepoActor};
|
||||
|
||||
/// Loads the [RepoConfig] from the `.git-next.toml` file in the repository
|
||||
pub async fn load(repo_details: RepoDetails, addr: Addr<RepoActor>, forge: gitforge::Forge) {
|
||||
let repo_config = match crate::server::config::load::load(&repo_details, &forge).await {
|
||||
#[tracing::instrument(skip_all, fields(branch = %repo_details.branch))]
|
||||
pub async fn load(
|
||||
repo_details: config::RepoDetails,
|
||||
addr: Addr<RepoActor>,
|
||||
forge: gitforge::Forge,
|
||||
) {
|
||||
info!("Loading .git-next.toml from repo");
|
||||
let repo_config = match config::load::load(&repo_details, &forge).await {
|
||||
Ok(repo_config) => repo_config,
|
||||
Err(err) => {
|
||||
error!(?err, "Failed to load config");
|
||||
return;
|
||||
}
|
||||
};
|
||||
info!("Loaded .git-next.toml from repo");
|
||||
addr.do_send(LoadedConfig(repo_config));
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ pub mod webhook;
|
|||
|
||||
use actix::prelude::*;
|
||||
use kxio::network::Network;
|
||||
use tracing::{info, warn};
|
||||
use tracing::{debug, info, warn, Instrument};
|
||||
|
||||
use crate::server::{
|
||||
actors::repo::webhook::WebhookAuth,
|
||||
|
@ -16,6 +16,7 @@ use crate::server::{
|
|||
use self::webhook::WebhookId;
|
||||
|
||||
pub struct RepoActor {
|
||||
span: tracing::Span,
|
||||
details: RepoDetails,
|
||||
webhook: Webhook,
|
||||
webhook_id: Option<WebhookId>, // INFO: if [None] then no webhook is configured
|
||||
|
@ -28,6 +29,7 @@ pub struct RepoActor {
|
|||
}
|
||||
impl RepoActor {
|
||||
pub(crate) fn new(details: RepoDetails, webhook: Webhook, net: Network) -> Self {
|
||||
let span = tracing::info_span!("RepoActor", repo = %details);
|
||||
let forge = match details.forge.forge_type {
|
||||
#[cfg(feature = "forgejo")]
|
||||
crate::server::config::ForgeType::ForgeJo => {
|
||||
|
@ -36,7 +38,9 @@ impl RepoActor {
|
|||
#[cfg(test)]
|
||||
crate::server::config::ForgeType::MockForge => gitforge::Forge::new_mock(),
|
||||
};
|
||||
debug!(?forge, "new");
|
||||
Self {
|
||||
span,
|
||||
details,
|
||||
webhook,
|
||||
webhook_id: None,
|
||||
|
@ -52,11 +56,14 @@ impl RepoActor {
|
|||
impl Actor for RepoActor {
|
||||
type Context = Context<Self>;
|
||||
fn stopping(&mut self, ctx: &mut Self::Context) -> Running {
|
||||
let _gaurd = self.span.enter();
|
||||
info!("Checking webhook");
|
||||
match self.webhook_id.take() {
|
||||
Some(webhook_id) => {
|
||||
let repo_details = self.details.clone();
|
||||
let net = self.net.clone();
|
||||
webhook::unregister(webhook_id, repo_details, net)
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
Running::Continue
|
||||
|
@ -69,7 +76,7 @@ impl std::fmt::Display for RepoActor {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"RepoActor: {}/{}",
|
||||
"{}/{}",
|
||||
self.details.forge.forge_name, self.details.repo_alias
|
||||
)
|
||||
}
|
||||
|
@ -80,9 +87,9 @@ impl std::fmt::Display for RepoActor {
|
|||
pub struct CloneRepo;
|
||||
impl Handler<CloneRepo> for RepoActor {
|
||||
type Result = ();
|
||||
#[tracing::instrument(skip_all, fields(%self))]
|
||||
#[tracing::instrument(name = "RepoActor::CloneRepo", skip_all, fields(repo = %self, gitdir = %self.details.gitdir))]
|
||||
fn handle(&mut self, _msg: CloneRepo, ctx: &mut Self::Context) -> Self::Result {
|
||||
info!(%self.details, "Clone/Update Repo");
|
||||
info!("Message Received");
|
||||
let gitdir = self.details.gitdir.clone();
|
||||
match self.forge.repo_clone(gitdir) {
|
||||
Ok(_) => ctx.address().do_send(LoadConfigFromRepo),
|
||||
|
@ -96,13 +103,14 @@ impl Handler<CloneRepo> for RepoActor {
|
|||
pub struct LoadConfigFromRepo;
|
||||
impl Handler<LoadConfigFromRepo> for RepoActor {
|
||||
type Result = ();
|
||||
#[tracing::instrument(skip_all, fields(%self))]
|
||||
#[tracing::instrument(name = "RepoActor::LoadConfigFromRepo", skip_all, fields(repo = %self))]
|
||||
fn handle(&mut self, _msg: LoadConfigFromRepo, ctx: &mut Self::Context) -> Self::Result {
|
||||
info!(%self.details, "Loading .git-next.toml from repo");
|
||||
info!("Message Received");
|
||||
let details = self.details.clone();
|
||||
let addr = ctx.address();
|
||||
let forge = self.forge.clone();
|
||||
config::load(details, addr, forge)
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
}
|
||||
|
@ -113,10 +121,10 @@ impl Handler<LoadConfigFromRepo> for RepoActor {
|
|||
struct LoadedConfig(pub RepoConfig);
|
||||
impl Handler<LoadedConfig> for RepoActor {
|
||||
type Result = ();
|
||||
#[tracing::instrument(skip_all, fields(%self))]
|
||||
#[tracing::instrument(name = "RepoActor::LoadedConfig", skip_all, fields(repo = %self.details, branches = %msg.0))]
|
||||
fn handle(&mut self, msg: LoadedConfig, ctx: &mut Self::Context) -> Self::Result {
|
||||
info!("Message Received");
|
||||
let repo_config = msg.0;
|
||||
info!(%self.details, %repo_config, "Config loaded");
|
||||
self.details.repo_config.replace(repo_config);
|
||||
if self.webhook_id.is_none() {
|
||||
webhook::register(
|
||||
|
@ -125,6 +133,7 @@ impl Handler<LoadedConfig> for RepoActor {
|
|||
ctx.address(),
|
||||
self.net.clone(),
|
||||
)
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
}
|
||||
|
@ -137,13 +146,14 @@ impl Handler<LoadedConfig> for RepoActor {
|
|||
pub struct ValidateRepo;
|
||||
impl Handler<ValidateRepo> for RepoActor {
|
||||
type Result = ();
|
||||
#[tracing::instrument(skip_all, fields(%self))]
|
||||
#[tracing::instrument(name = "RepoActor::ValidateRepo", skip_all, fields(repo = %self.details))]
|
||||
fn handle(&mut self, _msg: ValidateRepo, ctx: &mut Self::Context) -> Self::Result {
|
||||
info!("ValidateRepo");
|
||||
info!("Message Received");
|
||||
if let Some(repo_config) = self.details.repo_config.clone() {
|
||||
let forge = self.forge.clone();
|
||||
let addr = ctx.address();
|
||||
async move { forge.branches_validate_positions(repo_config, addr).await }
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
}
|
||||
|
@ -160,9 +170,9 @@ pub struct StartMonitoring {
|
|||
}
|
||||
impl Handler<StartMonitoring> for RepoActor {
|
||||
type Result = ();
|
||||
#[tracing::instrument(skip_all, fields(%self))]
|
||||
#[tracing::instrument(name = "RepoActor::StartMonitoring", skip_all, fields(repo = %self.details, main = %msg.main, next= %msg.next, dev = %msg.dev))]
|
||||
fn handle(&mut self, msg: StartMonitoring, ctx: &mut Self::Context) -> Self::Result {
|
||||
info!("StartMonitoring");
|
||||
info!("Message Received");
|
||||
let Some(repo_config) = self.details.repo_config.clone() else {
|
||||
warn!("No config loaded");
|
||||
return;
|
||||
|
@ -170,7 +180,7 @@ impl Handler<StartMonitoring> for RepoActor {
|
|||
|
||||
let next_ahead_of_main = msg.main != msg.next;
|
||||
let dev_ahead_of_next = msg.next != msg.dev;
|
||||
info!(%msg.main, %msg.next, %msg.dev, next_ahead_of_main, dev_ahead_of_next, "StartMonitoring");
|
||||
info!(next_ahead_of_main, dev_ahead_of_next, "StartMonitoring");
|
||||
|
||||
let repo_details = self.details.clone();
|
||||
let webhook = self.webhook.clone();
|
||||
|
@ -180,14 +190,17 @@ impl Handler<StartMonitoring> for RepoActor {
|
|||
|
||||
if next_ahead_of_main {
|
||||
status::check_next(msg.next, addr, forge)
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
} else if dev_ahead_of_next {
|
||||
branch::advance_next(msg.next, msg.dev_commit_history, repo_config, forge, addr)
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
} else if self.webhook_id.is_none() {
|
||||
webhook::register(repo_details, webhook, addr, net)
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
}
|
||||
|
@ -199,8 +212,9 @@ impl Handler<StartMonitoring> for RepoActor {
|
|||
pub struct WebhookRegistered(pub WebhookId, pub WebhookAuth);
|
||||
impl Handler<WebhookRegistered> for RepoActor {
|
||||
type Result = ();
|
||||
#[tracing::instrument(skip_all, fields(%self))]
|
||||
#[tracing::instrument(name = "RepoActor::WebhookRegistered", skip_all, fields(webhook_id = %msg.0))]
|
||||
fn handle(&mut self, msg: WebhookRegistered, _ctx: &mut Self::Context) -> Self::Result {
|
||||
info!("Message Received");
|
||||
self.webhook_id.replace(msg.0);
|
||||
self.webhook_auth.replace(msg.1);
|
||||
}
|
||||
|
@ -211,8 +225,9 @@ impl Handler<WebhookRegistered> for RepoActor {
|
|||
pub struct AdvanceMainTo(pub gitforge::Commit);
|
||||
impl Handler<AdvanceMainTo> for RepoActor {
|
||||
type Result = ();
|
||||
#[tracing::instrument(skip_all, fields(%self))]
|
||||
#[tracing::instrument(name = "RepoActor::AdvanceMainTo", skip_all, fields(commit = %msg.0))]
|
||||
fn handle(&mut self, msg: AdvanceMainTo, ctx: &mut Self::Context) -> Self::Result {
|
||||
info!("Message Received");
|
||||
let Some(repo_config) = self.details.repo_config.clone() else {
|
||||
warn!("No config loaded");
|
||||
return;
|
||||
|
@ -220,6 +235,7 @@ impl Handler<AdvanceMainTo> for RepoActor {
|
|||
let forge = self.forge.clone();
|
||||
let addr = ctx.address();
|
||||
branch::advance_main(msg.0, repo_config, forge, addr)
|
||||
.in_current_span()
|
||||
.into_actor(self)
|
||||
.wait(ctx);
|
||||
}
|
||||
|
|
|
@ -57,12 +57,12 @@ impl Deref for WebhookAuth {
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(%webhook_id))]
|
||||
pub async fn unregister(
|
||||
webhook_id: WebhookId,
|
||||
repo_details: crate::server::config::RepoDetails,
|
||||
net: network::Network,
|
||||
) {
|
||||
info!(?webhook_id, "unregister webhook");
|
||||
let hostname = &repo_details.forge.hostname;
|
||||
let repo_path = repo_details.repo_path;
|
||||
use secrecy::ExposeSecret;
|
||||
|
@ -81,11 +81,12 @@ pub async fn unregister(
|
|||
);
|
||||
let result = net.delete(request).await;
|
||||
match result {
|
||||
Ok(_) => info!(?webhook_id, "unregistered webhook"),
|
||||
Err(err) => warn!(?webhook_id, ?err, "Failed to unregister webhook"),
|
||||
Ok(_) => info!("unregistered webhook"),
|
||||
Err(err) => warn!(?err, "Failed to unregister webhook"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub async fn register(
|
||||
repo_details: crate::server::config::RepoDetails,
|
||||
webhook: Webhook,
|
||||
|
@ -103,7 +104,6 @@ pub async fn register(
|
|||
unregister(webhook_id, repo_details.clone(), net.clone()).await;
|
||||
}
|
||||
|
||||
info!("Registering webhook");
|
||||
let hostname = &repo_details.forge.hostname;
|
||||
let repo_path = repo_details.repo_path;
|
||||
use secrecy::ExposeSecret;
|
||||
|
@ -138,7 +138,7 @@ pub async fn register(
|
|||
match result {
|
||||
Ok(response) => {
|
||||
if let Some(hook) = response.response_body() {
|
||||
info!("Webhook registered");
|
||||
info!(webhook_id = %hook.id, "Webhook registered");
|
||||
addr.do_send(WebhookRegistered(hook.id(), authorisation));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,19 @@ use actix::prelude::*;
|
|||
pub use message::WebhookMessage;
|
||||
pub use router::AddWebhookRecipient;
|
||||
pub use router::WebhookRouter;
|
||||
use tracing::Instrument;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WebhookActor {
|
||||
span: tracing::Span,
|
||||
spawn_handle: Option<actix::SpawnHandle>,
|
||||
message_receiver: Recipient<WebhookMessage>,
|
||||
}
|
||||
impl WebhookActor {
|
||||
pub const fn new(message_receiver: Recipient<WebhookMessage>) -> Self {
|
||||
pub fn new(message_receiver: Recipient<WebhookMessage>) -> Self {
|
||||
let span = tracing::info_span!("WebhookActor");
|
||||
Self {
|
||||
span,
|
||||
message_receiver,
|
||||
spawn_handle: None,
|
||||
}
|
||||
|
@ -26,9 +30,10 @@ impl WebhookActor {
|
|||
impl Actor for WebhookActor {
|
||||
type Context = actix::Context<Self>;
|
||||
fn started(&mut self, ctx: &mut Self::Context) {
|
||||
let _gaurd = self.span.enter();
|
||||
let address: Recipient<WebhookMessage> = self.message_receiver.clone();
|
||||
let server = server::start(address);
|
||||
let spawn_handle = ctx.spawn(server.into_actor(self));
|
||||
let spawn_handle = ctx.spawn(server.in_current_span().into_actor(self));
|
||||
self.spawn_handle.replace(spawn_handle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use actix::prelude::*;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::server::{actors::webhook::message::WebhookMessage, config::RepoAlias};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WebhookRouter {
|
||||
span: tracing::Span,
|
||||
repos: HashMap<RepoAlias, Recipient<WebhookMessage>>,
|
||||
}
|
||||
impl WebhookRouter {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
let span = tracing::info_span!("WebhookRouter");
|
||||
Self {
|
||||
span,
|
||||
repos: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Actor for WebhookRouter {
|
||||
|
@ -22,10 +26,11 @@ impl Handler<WebhookMessage> for WebhookRouter {
|
|||
type Result = ();
|
||||
|
||||
fn handle(&mut self, msg: WebhookMessage, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let _gaurd = self.span.enter();
|
||||
let repo_alias = RepoAlias(msg.path().clone());
|
||||
debug!(?repo_alias, "Router...");
|
||||
debug!(repo = %repo_alias, "Router...");
|
||||
if let Some(recipient) = self.repos.get(&repo_alias) {
|
||||
debug!("Sending to recipient");
|
||||
info!("Sending to Recipient");
|
||||
recipient.do_send(msg);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +43,8 @@ impl Handler<AddWebhookRecipient> for WebhookRouter {
|
|||
type Result = ();
|
||||
|
||||
fn handle(&mut self, msg: AddWebhookRecipient, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let _gaurd = self.span.enter();
|
||||
info!(repo = %msg.0, "Register Recipient");
|
||||
self.repos.insert(msg.0, msg.1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use kxio::network;
|
||||
use terrors::OneOf;
|
||||
use tracing::error;
|
||||
|
||||
|
@ -7,17 +6,6 @@ use crate::server::{
|
|||
gitforge::{self, ForgeFileError},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RepoConfigFileNotFound;
|
||||
#[derive(Debug)]
|
||||
pub struct RepoConfigIsNotFile;
|
||||
#[derive(Debug)]
|
||||
pub struct RepoConfigDecodeError;
|
||||
#[derive(Debug)]
|
||||
pub struct RepoConfigParseError;
|
||||
#[derive(Debug)]
|
||||
pub struct RepoConfigUnknownError(pub network::StatusCode);
|
||||
|
||||
pub async fn load(
|
||||
details: &RepoDetails,
|
||||
forge: &gitforge::Forge,
|
||||
|
|
|
@ -30,8 +30,11 @@ pub struct ServerConfig {
|
|||
forge: HashMap<String, ForgeConfig>,
|
||||
}
|
||||
impl ServerConfig {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) fn load(fs: &FileSystem) -> Result<Self> {
|
||||
let str = fs.file_read_to_string(&fs.base().join("git-next-server.toml"))?;
|
||||
let file = fs.base().join("git-next-server.toml");
|
||||
info!(?file, "");
|
||||
let str = fs.file_read_to_string(&file)?;
|
||||
toml::from_str(&str).map_err(Into::into)
|
||||
}
|
||||
|
||||
|
@ -104,7 +107,7 @@ impl RepoConfig {
|
|||
}
|
||||
impl Display for RepoConfig {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.branches)
|
||||
write!(f, "{}", self.branches)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +141,7 @@ impl RepoBranches {
|
|||
}
|
||||
impl Display for RepoBranches {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
write!(f, "{},{},{}", self.main, self.next, self.dev)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +183,13 @@ impl ForgeConfig {
|
|||
}
|
||||
impl Display for ForgeConfig {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} - {}@{}", self.forge_type, self.user, self.hostname)
|
||||
write!(
|
||||
f,
|
||||
"{}:{}@{}",
|
||||
self.forge_type.to_string().to_lowercase(),
|
||||
self.user,
|
||||
self.hostname
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,7 +240,7 @@ impl AsRef<Self> for ServerRepoConfig {
|
|||
}
|
||||
impl Display for ServerRepoConfig {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} - {}", self.repo, self.branch)
|
||||
write!(f, "{}@{}", self.repo, self.branch)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,12 +411,12 @@ impl Display for RepoDetails {
|
|||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}/{} ({}): {}:{}/{} @ {}",
|
||||
"{}:{}/{}:{}@{}/{}@{}",
|
||||
self.forge.forge_type,
|
||||
self.forge.forge_name,
|
||||
self.repo_alias,
|
||||
self.forge.forge_type,
|
||||
self.forge.hostname,
|
||||
self.forge.user,
|
||||
self.forge.hostname,
|
||||
self.repo_path,
|
||||
self.branch,
|
||||
)
|
||||
|
@ -468,7 +477,7 @@ pub enum ForgeType {
|
|||
}
|
||||
impl Display for ForgeType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
write!(f, "{}", format!("{:?}", self).to_lowercase())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,12 +494,13 @@ impl GitDir {
|
|||
&self.0
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn validate(&self, repo_details: &RepoDetails) -> ValidationResult<()> {
|
||||
let git_remote = repo_details.git_remote();
|
||||
use gix::remote::Direction;
|
||||
let push_remote = self.find_default_remote(Direction::Push)?;
|
||||
let fetch_remote = self.find_default_remote(Direction::Fetch)?;
|
||||
info!(gitdir = %self, ?git_remote, ?push_remote, ?fetch_remote, "Gitdir::validate");
|
||||
info!(config = %git_remote, push = %push_remote, fetch = %fetch_remote, "Check remotes match");
|
||||
if git_remote != push_remote {
|
||||
return Err(RepoValidationError::MismatchDefaultPushRemote {
|
||||
found: push_remote,
|
||||
|
@ -506,7 +516,7 @@ impl GitDir {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
#[tracing::instrument(skip_all, fields(?direction))]
|
||||
fn find_default_remote(
|
||||
&self,
|
||||
direction: gix::remote::Direction,
|
||||
|
@ -514,7 +524,6 @@ impl GitDir {
|
|||
let repository = gix::ThreadSafeRepository::open(self.deref())
|
||||
.map_err(|e| RepoValidationError::UnableToOpenRepo(e.to_string()))?
|
||||
.to_thread_local();
|
||||
info!(?repository, from = ?self.deref(), "gix::discover");
|
||||
let Some(Ok(remote)) = repository.find_default_remote(gix::remote::Direction::Push) else {
|
||||
return Err(RepoValidationError::NoDefaultPushRemote);
|
||||
};
|
||||
|
@ -548,13 +557,11 @@ impl std::fmt::Display for GitDir {
|
|||
}
|
||||
impl From<&str> for GitDir {
|
||||
fn from(value: &str) -> Self {
|
||||
info!("GitDir::from::<&str>({value:?})");
|
||||
Self(value.into())
|
||||
}
|
||||
}
|
||||
impl From<PathBuf> for GitDir {
|
||||
fn from(value: PathBuf) -> Self {
|
||||
info!("GitDir::from::<PathBuf>({value:?})");
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use kxio::network::{self, Network};
|
||||
use tracing::{error, info};
|
||||
use tracing::error;
|
||||
|
||||
use crate::server::{
|
||||
config::{BranchName, RepoDetails},
|
||||
|
@ -18,7 +18,7 @@ pub async fn get_all(
|
|||
"https://{hostname}/api/v1/repos/{repo_path}/branches?token={token}"
|
||||
));
|
||||
|
||||
info!(%url, "Listing branches");
|
||||
// info!(%url, "Listing branches");
|
||||
let request = network::NetRequest::new(
|
||||
network::RequestMethod::Get,
|
||||
url,
|
||||
|
|
|
@ -7,3 +7,4 @@ pub use fetch::fetch;
|
|||
pub use get_all::get_all;
|
||||
pub use reset::reset;
|
||||
pub use validate_positions::validate_positions;
|
||||
pub use validate_positions::ValidatedPositions;
|
||||
|
|
|
@ -1,20 +1,37 @@
|
|||
use actix::prelude::*;
|
||||
|
||||
use kxio::network;
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
use crate::server::{
|
||||
self,
|
||||
actors::repo::{RepoActor, StartMonitoring},
|
||||
config::{BranchName, RepoConfig, RepoDetails},
|
||||
gitforge::{self, ForgeLike},
|
||||
};
|
||||
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum Error {
|
||||
Network(Box<kxio::network::NetworkError>),
|
||||
#[display("Failed to Reset Branch {branch} to {commit}")]
|
||||
FailedToResetBranch {
|
||||
branch: BranchName,
|
||||
commit: gitforge::Commit,
|
||||
},
|
||||
BranchReset(BranchName),
|
||||
BranchHasNoCommits(BranchName),
|
||||
DevBranchNotBasedOn(BranchName),
|
||||
}
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
pub struct ValidatedPositions {
|
||||
pub main: gitforge::Commit,
|
||||
pub next: gitforge::Commit,
|
||||
pub dev: gitforge::Commit,
|
||||
pub dev_commit_history: Vec<gitforge::Commit>,
|
||||
}
|
||||
|
||||
pub async fn validate_positions(
|
||||
forge: &gitforge::forgejo::ForgeJoEnv,
|
||||
repo_config: RepoConfig,
|
||||
addr: Addr<RepoActor>,
|
||||
) {
|
||||
) -> Result<ValidatedPositions, Error> {
|
||||
let repo_details = &forge.repo_details;
|
||||
// Collect Commit Histories for `main`, `next` and `dev` branches
|
||||
let commit_histories = get_commit_histories(repo_details, &repo_config, &forge.net).await;
|
||||
|
@ -22,7 +39,7 @@ pub async fn validate_positions(
|
|||
Ok(commit_histories) => commit_histories,
|
||||
Err(err) => {
|
||||
error!(?err, "Failed to get commit histories");
|
||||
return;
|
||||
return Err(Error::Network(Box::new(err)));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -32,7 +49,7 @@ pub async fn validate_positions(
|
|||
"No commits on main branch '{}'",
|
||||
repo_config.branches().main()
|
||||
);
|
||||
return;
|
||||
return Err(Error::BranchHasNoCommits(repo_config.branches().main()));
|
||||
};
|
||||
// verify that next is an ancestor of dev, and force update to it main if it isn't
|
||||
let Some(next) = commit_histories.next.first().cloned() else {
|
||||
|
@ -40,7 +57,7 @@ pub async fn validate_positions(
|
|||
"No commits on next branch '{}",
|
||||
repo_config.branches().next()
|
||||
);
|
||||
return;
|
||||
return Err(Error::BranchHasNoCommits(repo_config.branches().next()));
|
||||
};
|
||||
let next_is_ancestor_of_dev = commit_histories.dev.iter().any(|dev| dev == &next);
|
||||
if !next_is_ancestor_of_dev {
|
||||
|
@ -48,11 +65,15 @@ pub async fn validate_positions(
|
|||
if let Err(err) = forge.branch_reset(
|
||||
repo_config.branches().next(),
|
||||
main.into(),
|
||||
gitforge::Force::From(next.into()),
|
||||
gitforge::Force::From(next.clone().into()),
|
||||
) {
|
||||
warn!(?err, "Failed to reset next to main");
|
||||
return Err(Error::FailedToResetBranch {
|
||||
branch: repo_config.branches().next(),
|
||||
commit: next,
|
||||
});
|
||||
}
|
||||
return;
|
||||
return Err(Error::BranchReset(repo_config.branches().next()));
|
||||
}
|
||||
|
||||
let next_commits = commit_histories
|
||||
|
@ -69,18 +90,22 @@ pub async fn validate_positions(
|
|||
if let Err(err) = forge.branch_reset(
|
||||
repo_config.branches().next(),
|
||||
main.into(),
|
||||
gitforge::Force::From(next.into()),
|
||||
gitforge::Force::From(next.clone().into()),
|
||||
) {
|
||||
warn!(?err, "Failed to reset next to main");
|
||||
return Err(Error::FailedToResetBranch {
|
||||
branch: repo_config.branches().next(),
|
||||
commit: next,
|
||||
});
|
||||
}
|
||||
return;
|
||||
return Err(Error::BranchReset(repo_config.branches().next()));
|
||||
}
|
||||
let Some(next) = next_commits.first().cloned() else {
|
||||
warn!(
|
||||
"No commits on next branch '{}'",
|
||||
repo_config.branches().next()
|
||||
);
|
||||
return;
|
||||
return Err(Error::BranchHasNoCommits(repo_config.branches().next()));
|
||||
};
|
||||
let dev_has_next = commit_histories
|
||||
.dev
|
||||
|
@ -92,7 +117,7 @@ pub async fn validate_positions(
|
|||
repo_config.branches().dev(),
|
||||
repo_config.branches().next()
|
||||
);
|
||||
return; // dev is not based on next
|
||||
return Err(Error::DevBranchNotBasedOn(repo_config.branches().next())); // dev is not based on next
|
||||
}
|
||||
let dev_has_main = commit_histories.dev.iter().any(|commit| commit == &main);
|
||||
if !dev_has_main {
|
||||
|
@ -102,21 +127,23 @@ pub async fn validate_positions(
|
|||
repo_config.branches().main(),
|
||||
repo_config.branches().main(),
|
||||
);
|
||||
return;
|
||||
return Err(Error::DevBranchNotBasedOn(repo_config.branches().main()));
|
||||
}
|
||||
let Some(dev) = commit_histories.dev.first().cloned() else {
|
||||
warn!(
|
||||
"No commits on dev branch '{}'",
|
||||
repo_config.branches().dev()
|
||||
);
|
||||
return;
|
||||
return Err(Error::BranchHasNoCommits(repo_config.branches().dev()));
|
||||
};
|
||||
addr.do_send(StartMonitoring {
|
||||
info!("Validation - OK");
|
||||
|
||||
Ok(ValidatedPositions {
|
||||
main,
|
||||
next,
|
||||
dev,
|
||||
dev_commit_history: commit_histories.dev,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_commit_histories(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use kxio::network::{self, Network};
|
||||
use tracing::{error, info, warn};
|
||||
use tracing::{error, warn};
|
||||
|
||||
use crate::server::{
|
||||
config::{BranchName, RepoDetails},
|
||||
|
@ -21,7 +21,7 @@ pub(super) async fn contents_get(
|
|||
"https://{hostname}/api/v1/repos/{repo_path}/contents/{file_path}?ref={branch}&token={token}"
|
||||
));
|
||||
|
||||
info!(%url, "Loading config");
|
||||
// info!("Loading config");
|
||||
let request = network::NetRequest::new(
|
||||
network::RequestMethod::Get,
|
||||
url,
|
||||
|
|
|
@ -2,20 +2,22 @@ pub mod branch;
|
|||
mod file;
|
||||
mod repo;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use actix::prelude::*;
|
||||
|
||||
use kxio::network::{self, Network};
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
use crate::server::{
|
||||
actors::repo::RepoActor,
|
||||
actors::repo::{RepoActor, StartMonitoring, ValidateRepo},
|
||||
config::{BranchName, GitDir, RepoConfig, RepoDetails},
|
||||
gitforge::{self, RepoCloneError},
|
||||
gitforge::{self, forgejo::branch::ValidatedPositions, RepoCloneError},
|
||||
types::GitRef,
|
||||
};
|
||||
|
||||
struct ForgeJo;
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ForgeJoEnv {
|
||||
repo_details: RepoDetails,
|
||||
net: Network,
|
||||
|
@ -44,7 +46,26 @@ impl super::ForgeLike for ForgeJoEnv {
|
|||
}
|
||||
|
||||
async fn branches_validate_positions(&self, repo_config: RepoConfig, addr: Addr<RepoActor>) {
|
||||
branch::validate_positions(self, repo_config, addr).await
|
||||
match branch::validate_positions(self, repo_config).await {
|
||||
Ok(ValidatedPositions {
|
||||
main,
|
||||
next,
|
||||
dev,
|
||||
dev_commit_history,
|
||||
}) => {
|
||||
addr.do_send(StartMonitoring {
|
||||
main,
|
||||
next,
|
||||
dev,
|
||||
dev_commit_history,
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("{}", err);
|
||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||
addr.do_send(ValidateRepo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn branch_reset(
|
||||
|
@ -102,16 +123,15 @@ impl super::ForgeLike for ForgeJoEnv {
|
|||
}
|
||||
|
||||
fn repo_clone(&self, gitdir: GitDir) -> Result<(), RepoCloneError> {
|
||||
if gitdir.exists() {
|
||||
info!(%gitdir, "Gitdir already exists - validating...");
|
||||
gitdir
|
||||
.validate(&self.repo_details)
|
||||
.map_err(|e| RepoCloneError::Validation(e.to_string()))
|
||||
.inspect(|_| info!(%gitdir, "Validation - OK"))
|
||||
} else {
|
||||
info!(%gitdir, "Gitdir doesn't exists - cloning...");
|
||||
repo::clone(&self.repo_details, gitdir).inspect(|_| info!("Cloned - OK"))
|
||||
if !gitdir.exists() {
|
||||
info!("Local copy not found - cloning...");
|
||||
repo::clone(&self.repo_details, gitdir.clone())?;
|
||||
}
|
||||
info!("Validating...");
|
||||
gitdir
|
||||
.validate(&self.repo_details)
|
||||
.map_err(|e| RepoCloneError::Validation(e.to_string()))
|
||||
.inspect(|_| info!("Validation - OK"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@ use crate::server::{
|
|||
gitforge::RepoCloneError,
|
||||
};
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn clone(repo_details: &RepoDetails, gitdir: GitDir) -> Result<(), RepoCloneError> {
|
||||
use secrecy::ExposeSecret;
|
||||
let origin = repo_details.origin();
|
||||
info!("Cloning");
|
||||
let (repository, _outcome) =
|
||||
let (_repository, _outcome) =
|
||||
gix::prepare_clone_bare(origin.expose_secret().as_str(), gitdir.deref())?
|
||||
.fetch_only(gix::progress::Discard, &AtomicBool::new(false))?;
|
||||
info!(?repository, "Cloned");
|
||||
info!("Cloned - OK");
|
||||
|
||||
Ok(()) // TODO: (#69) return Repository inside a newtype to store in the RepoActor for reuse else where
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::server::{
|
|||
};
|
||||
|
||||
struct MockForge;
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MockForgeEnv;
|
||||
impl MockForgeEnv {
|
||||
pub(crate) const fn new() -> Self {
|
||||
|
|
|
@ -58,7 +58,7 @@ pub trait ForgeLike {
|
|||
fn repo_clone(&self, gitdir: GitDir) -> Result<(), RepoCloneError>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Forge {
|
||||
Mock(mock_forge::MockForgeEnv),
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
|
|
|
@ -69,24 +69,34 @@ pub async fn start(fs: FileSystem, net: Network) {
|
|||
return;
|
||||
}
|
||||
};
|
||||
// create data dir if missing
|
||||
// Server Storage
|
||||
let dir = server_config.storage().path();
|
||||
if !dir.exists() {
|
||||
info!(?dir, "server storage doesn't exist - creating it");
|
||||
if let Err(err) = fs.dir_create(dir) {
|
||||
error!(?err, ?dir, "Failed to create server storage directory");
|
||||
error!(?err, ?dir, "Failed to create server storage");
|
||||
return;
|
||||
}
|
||||
}
|
||||
let Ok(canon) = dir.canonicalize() else {
|
||||
error!(?dir, "Failed to confirm servier storage");
|
||||
return;
|
||||
};
|
||||
info!(dir = ?canon, "server storage");
|
||||
|
||||
let webhook_router = webhook::WebhookRouter::new().start();
|
||||
let webhook = server_config.webhook();
|
||||
// Forge directories in Server Storage
|
||||
let server_storage = server_config.storage();
|
||||
|
||||
if let Err(err) = create_forge_data_directories(&server_config, &fs, &dir) {
|
||||
error!(?err, "Failure creating forge data directories");
|
||||
error!(?err, "Failure creating forge storage");
|
||||
return;
|
||||
}
|
||||
|
||||
// Webhook Server
|
||||
info!("Starting Webhook Server...");
|
||||
let webhook_router = webhook::WebhookRouter::new().start();
|
||||
let webhook = server_config.webhook();
|
||||
|
||||
// Forge Actors
|
||||
for (forge_name, forge_config) in server_config.forges() {
|
||||
create_forge_repos(
|
||||
forge_config,
|
||||
|
@ -100,7 +110,9 @@ pub async fn start(fs: FileSystem, net: Network) {
|
|||
.map(|(alias, addr)| webhook::AddWebhookRecipient(alias, addr.recipient()))
|
||||
.for_each(|msg| webhook_router.do_send(msg));
|
||||
}
|
||||
|
||||
let webhook_server = webhook::WebhookActor::new(webhook_router.recipient()).start();
|
||||
info!("Server running - Press Ctrl-C to stop...");
|
||||
let _ = actix_rt::signal::ctrl_c().await;
|
||||
info!("Ctrl-C received, shutting down...");
|
||||
drop(webhook_server);
|
||||
|
@ -119,6 +131,7 @@ fn create_forge_data_directories(
|
|||
return Err(Error::ForgeDirIsNotDirectory { path });
|
||||
}
|
||||
} else {
|
||||
info!(%forge_name, ?path, "creating storage");
|
||||
fs.dir_create_all(&path)?;
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +146,8 @@ fn create_forge_repos(
|
|||
webhook: &Webhook,
|
||||
net: &Network,
|
||||
) -> Vec<(ForgeName, RepoAlias, RepoActor)> {
|
||||
let span = tracing::info_span!("Forge", %forge_name, %forge_config);
|
||||
let span =
|
||||
tracing::info_span!("create_forge_repos", name = %forge_name, config = %forge_config);
|
||||
let _guard = span.enter();
|
||||
info!("Creating Forge");
|
||||
let mut repos = vec![];
|
||||
|
@ -147,9 +161,8 @@ fn create_forge_repos(
|
|||
for (repo_alias, server_repo_config) in forge_config.repos() {
|
||||
let forge_repo = creator((repo_alias, server_repo_config));
|
||||
info!(
|
||||
forge = %forge_repo.0,
|
||||
alias = %forge_repo.1,
|
||||
"created forge repo"
|
||||
"Created Repo"
|
||||
);
|
||||
repos.push(forge_repo);
|
||||
}
|
||||
|
@ -166,8 +179,9 @@ fn create_actor(
|
|||
let server_storage = server_storage.clone();
|
||||
let webhook = webhook.clone();
|
||||
let net = net.clone();
|
||||
move |(repo_name, server_repo_config)| {
|
||||
let span = tracing::info_span!("Repo", %repo_name, %server_repo_config);
|
||||
move |(repo_alias, server_repo_config)| {
|
||||
let span =
|
||||
tracing::info_span!("create_actor", alias = %repo_alias, config = %server_repo_config);
|
||||
let _guard = span.enter();
|
||||
info!("Creating Repo");
|
||||
let gitdir = server_repo_config.gitdir().map_or_else(
|
||||
|
@ -176,7 +190,7 @@ fn create_actor(
|
|||
server_storage
|
||||
.path()
|
||||
.join(forge_name.to_string())
|
||||
.join(repo_name.to_string()),
|
||||
.join(repo_alias.to_string()),
|
||||
)
|
||||
},
|
||||
|gitdir| gitdir,
|
||||
|
@ -184,15 +198,15 @@ fn create_actor(
|
|||
// INFO: can't canonicalise gitdir as the path needs to exist to do that and we may not
|
||||
// have cloned the repo yet
|
||||
let repo_details = config::RepoDetails::new(
|
||||
&repo_name,
|
||||
&repo_alias,
|
||||
server_repo_config,
|
||||
&forge_name,
|
||||
&forge_config,
|
||||
gitdir,
|
||||
);
|
||||
info!("Starting Repo Actor");
|
||||
let actor = actors::repo::RepoActor::new(repo_details, webhook.clone(), net.clone());
|
||||
info!("Created Repo");
|
||||
(forge_name.clone(), repo_name, actor)
|
||||
(forge_name.clone(), repo_alias, actor)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,7 +214,7 @@ fn start_actor(
|
|||
actor: (ForgeName, RepoAlias, actors::repo::RepoActor),
|
||||
) -> (RepoAlias, Addr<actors::repo::RepoActor>) {
|
||||
let (forge_name, repo_alias, actor) = actor;
|
||||
let span = tracing::info_span!("Forge/Repo", %forge_name, %repo_alias);
|
||||
let span = tracing::info_span!("start_actor", forge = %forge_name, repo = %repo_alias);
|
||||
let _guard = span.enter();
|
||||
info!("Starting");
|
||||
let addr = actor.start();
|
||||
|
|
Loading…
Reference in a new issue