From aab618018ab2bc01d0d459b2be68e4c703065862 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Thu, 30 Apr 2026 10:41:53 +1000 Subject: [PATCH 1/6] fix: hide reviews for missing commits Filter branch timeline reviews to SHAs that are still visible in git history and cover reset-away commits with a unit test. Signed-off-by: Matt Toohey --- apps/staged/src-tauri/src/timeline.rs | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/apps/staged/src-tauri/src/timeline.rs b/apps/staged/src-tauri/src/timeline.rs index 5ccb505d..246004dd 100644 --- a/apps/staged/src-tauri/src/timeline.rs +++ b/apps/staged/src-tauri/src/timeline.rs @@ -7,6 +7,7 @@ use crate::{ blox, branches, BranchTimeline, CommitTimelineItem, ImageTimelineItem, NoteTimelineItem, ReviewTimelineItem, }; +use std::collections::HashSet; use std::path::Path; use std::sync::{Arc, Mutex}; @@ -146,6 +147,12 @@ fn build_branch_timeline(store: &Arc, branch_id: &str) -> Result = commits + .iter() + .filter(|c| !c.sha.is_empty()) + .map(|c| c.sha.as_str()) + .collect(); + // Get notes let db_notes = store .list_notes_for_branch(branch_id) @@ -175,6 +182,7 @@ fn build_branch_timeline(store: &Arc, branch_id: &str) -> Result = db_reviews .into_iter() + .filter(|r| visible_shas.contains(r.commit_sha.as_str())) .map(|r| { let resolved = store.resolve_session_status(r.session_id.as_deref()); let comment_count = r.comments.len(); @@ -447,3 +455,103 @@ pub async fn delete_commit( .await .map_err(|e| format!("Delete task failed: {e}"))? } + +#[cfg(test)] +mod tests { + use super::*; + use crate::store::models::{Branch, Project, Review, ReviewScope, Workdir}; + use std::fs; + use std::path::{Path, PathBuf}; + use std::process::Command; + use uuid::Uuid; + + struct TempGitRepo { + path: PathBuf, + } + + impl TempGitRepo { + fn new() -> Self { + let path = std::env::temp_dir().join(format!("staged-timeline-{}", Uuid::new_v4())); + fs::create_dir_all(&path).unwrap(); + + let repo = Self { path }; + repo.run_git(&["init"]); + repo.run_git(&["checkout", "-b", "main"]); + repo.run_git(&["config", "user.email", "test@example.com"]); + repo.run_git(&["config", "user.name", "Timeline Test"]); + repo + } + + fn path(&self) -> &Path { + &self.path + } + + fn write_file(&self, name: &str, content: &str) { + fs::write(self.path.join(name), content).unwrap(); + } + + fn commit(&self, message: &str) -> String { + self.run_git(&["add", "."]); + self.run_git(&["commit", "-m", message]); + self.run_git(&["rev-parse", "HEAD"]).trim().to_string() + } + + fn run_git(&self, args: &[&str]) -> String { + let output = Command::new("git") + .arg("-C") + .arg(&self.path) + .args(args) + .output() + .unwrap(); + + assert!( + output.status.success(), + "git {:?} failed: {}", + args, + String::from_utf8_lossy(&output.stderr) + ); + + String::from_utf8(output.stdout).unwrap() + } + } + + impl Drop for TempGitRepo { + fn drop(&mut self) { + let _ = fs::remove_dir_all(&self.path); + } + } + + #[test] + fn build_branch_timeline_hides_reviews_for_commits_missing_from_git_history() { + let repo = TempGitRepo::new(); + repo.write_file("file.txt", "base\n"); + repo.commit("base"); + repo.run_git(&["checkout", "-b", "feature"]); + repo.write_file("file.txt", "base\nvisible\n"); + let visible_sha = repo.commit("visible change"); + repo.write_file("file.txt", "base\nvisible\nstale\n"); + let stale_sha = repo.commit("stale change"); + repo.run_git(&["reset", "--hard", &visible_sha]); + + let store = Arc::new(Store::in_memory().unwrap()); + let project = Project::new("test-owner/test-repo"); + store.create_project(&project).unwrap(); + let branch = Branch::new(&project.id, "feature", "main"); + store.create_branch(&branch).unwrap(); + let workdir = + Workdir::new(&project.id, repo.path().to_str().unwrap()).with_branch(&branch.id); + store.create_workdir(&workdir).unwrap(); + + let visible_review = Review::new(&branch.id, &visible_sha, ReviewScope::Commit); + let stale_review = Review::new(&branch.id, &stale_sha, ReviewScope::Commit); + store.create_review(&visible_review).unwrap(); + store.create_review(&stale_review).unwrap(); + + let timeline = build_branch_timeline(&store, &branch.id).unwrap(); + + assert_eq!(timeline.commits.len(), 1); + assert_eq!(timeline.commits[0].sha, visible_sha); + assert_eq!(timeline.reviews.len(), 1); + assert_eq!(timeline.reviews[0].id, visible_review.id); + } +} From 8d652e5fddf359d61d0c77767a2be149a3f3d9a5 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Thu, 30 Apr 2026 12:05:38 +1000 Subject: [PATCH 2/6] fix: allow in-progress reviews and improve test robustness - Allow reviews with empty commit_sha through the visibility filter so in-progress branch reviews (not yet associated with a commit) are not hidden from the timeline. - Use 'git init --initial-branch=main' in test helper instead of separate init + checkout to be explicit about the default branch name regardless of system git configuration. Signed-off-by: Matt Toohey --- apps/staged/src-tauri/src/timeline.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/staged/src-tauri/src/timeline.rs b/apps/staged/src-tauri/src/timeline.rs index 246004dd..69f8d77d 100644 --- a/apps/staged/src-tauri/src/timeline.rs +++ b/apps/staged/src-tauri/src/timeline.rs @@ -182,7 +182,7 @@ fn build_branch_timeline(store: &Arc, branch_id: &str) -> Result = db_reviews .into_iter() - .filter(|r| visible_shas.contains(r.commit_sha.as_str())) + .filter(|r| r.commit_sha.is_empty() || visible_shas.contains(r.commit_sha.as_str())) .map(|r| { let resolved = store.resolve_session_status(r.session_id.as_deref()); let comment_count = r.comments.len(); @@ -475,8 +475,7 @@ mod tests { fs::create_dir_all(&path).unwrap(); let repo = Self { path }; - repo.run_git(&["init"]); - repo.run_git(&["checkout", "-b", "main"]); + repo.run_git(&["init", "--initial-branch=main"]); repo.run_git(&["config", "user.email", "test@example.com"]); repo.run_git(&["config", "user.name", "Timeline Test"]); repo From d1c13f3b28608357212617d5e12ff1a0042b1c40 Mon Sep 17 00:00:00 2001 From: Test User Date: Mon, 4 May 2026 14:51:40 +1000 Subject: [PATCH 3/6] refactor: extract TempGitRepo test helper into shared test_utils module Move the TempGitRepo helper from timeline.rs tests into a dedicated src/test_utils.rs module so it can be reused by future test modules without duplication. Signed-off-by: Matt Toohey --- apps/staged/src-tauri/src/lib.rs | 3 ++ apps/staged/src-tauri/src/test_utils.rs | 62 +++++++++++++++++++++++++ apps/staged/src-tauri/src/timeline.rs | 60 +----------------------- 3 files changed, 66 insertions(+), 59 deletions(-) create mode 100644 apps/staged/src-tauri/src/test_utils.rs diff --git a/apps/staged/src-tauri/src/lib.rs b/apps/staged/src-tauri/src/lib.rs index 766aaeac..7d3d3ff3 100644 --- a/apps/staged/src-tauri/src/lib.rs +++ b/apps/staged/src-tauri/src/lib.rs @@ -26,6 +26,9 @@ pub(crate) mod terminal_output; pub mod timeline; pub mod util_commands; +#[cfg(test)] +pub mod test_utils; + use serde::Serialize; use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/apps/staged/src-tauri/src/test_utils.rs b/apps/staged/src-tauri/src/test_utils.rs new file mode 100644 index 00000000..54f80a8f --- /dev/null +++ b/apps/staged/src-tauri/src/test_utils.rs @@ -0,0 +1,62 @@ +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; +use uuid::Uuid; + +/// A temporary git repository for use in tests. +/// +/// Creates a fresh git repo in a temp directory and cleans it up on drop. +pub struct TempGitRepo { + path: PathBuf, +} + +impl TempGitRepo { + pub fn new() -> Self { + let path = std::env::temp_dir().join(format!("staged-test-{}", Uuid::new_v4())); + fs::create_dir_all(&path).unwrap(); + + let repo = Self { path }; + repo.run_git(&["init", "--initial-branch=main"]); + repo.run_git(&["config", "user.email", "test@example.com"]); + repo.run_git(&["config", "user.name", "Test"]); + repo + } + + pub fn path(&self) -> &Path { + &self.path + } + + pub fn write_file(&self, name: &str, content: &str) { + fs::write(self.path.join(name), content).unwrap(); + } + + pub fn commit(&self, message: &str) -> String { + self.run_git(&["add", "."]); + self.run_git(&["commit", "-m", message]); + self.run_git(&["rev-parse", "HEAD"]).trim().to_string() + } + + pub fn run_git(&self, args: &[&str]) -> String { + let output = Command::new("git") + .arg("-C") + .arg(&self.path) + .args(args) + .output() + .unwrap(); + + assert!( + output.status.success(), + "git {:?} failed: {}", + args, + String::from_utf8_lossy(&output.stderr) + ); + + String::from_utf8(output.stdout).unwrap() + } +} + +impl Drop for TempGitRepo { + fn drop(&mut self) { + let _ = fs::remove_dir_all(&self.path); + } +} diff --git a/apps/staged/src-tauri/src/timeline.rs b/apps/staged/src-tauri/src/timeline.rs index 69f8d77d..6c11ff1e 100644 --- a/apps/staged/src-tauri/src/timeline.rs +++ b/apps/staged/src-tauri/src/timeline.rs @@ -460,65 +460,7 @@ pub async fn delete_commit( mod tests { use super::*; use crate::store::models::{Branch, Project, Review, ReviewScope, Workdir}; - use std::fs; - use std::path::{Path, PathBuf}; - use std::process::Command; - use uuid::Uuid; - - struct TempGitRepo { - path: PathBuf, - } - - impl TempGitRepo { - fn new() -> Self { - let path = std::env::temp_dir().join(format!("staged-timeline-{}", Uuid::new_v4())); - fs::create_dir_all(&path).unwrap(); - - let repo = Self { path }; - repo.run_git(&["init", "--initial-branch=main"]); - repo.run_git(&["config", "user.email", "test@example.com"]); - repo.run_git(&["config", "user.name", "Timeline Test"]); - repo - } - - fn path(&self) -> &Path { - &self.path - } - - fn write_file(&self, name: &str, content: &str) { - fs::write(self.path.join(name), content).unwrap(); - } - - fn commit(&self, message: &str) -> String { - self.run_git(&["add", "."]); - self.run_git(&["commit", "-m", message]); - self.run_git(&["rev-parse", "HEAD"]).trim().to_string() - } - - fn run_git(&self, args: &[&str]) -> String { - let output = Command::new("git") - .arg("-C") - .arg(&self.path) - .args(args) - .output() - .unwrap(); - - assert!( - output.status.success(), - "git {:?} failed: {}", - args, - String::from_utf8_lossy(&output.stderr) - ); - - String::from_utf8(output.stdout).unwrap() - } - } - - impl Drop for TempGitRepo { - fn drop(&mut self) { - let _ = fs::remove_dir_all(&self.path); - } - } + use crate::test_utils::TempGitRepo; #[test] fn build_branch_timeline_hides_reviews_for_commits_missing_from_git_history() { From 82657ed9aa6e7c9974a7eeb6df2944006e08a50b Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Tue, 5 May 2026 14:26:14 +1000 Subject: [PATCH 4/6] fix: keep user-commented stale reviews visible Allow branch timeline visibility to retain stale reviews when their loaded active comments include a user-authored comment. Keep stale empty reviews, agent-only reviews, and reviews with only deleted user comments hidden, and cover those cases in timeline tests. Signed-off-by: Matt Toohey --- apps/staged/src-tauri/src/timeline.rs | 84 +++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 5 deletions(-) diff --git a/apps/staged/src-tauri/src/timeline.rs b/apps/staged/src-tauri/src/timeline.rs index 6c11ff1e..f995d6b2 100644 --- a/apps/staged/src-tauri/src/timeline.rs +++ b/apps/staged/src-tauri/src/timeline.rs @@ -2,7 +2,7 @@ use crate::git; use crate::session_runner; -use crate::store::Store; +use crate::store::{CommentAuthor, Review, Store}; use crate::{ blox, branches, BranchTimeline, CommitTimelineItem, ImageTimelineItem, NoteTimelineItem, ReviewTimelineItem, @@ -182,7 +182,7 @@ fn build_branch_timeline(store: &Arc, branch_id: &str) -> Result = db_reviews .into_iter() - .filter(|r| r.commit_sha.is_empty() || visible_shas.contains(r.commit_sha.as_str())) + .filter(|r| review_is_visible_in_timeline(r, &visible_shas)) .map(|r| { let resolved = store.resolve_session_status(r.session_id.as_deref()); let comment_count = r.comments.len(); @@ -233,6 +233,15 @@ fn build_branch_timeline(store: &Arc, branch_id: &str) -> Result) -> bool { + review.commit_sha.is_empty() + || visible_shas.contains(review.commit_sha.as_str()) + || review + .comments + .iter() + .any(|comment| comment.author == CommentAuthor::User) +} + #[tauri::command] pub async fn get_branch_timeline( store: tauri::State<'_, Mutex>>>, @@ -459,14 +468,15 @@ pub async fn delete_commit( #[cfg(test)] mod tests { use super::*; - use crate::store::models::{Branch, Project, Review, ReviewScope, Workdir}; + use crate::git::Span; + use crate::store::models::{Branch, Comment, Project, ReviewScope, Workdir}; use crate::test_utils::TempGitRepo; - #[test] - fn build_branch_timeline_hides_reviews_for_commits_missing_from_git_history() { + fn repo_with_visible_and_stale_commit() -> (TempGitRepo, String, String) { let repo = TempGitRepo::new(); repo.write_file("file.txt", "base\n"); repo.commit("base"); + repo.run_git(&["update-ref", "refs/remotes/origin/main", "main"]); repo.run_git(&["checkout", "-b", "feature"]); repo.write_file("file.txt", "base\nvisible\n"); let visible_sha = repo.commit("visible change"); @@ -474,6 +484,10 @@ mod tests { let stale_sha = repo.commit("stale change"); repo.run_git(&["reset", "--hard", &visible_sha]); + (repo, visible_sha, stale_sha) + } + + fn store_with_branch(repo: &TempGitRepo) -> (Arc, Branch) { let store = Arc::new(Store::in_memory().unwrap()); let project = Project::new("test-owner/test-repo"); store.create_project(&project).unwrap(); @@ -483,6 +497,14 @@ mod tests { Workdir::new(&project.id, repo.path().to_str().unwrap()).with_branch(&branch.id); store.create_workdir(&workdir).unwrap(); + (store, branch) + } + + #[test] + fn build_branch_timeline_hides_reviews_for_commits_missing_from_git_history() { + let (repo, visible_sha, stale_sha) = repo_with_visible_and_stale_commit(); + let (store, branch) = store_with_branch(&repo); + let visible_review = Review::new(&branch.id, &visible_sha, ReviewScope::Commit); let stale_review = Review::new(&branch.id, &stale_sha, ReviewScope::Commit); store.create_review(&visible_review).unwrap(); @@ -495,4 +517,56 @@ mod tests { assert_eq!(timeline.reviews.len(), 1); assert_eq!(timeline.reviews[0].id, visible_review.id); } + + #[test] + fn build_branch_timeline_hides_stale_reviews_with_only_agent_comments() { + let (repo, _visible_sha, stale_sha) = repo_with_visible_and_stale_commit(); + let (store, branch) = store_with_branch(&repo); + + let stale_review = Review::new(&branch.id, &stale_sha, ReviewScope::Commit); + let agent_comment = Comment::new("file.txt", Span::new(2, 3), "Agent note") + .with_author(CommentAuthor::Agent); + store.create_review(&stale_review).unwrap(); + store.add_comment(&stale_review.id, &agent_comment).unwrap(); + + let timeline = build_branch_timeline(&store, &branch.id).unwrap(); + + assert_eq!(timeline.commits.len(), 1); + assert!(timeline.reviews.is_empty()); + } + + #[test] + fn build_branch_timeline_keeps_stale_reviews_with_user_comments() { + let (repo, _visible_sha, stale_sha) = repo_with_visible_and_stale_commit(); + let (store, branch) = store_with_branch(&repo); + + let stale_review = Review::new(&branch.id, &stale_sha, ReviewScope::Commit); + let user_comment = Comment::new("file.txt", Span::new(2, 3), "Please follow up"); + store.create_review(&stale_review).unwrap(); + store.add_comment(&stale_review.id, &user_comment).unwrap(); + + let timeline = build_branch_timeline(&store, &branch.id).unwrap(); + + assert_eq!(timeline.commits.len(), 1); + assert_eq!(timeline.reviews.len(), 1); + assert_eq!(timeline.reviews[0].id, stale_review.id); + assert_eq!(timeline.reviews[0].comment_count, 1); + } + + #[test] + fn build_branch_timeline_hides_stale_reviews_with_deleted_user_comments() { + let (repo, _visible_sha, stale_sha) = repo_with_visible_and_stale_commit(); + let (store, branch) = store_with_branch(&repo); + + let stale_review = Review::new(&branch.id, &stale_sha, ReviewScope::Commit); + let user_comment = Comment::new("file.txt", Span::new(2, 3), "Please follow up"); + store.create_review(&stale_review).unwrap(); + store.add_comment(&stale_review.id, &user_comment).unwrap(); + store.delete_comment(&user_comment.id).unwrap(); + + let timeline = build_branch_timeline(&store, &branch.id).unwrap(); + + assert_eq!(timeline.commits.len(), 1); + assert!(timeline.reviews.is_empty()); + } } From a0ef349848a3e4baf2648418c3900a3d4ffbba85 Mon Sep 17 00:00:00 2001 From: Test Date: Tue, 5 May 2026 14:53:17 +1000 Subject: [PATCH 5/6] test: isolate TempGitRepo git commands Signed-off-by: Test --- apps/staged/src-tauri/src/test_utils.rs | 32 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/staged/src-tauri/src/test_utils.rs b/apps/staged/src-tauri/src/test_utils.rs index 54f80a8f..50cbd0d3 100644 --- a/apps/staged/src-tauri/src/test_utils.rs +++ b/apps/staged/src-tauri/src/test_utils.rs @@ -3,6 +3,24 @@ use std::path::{Path, PathBuf}; use std::process::Command; use uuid::Uuid; +const GIT_LOCAL_ENV_VARS: &[&str] = &[ + "GIT_ALTERNATE_OBJECT_DIRECTORIES", + "GIT_CONFIG", + "GIT_CONFIG_PARAMETERS", + "GIT_CONFIG_COUNT", + "GIT_OBJECT_DIRECTORY", + "GIT_DIR", + "GIT_WORK_TREE", + "GIT_IMPLICIT_WORK_TREE", + "GIT_GRAFT_FILE", + "GIT_INDEX_FILE", + "GIT_NO_REPLACE_OBJECTS", + "GIT_REPLACE_REF_BASE", + "GIT_PREFIX", + "GIT_SHALLOW_FILE", + "GIT_COMMON_DIR", +]; + /// A temporary git repository for use in tests. /// /// Creates a fresh git repo in a temp directory and cleans it up on drop. @@ -37,12 +55,18 @@ impl TempGitRepo { } pub fn run_git(&self, args: &[&str]) -> String { - let output = Command::new("git") + let mut command = Command::new("git"); + command + .arg("-c") + .arg("core.hooksPath=/dev/null") .arg("-C") .arg(&self.path) - .args(args) - .output() - .unwrap(); + .args(args); + for key in GIT_LOCAL_ENV_VARS { + command.env_remove(key); + } + + let output = command.output().unwrap(); assert!( output.status.success(), From 5831e27a174d0ef2db1779b2144176402248332f Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Tue, 5 May 2026 15:05:01 +1000 Subject: [PATCH 6/6] fix: strip inherited git env dynamically Extract a shared helper that removes every inherited GIT_* variable before running git and use it from the CLI and test git helpers. Signed-off-by: Matt Toohey --- apps/staged/src-tauri/src/git/cli.rs | 24 +++------------------ apps/staged/src-tauri/src/git/env.rs | 15 +++++++++++++ apps/staged/src-tauri/src/git/mod.rs | 2 ++ apps/staged/src-tauri/src/session_runner.rs | 21 ++---------------- apps/staged/src-tauri/src/test_utils.rs | 22 ++----------------- 5 files changed, 24 insertions(+), 60 deletions(-) create mode 100644 apps/staged/src-tauri/src/git/env.rs diff --git a/apps/staged/src-tauri/src/git/cli.rs b/apps/staged/src-tauri/src/git/cli.rs index cb0566d3..761175e2 100644 --- a/apps/staged/src-tauri/src/git/cli.rs +++ b/apps/staged/src-tauri/src/git/cli.rs @@ -2,6 +2,8 @@ use std::path::Path; use std::process::Command; use thiserror::Error; +use super::strip_git_env; + #[derive(Error, Debug)] pub enum GitError { #[error("git not found - is git installed?")] @@ -20,24 +22,6 @@ pub enum GitError { InvalidPath(String), } -const GIT_LOCAL_ENV_VARS: &[&str] = &[ - "GIT_ALTERNATE_OBJECT_DIRECTORIES", - "GIT_CONFIG", - "GIT_CONFIG_PARAMETERS", - "GIT_CONFIG_COUNT", - "GIT_OBJECT_DIRECTORY", - "GIT_DIR", - "GIT_WORK_TREE", - "GIT_IMPLICIT_WORK_TREE", - "GIT_GRAFT_FILE", - "GIT_INDEX_FILE", - "GIT_NO_REPLACE_OBJECTS", - "GIT_REPLACE_REF_BASE", - "GIT_PREFIX", - "GIT_SHALLOW_FILE", - "GIT_COMMON_DIR", -]; - /// Run a git command and return stdout as a string pub fn run(repo: &Path, args: &[&str]) -> Result { let repo_str = repo @@ -46,9 +30,7 @@ pub fn run(repo: &Path, args: &[&str]) -> Result { let mut command = Command::new("git"); command.args(["-C", repo_str]).args(args); - for key in GIT_LOCAL_ENV_VARS { - command.env_remove(key); - } + strip_git_env(&mut command); let output = command.output().map_err(|e| { if e.kind() == std::io::ErrorKind::NotFound { diff --git a/apps/staged/src-tauri/src/git/env.rs b/apps/staged/src-tauri/src/git/env.rs new file mode 100644 index 00000000..7240dd6d --- /dev/null +++ b/apps/staged/src-tauri/src/git/env.rs @@ -0,0 +1,15 @@ +use std::ffi::OsStr; +use std::process::Command; + +/// Remove inherited git-specific environment from a command before running git. +pub(crate) fn strip_git_env(command: &mut Command) { + for (key, _) in std::env::vars_os() { + if starts_with_git_prefix(&key) { + command.env_remove(key); + } + } +} + +fn starts_with_git_prefix(key: &OsStr) -> bool { + key.to_string_lossy().starts_with("GIT_") +} diff --git a/apps/staged/src-tauri/src/git/mod.rs b/apps/staged/src-tauri/src/git/mod.rs index edf62666..a6f17c76 100644 --- a/apps/staged/src-tauri/src/git/mod.rs +++ b/apps/staged/src-tauri/src/git/mod.rs @@ -1,6 +1,7 @@ mod cli; mod commit; mod diff; +mod env; mod files; pub mod github; mod refs; @@ -10,6 +11,7 @@ mod worktree; pub use cli::GitError; pub use commit::commit; pub use diff::{get_file_diff, get_unified_diff, list_diff_files}; +pub(crate) use env::strip_git_env; pub use files::{get_file_at_ref, search_files}; pub use github::{ check_github_auth, check_monorepo_modules, create_pull_request, detect_default_branch_for_repo, diff --git a/apps/staged/src-tauri/src/session_runner.rs b/apps/staged/src-tauri/src/session_runner.rs index 65c13f97..60f57ab9 100644 --- a/apps/staged/src-tauri/src/session_runner.rs +++ b/apps/staged/src-tauri/src/session_runner.rs @@ -2215,6 +2215,7 @@ pub fn emit_session_running( #[cfg(test)] mod tests { use super::*; + use crate::git::strip_git_env; #[cfg(unix)] #[tokio::test] @@ -2293,25 +2294,7 @@ mod tests { fn run_git(dir: &std::path::Path, args: &[&str]) -> String { let mut command = std::process::Command::new("git"); command.args(args).current_dir(dir); - for key in [ - "GIT_ALTERNATE_OBJECT_DIRECTORIES", - "GIT_CONFIG", - "GIT_CONFIG_PARAMETERS", - "GIT_CONFIG_COUNT", - "GIT_OBJECT_DIRECTORY", - "GIT_DIR", - "GIT_WORK_TREE", - "GIT_IMPLICIT_WORK_TREE", - "GIT_GRAFT_FILE", - "GIT_INDEX_FILE", - "GIT_NO_REPLACE_OBJECTS", - "GIT_REPLACE_REF_BASE", - "GIT_PREFIX", - "GIT_SHALLOW_FILE", - "GIT_COMMON_DIR", - ] { - command.env_remove(key); - } + strip_git_env(&mut command); let output = command.output().unwrap(); assert!( output.status.success(), diff --git a/apps/staged/src-tauri/src/test_utils.rs b/apps/staged/src-tauri/src/test_utils.rs index 50cbd0d3..4fe6a9fe 100644 --- a/apps/staged/src-tauri/src/test_utils.rs +++ b/apps/staged/src-tauri/src/test_utils.rs @@ -3,23 +3,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use uuid::Uuid; -const GIT_LOCAL_ENV_VARS: &[&str] = &[ - "GIT_ALTERNATE_OBJECT_DIRECTORIES", - "GIT_CONFIG", - "GIT_CONFIG_PARAMETERS", - "GIT_CONFIG_COUNT", - "GIT_OBJECT_DIRECTORY", - "GIT_DIR", - "GIT_WORK_TREE", - "GIT_IMPLICIT_WORK_TREE", - "GIT_GRAFT_FILE", - "GIT_INDEX_FILE", - "GIT_NO_REPLACE_OBJECTS", - "GIT_REPLACE_REF_BASE", - "GIT_PREFIX", - "GIT_SHALLOW_FILE", - "GIT_COMMON_DIR", -]; +use crate::git::strip_git_env; /// A temporary git repository for use in tests. /// @@ -62,9 +46,7 @@ impl TempGitRepo { .arg("-C") .arg(&self.path) .args(args); - for key in GIT_LOCAL_ENV_VARS { - command.env_remove(key); - } + strip_git_env(&mut command); let output = command.output().unwrap();