Repository: sqlfluff/sqlfluff

Issue:
Configuration from current working path not being loaded when path provided.
I have the following directory structure.
```
~/GitHub/sqlfluff-bug
➜  tree -a
.
├── .sqlfluffignore
├── ignore_me_1.sql
├── path_a
│   └── ignore_me_2.sql
└── path_b
    ├── ignore_me_3.sql
    └── lint_me_1.sql

2 directories, 5 files
```
And the following ignore file

```
~/GitHub/sqlfluff-bug
➜  cat .sqlfluffignore

~/GitHub/sqlfluff-bug
➜  cat .sqlfluffignore
ignore_me_1.sql
path_a/
path_b/ignore_me_3.sql%
```

When I run the following I get the expected result. Sqlfluff only lints the one file that is not ignored.
```
~/GitHub/sqlfluff-bug
➜  sqlfluff lint .

~/GitHub/sqlfluff-bug
➜  sqlfluff lint .
== [path_b/lint_me_1.sql] FAIL
L:   2 | P:   1 | L003 | Indent expected and not found compared to line #1
L:   2 | P:  10 | L010 | Inconsistent capitalisation of keywords.
```

However when I run the lint explicitly on one of the two directories then ignored files are also linted.

```
~/GitHub/sqlfluff-bug
➜  sqlfluff lint path_a

~/GitHub/sqlfluff-bug
➜  sqlfluff lint path_a
== [path_a/ignore_me_2.sql] FAIL
L:   2 | P:   1 | L003 | Indent expected and not found compared to line #1
L:   2 | P:  10 | L010 | Inconsistent capitalisation of keywords.

~/GitHub/sqlfluff-bug
➜  sqlfluff lint path_b

~/GitHub/sqlfluff-bug
➜  sqlfluff lint path_b
== [path_b/ignore_me_3.sql] FAIL
L:   2 | P:   1 | L003 | Indent expected and not found compared to line #1
L:   2 | P:  10 | L010 | Inconsistent capitalisation of keywords.
== [path_b/lint_me_1.sql] FAIL
L:   2 | P:   1 | L003 | Indent expected and not found compared to line #1
L:   2 | P:  10 | L010 | Inconsistent capitalisation of keywords.
```

