forked from kemitix/git-next
Implement advancing next branch to next commit on dev branch
Uses gix to invoke git commands as there is not API to directly update the position of a branch. Closes kemitix/git-next#14
This commit is contained in:
parent
a5e9421405
commit
98a94ea855
5 changed files with 104 additions and 15 deletions
|
@ -17,6 +17,9 @@ tracing-subscriber = "0.3"
|
||||||
# base64 decoding
|
# base64 decoding
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
|
|
||||||
|
# git
|
||||||
|
gix = "0.61"
|
||||||
|
|
||||||
# fs/network
|
# fs/network
|
||||||
kxio = "0.1" # { git = "https://git.kemitix.net/kemitix/kxio.git", branch = "main" }
|
kxio = "0.1" # { git = "https://git.kemitix.net/kemitix/kxio.git", branch = "main" }
|
||||||
|
|
||||||
|
|
|
@ -67,20 +67,69 @@ pub async fn validate_positions(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let dev = commit_histories.dev[0].clone();
|
let dev = commit_histories.dev[0].clone();
|
||||||
addr.do_send(StartMonitoring { main, next, dev });
|
addr.do_send(StartMonitoring {
|
||||||
|
main,
|
||||||
|
next,
|
||||||
|
dev,
|
||||||
|
dev_commit_history: commit_histories.dev,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance next to the next commit towards the head of the dev branch
|
// advance next to the next commit towards the head of the dev branch
|
||||||
#[allow(dead_code)]
|
|
||||||
pub async fn advance_next(
|
pub async fn advance_next(
|
||||||
_next: forge::Commit,
|
next: forge::Commit,
|
||||||
_repo_details: config::RepoDetails,
|
dev_commit_history: Vec<forge::Commit>,
|
||||||
|
repo_details: config::RepoDetails,
|
||||||
|
repo_config: config::RepoConfig,
|
||||||
addr: Addr<RepoActor>,
|
addr: Addr<RepoActor>,
|
||||||
_net: network::Network,
|
|
||||||
) {
|
) {
|
||||||
// TODO: (#14) advance next one commit towards dev
|
|
||||||
info!("Advance Next");
|
info!("Advance Next");
|
||||||
|
let user = repo_details.forge.user;
|
||||||
|
let token = repo_details.forge.token;
|
||||||
|
let hostname = repo_details.forge.hostname;
|
||||||
|
let path = repo_details.repo;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
let next = repo_config.branches().next();
|
||||||
|
let command =
|
||||||
|
format!("/usr/bin/git push https://{user}:{token}@{hostname}/{path}.git {commit}:{next}");
|
||||||
|
info!("Running command: {}", command);
|
||||||
|
match gix::command::prepare(command)
|
||||||
|
.with_shell_allow_argument_splitting()
|
||||||
|
.spawn()
|
||||||
|
{
|
||||||
|
Ok(mut child) => {
|
||||||
|
match child.wait() {
|
||||||
|
Ok(exit_status) => {
|
||||||
|
info!(%exit_status, "Advance Next Success");
|
||||||
addr.do_send(StartRepo);
|
addr.do_send(StartRepo);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!(?err, "Advance Next Failed (wait)")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!(?err, "Advance Next Failed (spawn)")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_next_commit_on_dev(
|
||||||
|
next: forge::Commit,
|
||||||
|
dev_commit_history: Vec<forge::Commit>,
|
||||||
|
) -> Option<forge::Commit> {
|
||||||
|
let mut next_commit: Option<forge::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'
|
// advance main branch to the commit 'next'
|
||||||
|
@ -95,3 +144,21 @@ pub async fn advance_main(
|
||||||
info!("Advance Main");
|
info!("Advance Main");
|
||||||
addr.do_send(StartRepo);
|
addr.do_send(StartRepo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_find_next_commit_on_dev() {
|
||||||
|
let next = forge::Commit::new("current-next");
|
||||||
|
let dev_commit_history = vec![
|
||||||
|
forge::Commit::new("dev"),
|
||||||
|
forge::Commit::new("dev-next"),
|
||||||
|
forge::Commit::new("current-next"),
|
||||||
|
forge::Commit::new("current-main"),
|
||||||
|
];
|
||||||
|
let next_commit = find_next_commit_on_dev(next, dev_commit_history);
|
||||||
|
assert_eq!(next_commit, Some(forge::Commit::new("dev-next")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ mod webhook;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use kxio::network::Network;
|
use kxio::network::Network;
|
||||||
use tracing::info;
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use crate::server::{
|
use crate::server::{
|
||||||
config::{RepoConfig, RepoDetails},
|
config::{RepoConfig, RepoDetails},
|
||||||
|
@ -86,22 +86,35 @@ pub struct StartMonitoring {
|
||||||
pub main: forge::Commit,
|
pub main: forge::Commit,
|
||||||
pub next: forge::Commit,
|
pub next: forge::Commit,
|
||||||
pub dev: forge::Commit,
|
pub dev: forge::Commit,
|
||||||
|
pub dev_commit_history: Vec<forge::Commit>,
|
||||||
}
|
}
|
||||||
impl Handler<StartMonitoring> for RepoActor {
|
impl Handler<StartMonitoring> for RepoActor {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
fn handle(&mut self, msg: StartMonitoring, ctx: &mut Self::Context) -> Self::Result {
|
fn handle(&mut self, msg: StartMonitoring, ctx: &mut Self::Context) -> Self::Result {
|
||||||
info!("Monitoring started");
|
info!("Monitoring started");
|
||||||
let next_ahead_of_main = msg.main != msg.next;
|
let Some(repo_config) = self.config.clone() else {
|
||||||
let dev_ahead_of_next = msg.next != msg.dev;
|
warn!("No config loaded");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let repo_details = self.details.clone();
|
let repo_details = self.details.clone();
|
||||||
let addr = ctx.address();
|
let addr = ctx.address();
|
||||||
let net = self.net.clone();
|
let net = self.net.clone();
|
||||||
|
|
||||||
|
let next_ahead_of_main = msg.main != msg.next;
|
||||||
|
let dev_ahead_of_next = msg.next != msg.dev;
|
||||||
if next_ahead_of_main {
|
if next_ahead_of_main {
|
||||||
status::check_next(msg.next, repo_details, addr, net)
|
status::check_next(msg.next, repo_details, addr, net)
|
||||||
.into_actor(self)
|
.into_actor(self)
|
||||||
.wait(ctx);
|
.wait(ctx);
|
||||||
} else if dev_ahead_of_next {
|
} else if dev_ahead_of_next {
|
||||||
branch::advance_next(msg.next, repo_details, addr, net)
|
branch::advance_next(
|
||||||
|
msg.next,
|
||||||
|
msg.dev_commit_history,
|
||||||
|
repo_details,
|
||||||
|
repo_config,
|
||||||
|
addr,
|
||||||
|
)
|
||||||
.into_actor(self)
|
.into_actor(self)
|
||||||
.wait(ctx);
|
.wait(ctx);
|
||||||
} else if self.webhook_id.is_none() {
|
} else if self.webhook_id.is_none() {
|
||||||
|
|
|
@ -34,9 +34,7 @@ pub async fn check_next(
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
#[allow(dead_code)] // TODO: (#13) remove this when we have results from the forge
|
|
||||||
Pass,
|
Pass,
|
||||||
#[allow(dead_code)] // TODO: (#13) remove this when we have results from the forge
|
|
||||||
Fail,
|
Fail,
|
||||||
Pending,
|
Pending,
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,14 @@ pub struct CommitHistories {
|
||||||
pub struct Commit {
|
pub struct Commit {
|
||||||
pub sha: String,
|
pub sha: String,
|
||||||
}
|
}
|
||||||
|
impl Commit {
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn new(sha: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
sha: sha.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Display for Commit {
|
impl Display for Commit {
|
||||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||||
write!(f, "{}", self.sha)
|
write!(f, "{}", self.sha)
|
||||||
|
|
Loading…
Reference in a new issue