From 0369442b06755e01aaf3bc88c9f5dba875844c71 Mon Sep 17 00:00:00 2001 From: Eric Stern Date: Sat, 28 Mar 2026 04:03:31 -0700 Subject: [PATCH] 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 --- ale_linters/php/phpcs.vim | 30 ++++++++++++++++++- test/linter/test_phpcs.vader | 2 +- .../phpcs/project-with-phpcs/composer.json | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 test/test-files/phpcs/project-with-phpcs/composer.json diff --git a/ale_linters/php/phpcs.vim b/ale_linters/php/phpcs.vim index ce47a13b..12ca9da9 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 afb88e32..e6776346 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 00000000..9e26dfee --- /dev/null +++ b/test/test-files/phpcs/project-with-phpcs/composer.json @@ -0,0 +1 @@ +{} \ No newline at end of file