Wrong file path passed to RuboCop and Reek #719
Description
Your environment
vscode-ruby
version: 0.28.1, and also commit 7b5b602- Ruby version: 2.7.2
- Ruby version manager (if any): RVM
- VS Code version: 1.54.3
- Operating System: macOS Catalina
- Using language server? (eg
useLanguageServer
is true in your configuration?) yes
Expected behavior
RuboCop is run with these arguments:
[
"bundle",
"exec",
"rubocop",
"-s",
"/path-to-file.rb",
"-f",
"json"
]
Reek is run with these arguments:
[
"bundle",
"exec",
"reek",
"-f",
"json",
"--stdin-filename",
"/path-to-file.rb"
]
Actual behavior
RuboCop is run with these arguments:
[
"bundle",
"exec",
"rubocop",
"-s",
"'/path-to-file.rb'", // <--- note the extraneous single quotes!
"-f",
"json"
]
Reek is run with these arguments:
[
"bundle",
"exec",
"reek",
"-f",
"json",
"--stdin-filename",
"'/path-to-file.rb'" // <--- note the extraneous single quotes!
]
To reproduce:
-
Create a shell script
~/fake-rubocop
that prints the exact arguments passed:#!/bin/sh set -x exec bundle exec rubocop "$@"
Make sure to chmod +x it.
-
Create a shell script
~/fake-reek
that prints the exact arguments passed:#!/bin/sh set -x exec bundle exec reek "$@"
Make sure to chmod +x it.
-
Use this configuration:
"ruby.useLanguageServer": true, "ruby.lint": { "rubocop": { "command": "/path-to-home-directory/fake-rubocop" }, "reek": { "command": "/path-to-home-directory/fake-reek" } },
-
Open a Ruby project directory. Inside that project directory, open a random Ruby file.
-
In the Ruby Language Server output, observe that
fake-rubocop
logs this:+ exec bundle exec rubocop -s ''\''/path-to-file.rb'\''' -f json
We expect no extraneous quotes:
+ exec bundle exec rubocop -s /path-to-file -f json
-
In the Ruby Language Server output, observe that
fake-reek
logs this:+ exec bundle exec reek -f json --stdin-filename ''\''/path-to-file.rb'\'''
We expect no extraneous quotes:
+ exec bundle exec reek -f json --stdin-filename /path-to-file.rb
Comments
Because of the extraneous quotes, we pass invalid filenames to RuboCop and Reek.
I don't know whether this causes problems for Reek, but it does cause problems for RuboCop: see #227. Normally, RuboCop checks each level of parent directory in the input file's path, in search for a .rubocop.yml. But because we pass an invalid filename, RuboCop can't find a .rubocop.yml, and ends up ignoring the .rubocop.yml that the project has.
The extraneous quotes are deliberately inserted by the code:
-
In packages/language-server-ruby/src/linters/RuboCop.ts:
let args = ['-s', `'${documentPath.fsPath}'`, '-f', 'json'];
-
In packages/language-server-ruby/src/linters/Reek.ts:
return ['-f', 'json', '--stdin-filename', `'${documentPath.fsPath}'`];
I suspect that the author meant to prevent any issues with spaces in filenames. However, Linters are executed through cross-spawn, which doesn't execute commands through a shell. There should be no problems with spaces in filenames: each element in the argument array represents exactly one argument, with no shell trying to split up filenames by space.