git-next/src/server/actors/repo/branch.rs

120 lines
3.5 KiB
Rust

use std::time::Duration;
use actix::prelude::*;
use tracing::{info, warn};
use crate::server::{
actors::repo::{LoadConfigFromRepo, RepoActor, ValidateRepo},
config::{self, RepoConfigSource},
gitforge,
};
// advance next to the next commit towards the head of the dev branch
#[tracing::instrument(fields(next), skip_all)]
pub async fn advance_next(
next: gitforge::Commit,
dev_commit_history: Vec<gitforge::Commit>,
repo_config: config::RepoConfig,
forge: gitforge::Forge,
repository: gitforge::Repository,
addr: Addr<super::RepoActor>,
message_token: super::MessageToken,
) {
let next_commit = find_next_commit_on_dev(next, dev_commit_history);
let Some(commit) = next_commit else {
warn!("No commits to advance next to");
return;
};
if let Some(problem) = validate_commit_message(commit.message()) {
warn!("Can't advance next to commit '{}': {}", commit, problem);
return;
}
info!("Advancing next to commit '{}'", commit);
if let Err(err) = forge.branch_reset(
&repository,
repo_config.branches().next(),
commit.into(),
gitforge::Force::No,
) {
warn!(?err, "Failed")
}
tokio::time::sleep(Duration::from_secs(10)).await;
addr.do_send(ValidateRepo { message_token })
}
#[tracing::instrument]
fn validate_commit_message(message: &gitforge::Message) -> Option<String> {
let message = &message.to_string();
if message.to_ascii_lowercase().starts_with("wip") {
return Some("Is Work-In-Progress".to_string());
}
match git_conventional::Commit::parse(message) {
Ok(commit) => {
info!(?commit, "Pass");
None
}
Err(err) => {
warn!(?err, "Fail");
Some(err.kind().to_string())
}
}
}
fn find_next_commit_on_dev(
next: gitforge::Commit,
dev_commit_history: Vec<gitforge::Commit>,
) -> Option<gitforge::Commit> {
let mut next_commit: Option<gitforge::Commit> = None;
for commit in dev_commit_history.into_iter() {
if commit == next {
break;
};
next_commit.replace(commit);
}
next_commit
}
// advance main branch to the commit 'next'
#[tracing::instrument(fields(next), skip_all)]
pub async fn advance_main(
next: gitforge::Commit,
repo_config: config::RepoConfig,
forge: gitforge::Forge,
repository: gitforge::Repository,
addr: Addr<RepoActor>,
message_token: super::MessageToken,
) {
info!("Advancing main to next");
if let Err(err) = forge.branch_reset(
&repository,
repo_config.branches().main(),
next.into(),
gitforge::Force::No,
) {
warn!(?err, "Failed")
};
match repo_config.source() {
RepoConfigSource::Repo => addr.do_send(LoadConfigFromRepo),
RepoConfigSource::Server => addr.do_send(ValidateRepo { message_token }),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[actix_rt::test]
async fn test_find_next_commit_on_dev() {
let next = gitforge::Commit::new("current-next", "foo");
let expected = gitforge::Commit::new("dev-next", "next-should-go-here");
let dev_commit_history = vec![
gitforge::Commit::new("dev", "future"),
expected.clone(),
next.clone(),
gitforge::Commit::new("current-main", "history"),
];
let next_commit = find_next_commit_on_dev(next, dev_commit_history);
assert_eq!(next_commit, Some(expected));
}
}