If this is the expected behaviour then it might be worthwhile to add an example to the [docs](https://docs.sqlfluff.com/en/latest/configuration.html#sqlfluffignore).

Edit: I've replicated this issue on sqlfluff version 0.3.2 to 0.3.6.


Discussion:
This is currently functioning as expected in that it only looks for `.sqlfluffignore` files within the directories you specify. So if you point sqlfluff at `/path_b`, it would only looks for a `.sqlfluffignore` file at `/path_b/.sqlfluffignore` and any child directories of that. It won't check in parents of the given file.

I think that's the expected behavior consistent with `.dockerignore` and `.gitignore` .

I agree about clarifying the documentation, which uses the phrase `placed in the root of your project` which I think alone is misleading.
I think the behavior described in this issue is desirable.

For CI with pre-commit for example, right now I would need to add a `.sqlfluffignore` to each sub-directory containing sql files I want to ignore. That's because pre-commit will give the full path pointing to each file that changed before commit.

I'm not sure the behavior is consistent with `.gitignore` because the "project root" stays the same and `.gitignore` files are applied from top level down to the subdirectory of each file, while in `sqlfluff` we don't really have a project root, which I think could come from a new configuration in `.sqlfluff` (or we could assume `cwd` if it's parent directory of the file we're trying to lint).
I've just hit this issue myself (but for configuration file) and I agree with @dmateusp on this one.

I think this is more than a documentation issue.

From putting together the initial configuration code, the config loader, *should* check the current working directory for config loading, but it feels like that isn't working right now.

Patch:
diff --git a/src/sqlfluff/core/config.py b/src/sqlfluff/core/config.py
--- a/src/sqlfluff/core/config.py
+++ b/src/sqlfluff/core/config.py
@@ -395,7 +395,7 @@ def load_config_up_to_path(
 
     @classmethod
     def find_ignore_config_files(
-        cls, path, working_path=os.getcwd(), ignore_file_name=".sqlfluffignore"
+        cls, path, working_path=Path.cwd(), ignore_file_name=".sqlfluffignore"
     ):
         """Finds sqlfluff ignore files from both the path and its parent paths."""
         return set(
@@ -417,8 +417,8 @@ def iter_config_locations_up_to_path(path, working_path=Path.cwd()):
         The lowest priority is the user appdir, then home dir, then increasingly
         the configs closest to the file being directly linted.
         """
-        given_path = Path(path).resolve()
-        working_path = Path(working_path).resolve()
+        given_path = Path(path).absolute()
+        working_path = Path(working_path).absolute()
 
         # If we've been passed a file and not a directory,
         # then go straight to the directory.
diff --git a/src/sqlfluff/core/linter/linter.py b/src/sqlfluff/core/linter/linter.py
--- a/src/sqlfluff/core/linter/linter.py
+++ b/src/sqlfluff/core/linter/linter.py
@@ -843,6 +843,7 @@ def paths_from_path(
         # matched, but we warn the users when that happens
         is_exact_file = os.path.isfile(path)
 
+        path_walk: WalkableType
         if is_exact_file:
             # When the exact file to lint is passed, we
             # fill path_walk with an input that follows
@@ -850,24 +851,26 @@ def paths_from_path(
             #   (root, directories, files)
             dirpath = os.path.dirname(path)
             files = [os.path.basename(path)]
-            ignore_file_paths = ConfigLoader.find_ignore_config_files(
-                path=path, working_path=working_path, ignore_file_name=ignore_file_name
-            )
-            # Add paths that could contain "ignore files"
-            # to the path_walk list
-            path_walk_ignore_file = [
-                (
-                    os.path.dirname(ignore_file_path),
-                    None,
-                    # Only one possible file, since we only
-                    # have one "ignore file name"
-                    [os.path.basename(ignore_file_path)],
-                )
-                for ignore_file_path in ignore_file_paths
-            ]
-            path_walk: WalkableType = [(dirpath, None, files)] + path_walk_ignore_file
+            path_walk = [(dirpath, None, files)]
         else:
-            path_walk = os.walk(path)
+            path_walk = list(os.walk(path))
+
+        ignore_file_paths = ConfigLoader.find_ignore_config_files(
+            path=path, working_path=working_path, ignore_file_name=ignore_file_name
+        )
+        # Add paths that could contain "ignore files"
+        # to the path_walk list
+        path_walk_ignore_file = [
+            (
+                os.path.dirname(ignore_file_path),
+                None,
+                # Only one possible file, since we only
+                # have one "ignore file name"
+                [os.path.basename(ignore_file_path)],
+            )
+            for ignore_file_path in ignore_file_paths
+        ]
+        path_walk += path_walk_ignore_file
 
         # If it's a directory then expand the path!
         buffer = []


Test patch:
diff --git a/test/core/linter_test.py b/test/core/linter_test.py
--- a/test/core/linter_test.py
+++ b/test/core/linter_test.py
@@ -1,10 +1,12 @@
 """The Test file for the linter class."""
 
-import pytest
+import os
 import logging
 from typing import List
 from unittest.mock import patch
 
+import pytest
+
 from sqlfluff.core import Linter, FluffConfig
 from sqlfluff.core.linter import runner
 from sqlfluff.core.errors import SQLLexError, SQLBaseError, SQLLintError, SQLParseError
@@ -91,6 +93,23 @@ def test__linter__path_from_paths__explicit_ignore():
     assert len(paths) == 0
 
 
+def test__linter__path_from_paths__sqlfluffignore_current_directory():
+    """Test that .sqlfluffignore in the current directory is read when dir given."""
+    oldcwd = os.getcwd()
+    try:
+        os.chdir("test/fixtures/linter/sqlfluffignore")
+        lntr = Linter()
+        paths = lntr.paths_from_path(
+            "path_a/",
+            ignore_non_existent_files=True,
+            ignore_files=True,
+            working_path="test/fixtures/linter/sqlfluffignore/",
+        )
+        assert len(paths) == 0
+    finally:
+        os.chdir(oldcwd)
+
+
 def test__linter__path_from_paths__dot():
     """Test extracting paths from a dot."""
     lntr = Linter()