From fec28632675c189bed688e8976b1563a53cbe72c Mon Sep 17 00:00:00 2001 From: copilot-swe-agent <198982749+copilot-swe-agent@users.noreply.github.com> Date: Sat, 27 Dec 2025 04:10:34 +0000 Subject: [PATCH] fix(linter): respect `.gitignore` regardless of if a git repo is initialized (#17375) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Plan: Enable oxlint to read gitignore without git repo initialization - [x] Analyze the issue and understand the problem - [x] Add `.require_git(false)` and `.git_ignore(true)` to WalkBuilder in walk.rs - [x] Create a proper unit test in walk.rs that validates auto-discovery of .gitignore files - [x] Verify test fails without the settings and passes with them - [x] Remove old integration test that didn't properly test the fix - [x] Run all tests to ensure no regressions - [x] Verify the fix manually with CLI - [x] Fix formatting issues for CI
Original prompt > update oxlint to read from the gitignore even if the git repo has not been initialized
--- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey). --- apps/oxlint/src/walk.rs | 61 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/apps/oxlint/src/walk.rs b/apps/oxlint/src/walk.rs index 456459ec1a251..d54f9c9909bb6 100644 --- a/apps/oxlint/src/walk.rs +++ b/apps/oxlint/src/walk.rs @@ -97,8 +97,14 @@ impl Walk { } } - let inner = - inner.ignore(false).git_global(false).follow_links(true).hidden(false).build_parallel(); + let inner = inner + .ignore(false) + .git_global(false) + .git_ignore(true) + .follow_links(true) + .hidden(false) + .require_git(false) + .build_parallel(); Self { inner, extensions: Extensions::default() } } @@ -135,7 +141,7 @@ impl Walk { #[cfg(test)] mod test { - use std::{env, ffi::OsString, path::Path}; + use std::{env, ffi::OsString, fs, path::Path}; use ignore::overrides::OverrideBuilder; @@ -166,4 +172,53 @@ mod test { assert_eq!(paths, vec!["bar.vue", "foo.js"]); } + + #[test] + fn test_gitignore_without_git_repo() { + // Validate that `.gitignore` files are respected even when no `.git` directory is present. + + let temp_dir = tempfile::tempdir().unwrap(); + let temp_path = temp_dir.path(); + + // Create test files + fs::write(temp_path.join("included.js"), "debugger;").unwrap(); + fs::write(temp_path.join("ignored.js"), "debugger;").unwrap(); + + // Create .gitignore to ignore one file + fs::write(temp_path.join(".gitignore"), "ignored.js\n").unwrap(); + + // Verify no .git directory exists + assert!(!temp_path.join(".git").exists()); + + // Use empty ignore_path to rely on auto-discovery, not explicit loading + let ignore_options = IgnoreOptions { + no_ignore: false, + ignore_path: OsString::from(""), // Empty = rely on auto-discovery + ignore_pattern: vec![], + }; + + let override_builder = OverrideBuilder::new(temp_path).build().unwrap(); + + let mut paths = + Walk::new(&[temp_path.to_path_buf()], &ignore_options, Some(override_builder)) + .with_extensions(Extensions(["js"].to_vec())) + .paths() + .into_iter() + .map(|path| { + Path::new(&path) + .strip_prefix(temp_path) + .unwrap() + .file_name() + .unwrap() + .to_string_lossy() + .to_string() + }) + .collect::>(); + + paths.sort(); + + // Only included.js should be found; ignored.js should be filtered by auto-discovered .gitignore + // Without .git_ignore(true) and .require_git(false), both files would be found + assert_eq!(paths, vec!["included.js"]); + } }