aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorEric Stern2026-03-28 04:03:31 -0700
committerGitHub2026-03-28 20:03:31 +0900
commit0369442b06755e01aaf3bc88c9f5dba875844c71 (patch)
tree327dda96d91f1453eab1b6096eff93c4fcf34cf5
parent69c945d5daecadf8e4c4c499d0a7babda748d603 (diff)
downloadale-0369442b06755e01aaf3bc88c9f5dba875844c71.tar.gz

fix(phpcs): run from project root instead of file directory (#5105)

When phpcs.xml sets installed_paths to a relative path (e.g. vendor/slevomat/coding-standard), running phpcs from the file’s directory causes it to fail because the path is resolved relative to cwd rather than the config file location.

Change cwd to find the nearest composer.json and use that directory, matching how most PHP ecosystem tools expect to operate.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

-rw-r--r--ale_linters/php/phpcs.vim30
-rw-r--r--test/linter/test_phpcs.vader2
-rw-r--r--test/test-files/phpcs/project-with-phpcs/composer.json1
3 files changed, 31 insertions, 2 deletions
diff --git a/ale_linters/php/phpcs.vim b/ale_linters/php/phpcs.vim
index ce47a13ba..12ca9da93 100644
--- a/ale_linters/php/phpcs.vim
+++ b/ale_linters/php/phpcs.vim
@@ -7,6 +7,34 @@ call ale#Set('php_phpcs_options', '')
call ale#Set('php_phpcs_executable', 'phpcs')
call ale#Set('php_phpcs_use_global', get(g:, 'ale_use_global_executables', 0))
+function! ale_linters#php#phpcs#GetCwd(buffer) abort
+ let l:result = ale#path#Dirname(ale_linters#php#phpcs#FindProjectRoot(a:buffer))
+
+ return empty(l:result) ? v:null : l:result
+endfunction
+
+function! ale_linters#php#phpcs#FindProjectRoot(buffer) abort
+ let l:result = ale#path#FindNearestFile(a:buffer, 'phpcs.xml')
+
+ if empty(l:result)
+ let l:result = ale#path#FindNearestFile(a:buffer, 'phpcs.xml.dist')
+ endif
+
+ if empty(l:result)
+ let l:result = ale#path#FindNearestFile(a:buffer, '.phpcs.xml')
+ endif
+
+ if empty(l:result)
+ let l:result = ale#path#FindNearestFile(a:buffer, '.phpcs.xml.dist')
+ endif
+
+ if empty(l:result)
+ let l:result = ale#path#FindNearestFile(a:buffer, 'composer.json')
+ endif
+
+ return l:result
+endfunction
+
function! ale_linters#php#phpcs#GetCommand(buffer) abort
let l:standard = ale#Var(a:buffer, 'php_phpcs_standard')
let l:standard_option = !empty(l:standard)
@@ -48,7 +76,7 @@ call ale#linter#Define('php', {
\ 'vendor/bin/phpcs',
\ 'phpcs'
\ ])},
-\ 'cwd': '%s:h',
+\ 'cwd': function('ale_linters#php#phpcs#GetCwd'),
\ 'command': function('ale_linters#php#phpcs#GetCommand'),
\ 'callback': 'ale_linters#php#phpcs#Handle',
\})
diff --git a/test/linter/test_phpcs.vader b/test/linter/test_phpcs.vader
index afb88e32d..e67763463 100644
--- a/test/linter/test_phpcs.vader
+++ b/test/linter/test_phpcs.vader
@@ -11,7 +11,7 @@ Execute(The local phpcs executable should be used):
let g:executable = ale#path#Simplify(g:dir . '/../test-files/phpcs/project-with-phpcs/vendor/bin/phpcs')
- AssertLinterCwd '%s:h'
+ AssertLinterCwd ale#path#Simplify(g:dir . '/../test-files/phpcs/project-with-phpcs')
AssertLinter g:executable, ale#Escape(g:executable)
\ . ' -s --report=emacs --stdin-path=%s'
diff --git a/test/test-files/phpcs/project-with-phpcs/composer.json b/test/test-files/phpcs/project-with-phpcs/composer.json
new file mode 100644
index 000000000..9e26dfeeb
--- /dev/null
+++ b/test/test-files/phpcs/project-with-phpcs/composer.json
@@ -0,0 +1 @@
+{} \ No newline at end of file