fix: merge local-only git remote PR #739
This commit is contained in:
@@ -3,6 +3,7 @@ use std::path::Path;
|
||||
use std::process::Output;
|
||||
|
||||
use super::credentials::request_remote_credentials;
|
||||
use super::remote_config::{configure_origin_remote, list_configured_remotes};
|
||||
use super::{ensure_author_config, git_command};
|
||||
|
||||
const DEFAULT_REMOTE_NAME: &str = "origin";
|
||||
@@ -105,7 +106,7 @@ pub fn git_add_remote(vault_path: &str, remote_url: &str) -> Result<GitAddRemote
|
||||
let connection = RemoteConnection::new(branch);
|
||||
|
||||
let trimmed_url = remote_url.trim();
|
||||
run_git(vault, &["remote", "add", DEFAULT_REMOTE_NAME, trimmed_url])?;
|
||||
configure_origin_remote(vault, trimmed_url)?;
|
||||
request_remote_credentials(vault, trimmed_url);
|
||||
|
||||
let result = finish_remote_connection(vault, &connection);
|
||||
@@ -186,13 +187,7 @@ fn current_branch(vault: &Path) -> Result<String, String> {
|
||||
}
|
||||
|
||||
fn list_remotes(vault: &Path) -> Result<Vec<String>, String> {
|
||||
let output = git_output(vault, &["remote"])?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(command_error("git remote", &output));
|
||||
}
|
||||
|
||||
Ok(stdout_lines(&output))
|
||||
list_configured_remotes(vault)
|
||||
}
|
||||
|
||||
fn unset_upstream(vault: &Path) {
|
||||
|
||||
@@ -7,6 +7,7 @@ mod dates;
|
||||
mod history;
|
||||
mod pulse;
|
||||
mod remote;
|
||||
mod remote_config;
|
||||
mod status;
|
||||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
77
src-tauri/src/git/remote_config.rs
Normal file
77
src-tauri/src/git/remote_config.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use std::path::Path;
|
||||
use std::process::Output;
|
||||
|
||||
use super::git_command;
|
||||
|
||||
const DEFAULT_FETCH_REFSPEC: &str = "+refs/heads/*:refs/remotes/origin/*";
|
||||
const REMOTE_URL_CONFIG_PATTERN: &str = r"^remote\..*\.url$";
|
||||
const ORIGIN_URL_CONFIG_KEY: &str = "remote.origin.url";
|
||||
const ORIGIN_FETCH_CONFIG_KEY: &str = "remote.origin.fetch";
|
||||
|
||||
pub(super) fn list_configured_remotes(vault: &Path) -> Result<Vec<String>, String> {
|
||||
let output = git_command()
|
||||
.args(["config", "--get-regexp", REMOTE_URL_CONFIG_PATTERN])
|
||||
.current_dir(vault)
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to inspect git remotes: {e}"))?;
|
||||
|
||||
if output.status.code() == Some(1) {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
if !output.status.success() {
|
||||
return Err(command_error("git config --get-regexp", &output));
|
||||
}
|
||||
|
||||
Ok(stdout_lines(&output)
|
||||
.into_iter()
|
||||
.filter_map(|line| remote_name_from_url_config(&line))
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn remote_name_from_url_config(line: &str) -> Option<String> {
|
||||
let (key, value) = line.split_once(' ')?;
|
||||
if value.trim().is_empty() {
|
||||
return None;
|
||||
}
|
||||
key.strip_prefix("remote.")
|
||||
.and_then(|name| name.strip_suffix(".url"))
|
||||
.filter(|name| !name.is_empty())
|
||||
.map(ToString::to_string)
|
||||
}
|
||||
|
||||
pub(super) fn configure_origin_remote(vault: &Path, remote_url: &str) -> Result<(), String> {
|
||||
run_git_config(vault, ORIGIN_URL_CONFIG_KEY, remote_url)?;
|
||||
run_git_config(vault, ORIGIN_FETCH_CONFIG_KEY, DEFAULT_FETCH_REFSPEC)
|
||||
}
|
||||
|
||||
fn run_git_config(vault: &Path, key: &str, value: &str) -> Result<(), String> {
|
||||
let output = git_command()
|
||||
.args(["config", "--local", "--replace-all", key, value])
|
||||
.current_dir(vault)
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to run git config: {e}"))?;
|
||||
|
||||
if output.status.success() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(command_error("git config", &output))
|
||||
}
|
||||
|
||||
fn stdout_lines(output: &Output) -> Vec<String> {
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty())
|
||||
.map(ToString::to_string)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn command_error(command: &str, output: &Output) -> String {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
|
||||
if stderr.is_empty() {
|
||||
format!("{command} failed")
|
||||
} else {
|
||||
stderr
|
||||
}
|
||||
}
|
||||
59
src-tauri/tests/git_connect_no_remote.rs
Normal file
59
src-tauri/tests/git_connect_no_remote.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use tempfile::TempDir;
|
||||
use tolaria_lib::git::{git_add_remote, git_commit, git_remote_status};
|
||||
|
||||
fn run_git(path: &Path, args: &[&str]) {
|
||||
let output = Command::new("git")
|
||||
.args(args)
|
||||
.current_dir(path)
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"git {:?} failed: {}",
|
||||
args,
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
fn setup_repo() -> TempDir {
|
||||
let dir = TempDir::new().unwrap();
|
||||
run_git(dir.path(), &["init", "-b", "main"]);
|
||||
dir
|
||||
}
|
||||
|
||||
fn setup_bare_repo() -> TempDir {
|
||||
let dir = TempDir::new().unwrap();
|
||||
run_git(dir.path(), &["init", "--bare"]);
|
||||
dir
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn git_add_remote_ignores_name_only_origin_config() {
|
||||
let local = setup_repo();
|
||||
fs::write(local.path().join("note.md"), "# Note\n").unwrap();
|
||||
git_commit(local.path().to_str().unwrap(), "initial").unwrap();
|
||||
|
||||
run_git(local.path(), &["config", "remote.origin.prune", "true"]);
|
||||
let remote_names = Command::new("git")
|
||||
.args(["remote"])
|
||||
.current_dir(local.path())
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(String::from_utf8_lossy(&remote_names.stdout).contains("origin"));
|
||||
|
||||
let bare = setup_bare_repo();
|
||||
let result = git_add_remote(
|
||||
local.path().to_str().unwrap(),
|
||||
bare.path().to_str().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.status, "connected");
|
||||
assert!(git_remote_status(local.path().to_str().unwrap())
|
||||
.unwrap()
|
||||
.has_remote);
|
||||
}
|
||||
Reference in New Issue
Block a user