mirror of
https://git.alemi.dev/tci.git
synced 2024-11-24 00:54:49 +01:00
112 lines
3.4 KiB
Rust
112 lines
3.4 KiB
Rust
|
use std::io::Read;
|
||
|
|
||
|
use crate::{config::{TciServerConfig, TciScriptConfig}, error::TciError, git::{shell_out, RefUpdate, RefUpdateVecHelper}};
|
||
|
|
||
|
lazy_static::lazy_static!{
|
||
|
static ref HOME : String = std::env::var("HOME").unwrap_or_default();
|
||
|
}
|
||
|
|
||
|
pub fn tci(cfg: TciServerConfig) -> Result<(), Box<dyn std::error::Error>> {
|
||
|
let repo_path = std::path::PathBuf::from(&std::env::var("GIT_DIR")?);
|
||
|
|
||
|
// check which branches are being updated
|
||
|
let mut input = String::new();
|
||
|
std::io::stdin().read_to_string(&mut input)?;
|
||
|
|
||
|
let updates : Vec<RefUpdate> = input.split('\n')
|
||
|
.filter_map(|l| {
|
||
|
let split : Vec<&str> = l.split(' ').collect();
|
||
|
Some(RefUpdate {
|
||
|
from: (*split.get(0)?).to_string(),
|
||
|
to: (*split.get(1)?).to_string(),
|
||
|
branch: (*split.get(2)?).to_string(),
|
||
|
})
|
||
|
})
|
||
|
.collect();
|
||
|
|
||
|
if let Some(branch) = cfg.branch {
|
||
|
if !updates.contains_branch(&branch) {
|
||
|
return Ok(()); // tci is not allowed to run on changes for this branch
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check config before even creating temp dir and cloning repo
|
||
|
let git_config = git2::Config::open(&repo_path.join("config"))?;
|
||
|
let tci_script = git_config.get_str("tci.script").unwrap_or(".tci").to_string();
|
||
|
|
||
|
// check if CI is allowed
|
||
|
if !cfg.allow_all
|
||
|
&& !cfg.run_setup_even_if_not_allowed
|
||
|
&& !git_config.get_bool("tci.allow").unwrap_or(false)
|
||
|
{
|
||
|
return Ok(()); // we are in whitelist mode and this repo is not whitelisted
|
||
|
}
|
||
|
|
||
|
// run hooks
|
||
|
for setup in cfg.setup {
|
||
|
println!("[+] setting up ({setup})");
|
||
|
shell_out(setup)?;
|
||
|
}
|
||
|
|
||
|
if !cfg.allow_all && !git_config.get_bool("tci.allow").unwrap_or(false) {
|
||
|
return Ok(()); // ewwww!!! ugly fix to allow running cgit update-agefile on every repo anyway
|
||
|
}
|
||
|
|
||
|
let res = tci_hook(&repo_path, &updates, tci_script);
|
||
|
|
||
|
for cleanup in cfg.cleanup {
|
||
|
println!("[-] cleaning up ({cleanup}) ");
|
||
|
shell_out(cleanup)?;
|
||
|
}
|
||
|
|
||
|
res?; // only check error AFTER running cleanup hooks
|
||
|
|
||
|
println!("[o] script run successfully");
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
pub fn tci_hook(repo_path: &std::path::Path, updates: &Vec<RefUpdate>, tci_script: String) -> Result<(), TciError> {
|
||
|
// TODO kind of ew but ehh should do its job
|
||
|
let mut name = repo_path.to_string_lossy()
|
||
|
.replace(HOME.as_str(), "");
|
||
|
if name.starts_with('/') {
|
||
|
name.remove(0);
|
||
|
}
|
||
|
if name.ends_with('/') {
|
||
|
name.remove(name.chars().count());
|
||
|
}
|
||
|
|
||
|
let tmp = tempdir::TempDir::new(&format!("tci-{}", name.replace('/', "_")))?;
|
||
|
|
||
|
// TODO allow customizing clone? just clone recursive? just let hook setup submodules?
|
||
|
git2::Repository::clone(
|
||
|
repo_path.to_str()
|
||
|
.ok_or(TciError::FsError("repo path is not a valid string"))?,
|
||
|
tmp.path(),
|
||
|
)?;
|
||
|
|
||
|
let tci_path = tmp.path().join(&tci_script);
|
||
|
let tci_config_path = tmp.path().join(tci_script + ".toml");
|
||
|
|
||
|
if tci_config_path.is_file() { // if .tci.toml is a config file, parse it for advanced CI options
|
||
|
let tci_config_raw = std::fs::read_to_string(tci_config_path)?;
|
||
|
let tci_config : TciScriptConfig = toml::from_str(&tci_config_raw)?;
|
||
|
if let Some(branch) = tci_config.branch {
|
||
|
if !updates.contains_branch(&branch) {
|
||
|
return Ok(()); // tci script should not be invoked for this branch
|
||
|
}
|
||
|
}
|
||
|
println!("[=] running tci pipeline for repo '{name}'");
|
||
|
Ok(())
|
||
|
} else if tci_path.is_file() { // if .tci is just one script, simply run it
|
||
|
println!("[=] running tci script for repo '{name}'");
|
||
|
std::env::set_current_dir(tmp.path())?;
|
||
|
let res = shell_out(tci_path);
|
||
|
std::env::set_current_dir(repo_path)?;
|
||
|
res
|
||
|
} else {
|
||
|
return Err(TciError::MissingScript);
|
||
|
}
|
||
|
}
|