From d28e051ecddee3aa45452094da63dc48495cb06f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 10 May 2026 17:12:24 +0000 Subject: [PATCH] fix(native): suppress git hooks during apply cancel Co-authored-by: cooper --- apps/native/src-tauri/src/commands/apply.rs | 62 +++++---------------- apps/native/src-tauri/src/git/exec.rs | 43 +++++++++++++- apps/native/src-tauri/src/git/mod.rs | 2 +- 3 files changed, 55 insertions(+), 52 deletions(-) diff --git a/apps/native/src-tauri/src/commands/apply.rs b/apps/native/src-tauri/src/commands/apply.rs index 09049eda6..2dc42e63c 100644 --- a/apps/native/src-tauri/src/commands/apply.rs +++ b/apps/native/src-tauri/src/commands/apply.rs @@ -1,9 +1,9 @@ use super::helpers::capture_err; use crate::bootstrap::default_config; +use crate::git; use crate::storage::store; use crate::system::nix; use crate::{rebuild, shared_types}; -use std::process::Command; use tauri::AppHandle; /// Starts a streaming darwin-rebuild switch operation. @@ -60,60 +60,24 @@ pub async fn darwin_apply_stream_cancel(app: AppHandle) -> Result GitCommand { +fn base_git_command() -> Command { let mut cmd = Command::new("git"); cmd.env("PATH", crate::system::nix::get_nix_path()); cmd.args([ @@ -54,7 +54,21 @@ fn git_command() -> GitCommand { "-c", "core.hooksPath=/dev/null", ]); - GitCommand(cmd) + cmd +} + +fn git_command() -> GitCommand { + GitCommand(base_git_command()) +} + +/// Runs a git command with nixmac's fixed identity and hook suppression. +pub fn run_command(dir: P, args: I) -> Result +where + I: IntoIterator, + S: AsRef, + P: AsRef, +{ + git_command().args(args).current_dir(dir).output() } /// Checks if a directory is inside a git repository. @@ -649,6 +663,31 @@ mod tests { assert!(is_repo(&repo_dir.to_string_lossy())); } + #[cfg(unix)] + #[test] + fn test_run_command_disables_repo_hooks() { + use std::os::unix::fs::PermissionsExt; + + let temp_dir = TempDir::new().unwrap(); + let repo_dir = temp_dir.path().join("repo"); + init_repo(&repo_dir.to_string_lossy()).unwrap(); + + let hook_path = repo_dir.join(".git/hooks/pre-commit"); + fs::write(&hook_path, "#!/bin/sh\nprintf ran > hook-ran\nexit 1\n").unwrap(); + let mut permissions = fs::metadata(&hook_path).unwrap().permissions(); + permissions.set_mode(0o755); + fs::set_permissions(&hook_path, permissions).unwrap(); + + fs::write(repo_dir.join("flake.nix"), "{ }").unwrap(); + run_command(&repo_dir, ["add", "-A"]).unwrap(); + run_command(&repo_dir, ["commit", "-m", "initial commit"]).unwrap(); + + assert!( + !repo_dir.join("hook-ran").exists(), + "repo hooks must not run from nixmac git commands" + ); + } + #[test] fn test_status() { let temp_dir = TempDir::new().unwrap(); diff --git a/apps/native/src-tauri/src/git/mod.rs b/apps/native/src-tauri/src/git/mod.rs index b5bc769cd..2881b7ec2 100644 --- a/apps/native/src-tauri/src/git/mod.rs +++ b/apps/native/src-tauri/src/git/mod.rs @@ -10,5 +10,5 @@ pub use exec::{ cache_status, cached, checkout_files_at_commit, commit_all, commit_diff, create_evolution_backup, current_branch, delete_backup_branch, get_full_diff, get_nix_diff, get_ref_sha, init_repo, intent_add_untracked, is_repo, log, read_tags, restore_all, - restore_from_branch_ref, stash, status, status_and_cache, tag_commit, CommitInfo, + restore_from_branch_ref, run_command, stash, status, status_and_cache, tag_commit, CommitInfo, };