Files
komodo/lib/git/src/clone.rs
2026-06-14 16:35:05 -04:00

126 lines
2.9 KiB
Rust

use std::{io::ErrorKind, path::Path};
use anyhow::Context;
use command::{CommandOptions, run_komodo_standard_command};
use formatting::format_serror;
use komodo_client::entities::{
RepoExecutionArgs, RepoExecutionResponse, all_logs_success,
update::Log,
};
use crate::{check_installed, get_commit_hash_log};
/// Will delete the existing repo folder,
/// clone the repo, get the latest hash / message,
/// and run on_clone / on_pull.
///
/// Assumes all interpolation is already done and takes the list of replacers
/// for the On Clone command.
pub async fn clone<T>(
clone_args: T,
root_repo_dir: &Path,
access_token: Option<String>,
) -> anyhow::Result<RepoExecutionResponse>
where
T: Into<RepoExecutionArgs> + std::fmt::Debug,
{
check_installed().await?;
let args: RepoExecutionArgs = clone_args.into();
let repo_url = args.remote_url(access_token.as_deref())?;
let mut res = RepoExecutionResponse {
path: args.path(root_repo_dir),
logs: Vec::new(),
commit_hash: None,
commit_message: None,
};
// Ensure parent folder exists
if let Some(parent) = res.path.parent()
&& let Err(e) = tokio::fs::create_dir_all(parent)
.await
.context("Failed to create clone parent directory.")
{
res.logs.push(Log::error(
"Prepare Repo Root",
format_serror(&e.into()),
));
return Ok(res);
}
match tokio::fs::remove_dir_all(&res.path).await {
Err(e) if e.kind() != ErrorKind::NotFound => {
let e: anyhow::Error = e.into();
res.logs.push(Log::error(
"Clean Repo Root",
format_serror(
&e.context(
"Failed to remove existing repo root before clone.",
)
.into(),
),
));
return Ok(res);
}
_ => {}
}
let command = format!(
"git clone {repo_url} {} -b {}",
res.path.display(),
args.branch
);
let mut log = run_komodo_standard_command(
"Clone Repo",
command,
CommandOptions::default(),
)
.await;
if let Some(token) = access_token {
log.command = log.command.replace(&token, "<TOKEN>");
log.stdout = log.stdout.replace(&token, "<TOKEN>");
log.stderr = log.stderr.replace(&token, "<TOKEN>");
}
res.logs.push(log);
if !all_logs_success(&res.logs) {
return Ok(res);
}
if let Some(commit) = args.commit {
let reset_log = run_komodo_standard_command(
"set commit",
format!("git reset --hard {commit}",),
CommandOptions::default().path(res.path.as_path()),
)
.await;
res.logs.push(reset_log);
}
if !all_logs_success(&res.logs) {
return Ok(res);
}
match get_commit_hash_log(&res.path)
.await
.context("Failed to get latest commit")
{
Ok((log, hash, message)) => {
res.logs.push(log);
res.commit_hash = Some(hash);
res.commit_message = Some(message);
}
Err(e) => {
res
.logs
.push(Log::simple("Latest Commit", format_serror(&e.into())));
}
};
Ok(res)
}