🐞 fix: Even more git fixes
Some checks failed
CI / Backend (Rust) (push) Failing after 9s
CI / Frontend (Vue) (push) Successful in 9m57s

This commit is contained in:
Keith Solomon
2026-02-25 08:05:02 -06:00
parent 2a55d5ebec
commit f1f106c948
5 changed files with 110 additions and 19 deletions

View File

@@ -1,4 +1,5 @@
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Duration;
use chrono::Utc;
@@ -196,6 +197,72 @@ fn remote_callbacks() -> git2::RemoteCallbacks<'static> {
callbacks
}
fn use_git_cli_fallback() -> bool {
std::env::var("IRONPAD_GIT_USE_CLI_FALLBACK")
.map(|v| !matches!(v.to_ascii_lowercase().as_str(), "0" | "false" | "no" | "off"))
.unwrap_or(true)
}
fn known_hosts_path() -> Option<PathBuf> {
if let Ok(path) = std::env::var("IRONPAD_GIT_SSH_KNOWN_HOSTS") {
let p = PathBuf::from(path);
if p.exists() {
return Some(p);
}
}
let default = PathBuf::from("/root/.ssh/known_hosts");
if default.exists() {
Some(default)
} else {
None
}
}
fn git_ssh_command(auth: &GitAuthConfig) -> Option<String> {
let private_key = auth.private_key.as_ref()?;
let mut cmd = format!(
"ssh -i {} -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes",
private_key.display()
);
if let Some(known_hosts) = known_hosts_path() {
cmd.push_str(&format!(" -o UserKnownHostsFile={}", known_hosts.display()));
}
Some(cmd)
}
fn run_git_cli(args: &[&str]) -> Result<(), String> {
let auth = git_auth_config();
let data_path = config::data_dir();
let mut cmd = Command::new("git");
cmd.args(args)
.current_dir(data_path)
.env("GIT_TERMINAL_PROMPT", "0");
if let Some(ssh_cmd) = git_ssh_command(&auth) {
cmd.env("GIT_SSH_COMMAND", ssh_cmd);
}
let output = cmd
.output()
.map_err(|e| format!("Failed to run git CLI: {}", e))?;
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
let msg = if !stderr.is_empty() { stderr } else { stdout };
Err(format!(
"git {} failed (exit {}): {}",
args.join(" "),
output.status.code().unwrap_or(-1),
msg
))
}
}
/// Get repository status
pub fn get_status() -> Result<RepoStatus, String> {
let data_path = config::data_dir();
@@ -423,12 +490,27 @@ pub fn push_to_remote() -> Result<(), String> {
// Push the current branch
let refspec = format!("refs/heads/{}:refs/heads/{}", branch_name, branch_name);
remote
.push(&[&refspec], Some(&mut push_options))
.map_err(|e| format!("Push failed: {}. Make sure SSH keys are configured.", e))?;
tracing::info!("Successfully pushed to origin/{}", branch_name);
Ok(())
match remote.push(&[&refspec], Some(&mut push_options)) {
Ok(_) => {
tracing::info!("Successfully pushed to origin/{}", branch_name);
Ok(())
}
Err(e) => {
let err_text = e.to_string();
if !use_git_cli_fallback() {
return Err(format!(
"Push failed: {}. Make sure SSH keys are configured.",
err_text
));
}
tracing::warn!("libgit2 push failed, trying git CLI fallback: {}", err_text);
run_git_cli(&["push", "origin", branch_name]).map_err(|cli_err| {
format!("Push failed: {} (libgit2) / {} (git CLI)", err_text, cli_err)
})?;
tracing::info!("Successfully pushed to origin/{} (git CLI fallback)", branch_name);
Ok(())
}
}
}
/// Check if remote is configured
@@ -850,18 +932,20 @@ pub fn fetch_from_remote() -> Result<(), String> {
.find_remote("origin")
.map_err(|e| format!("Remote 'origin' not found: {}", e))?;
// Create callbacks for authentication
let mut callbacks = git2::RemoteCallbacks::new();
callbacks.credentials(|_url, username_from_url, _allowed_types| {
git2::Cred::ssh_key_from_agent(username_from_url.unwrap_or("git"))
});
let mut fetch_options = git2::FetchOptions::new();
fetch_options.remote_callbacks(callbacks);
fetch_options.remote_callbacks(remote_callbacks());
remote
.fetch(&[] as &[&str], Some(&mut fetch_options), None)
.map_err(|e| format!("Fetch failed: {}", e))?;
Ok(())
match remote.fetch(&[] as &[&str], Some(&mut fetch_options), None) {
Ok(_) => Ok(()),
Err(e) => {
let err_text = e.to_string();
if !use_git_cli_fallback() {
return Err(format!("Fetch failed: {}", err_text));
}
tracing::warn!("libgit2 fetch failed, trying git CLI fallback: {}", err_text);
run_git_cli(&["fetch", "origin", "--prune"]).map_err(|cli_err| {
format!("Fetch failed: {} (libgit2) / {} (git CLI)", err_text, cli_err)
})
}
}
}