Description
Description
I find odd situation in my rails project using lint-staged with rubocop.
Lint-staged stuck forever only when using rubocop with Server Mode.
❯ bundle exec rubocop --start-server
RuboCop server starting on 127.0.0.1:50996.
❯ bundle exec rubocop --server-status
RuboCop server (90477) is running.
❯ git commit -m 'implement'
✔ Preparing lint-staged...
❯ Running tasks for staged files...
❯ .lintstagedrc — 4 files
❯ * — 4 files
⠦ bundle exec rubocop --version
◼ Applying modifications from tasks...
◼ Cleaning up temporary files...
I have research and found that non-TTY rubocop reads from stdin until EOF and will not exit forever in server mode.
rubocop which launched by lint-staged stucked in L24 in https://github.com/rubocop/rubocop/blob/v1.50.2/lib/rubocop/server/client_command/exec.rb#L21-L25
#1019 also says, subprocess spawned by lint-staged has non-tty and stdin is not closed.
❯ node -e "import('execa').then(m => m.execa('ruby', ['-e', 'puts \$stdin.tty?']).then(r => console.log(r.stdout)))"
false
❯ node -e "import('execa').then(m => m.execa('ruby', ['-e', '\$stdin.read']).then(r => console.log(r)))"
(does not exit forever)
Execa has input option to close the stdin of subprocess.
# does not stuck because stdin of subprocess is closed
❯ node -e "import('execa').then(m => m.execa('bundle', ['exec', 'rubocop', '--version'], { input: '' })).then(s => console.log(s));"
# node.js version
❯ node -e "import('execa').then(m => m.execa('node', ['-e', 'process.stdin.read()'], { input: '' })).then(s => console.log(s));"
I would prefer that the default behavior is stdin subprocess is already closed, or create an option to set stdin of subprocess like input of execaOption.
Steps to reproduce
git clone my repo.
Or manually install rubocop.
❯ bundle exec rubocop --start-server
RuboCop server starting on 127.0.0.1:50996.
❯ touch bar && git add bar
❯ git commit --allow-empty -m 'test'
✔ Preparing lint-staged...
❯ Running tasks for staged files...
❯ .lintstagedrc — 1 file
❯ * — 1 file
⠴ bundle exec rubocop --version
◼ Applying modifications from tasks...
◼ Cleaning up temporary files...
Debug Logs
expand to view
❯ git commit --allow-empty -m 'test'
lint-staged:bin Options parsed from command-line: {
allowEmpty: false,
concurrent: true,
configPath: undefined,
cwd: undefined,
debug: true,
diff: undefined,
diffFilter: undefined,
maxArgLength: undefined,
quiet: false,
relative: false,
shell: false,
stash: true,
verbose: false
} +0ms
lint-staged:validateOptions Validating options... +0ms
lint-staged:validateOptions Validated options! +0ms
lint-staged Unset GIT_LITERAL_PATHSPECS (was `undefined`) +0ms
lint-staged:runAll Running all linter scripts... +0ms
lint-staged:runAll Using working directory `/Users/user/work/ruby/example-rubocop` +0ms
lint-staged:resolveGitRepo Resolving git repo from `/Users/user/work/ruby/example-rubocop` +0ms
lint-staged:resolveGitRepo Unset GIT_DIR (was `undefined`) +0ms
lint-staged:resolveGitRepo Unset GIT_WORK_TREE (was `undefined`) +0ms
lint-staged:execGit Running git command [ 'rev-parse', '--show-prefix' ] +0ms
lint-staged:resolveGitRepo Resolved git directory to be `/Users/user/work/ruby/example-rubocop` +10ms
lint-staged:resolveGitRepo Resolved git config directory to be `/Users/user/work/ruby/example-rubocop/.git` +0ms
lint-staged:execGit Running git command [ 'log', '-1' ] +10ms
lint-staged:execGit Running git command [ 'diff', '--name-only', '-z', '--diff-filter=ACMR', '--staged' ] +5ms
lint-staged:runAll Loaded list of staged files in git:
lint-staged:runAll [ '/Users/user/work/ruby/example-rubocop/foo' ] +22ms
lint-staged:searchConfigs Searching for configuration files... +0ms
lint-staged:execGit Running git command [ 'ls-files', '-z', '--full-name' ] +8ms
lint-staged:execGit Running git command [ 'ls-files', '-z', '--full-name', '--others', '--exclude-standard' ] +1ms
lint-staged:searchConfigs Found possible config files: [
'/Users/user/work/ruby/example-rubocop/.lintstagedrc',
'/Users/user/work/ruby/example-rubocop/package.json'
] +5ms
lint-staged:loadConfig Loading configuration from `/Users/user/work/ruby/example-rubocop/.lintstagedrc`... +0ms
lint-staged:loadConfig Loading configuration from `/Users/user/work/ruby/example-rubocop/package.json`... +0ms
lint-staged:loadConfig Successfully loaded config from `/Users/user/work/ruby/example-rubocop/package.json`:
lint-staged:loadConfig null +0ms
lint-staged:loadConfig Successfully loaded config from `/Users/user/work/ruby/example-rubocop/.lintstagedrc`:
lint-staged:loadConfig { '*': 'bundle exec rubocop --version' } +3ms
lint-staged:validateConfig Validating config from `/Users/user/work/ruby/example-rubocop/.lintstagedrc`... +0ms
lint-staged:validateConfig Validated config from `/Users/user/work/ruby/example-rubocop/.lintstagedrc`: +0ms
lint-staged:validateConfig {
lint-staged:validateConfig '*': 'bundle exec rubocop --version'
lint-staged:validateConfig } +1ms
lint-staged:searchConfigs Found 1 config files +5ms
lint-staged:groupFilesByConfig Grouping 1 files by 1 configurations +0ms
lint-staged:chunkFiles Resolved an argument string length of 41 characters from 1 files +0ms
lint-staged:chunkFiles Creating 1 chunks for maxArgLength of 131072 +0ms
lint-staged:generateTasks Generating linter tasks +0ms
lint-staged:generateTasks Generated task:
lint-staged:generateTasks {
lint-staged:generateTasks pattern: '*',
lint-staged:generateTasks commands: 'bundle exec rubocop --version',
lint-staged:generateTasks fileList: [ '/Users/user/work/ruby/example-rubocop/foo' ]
lint-staged:generateTasks } +1ms
lint-staged:makeCmdTasks Creating listr tasks for commands 'bundle exec rubocop --version' +0ms
lint-staged:resolveTaskFn cmd: bundle +0ms
lint-staged:resolveTaskFn args: [ 'exec', 'rubocop', '--version' ] +0ms
lint-staged:resolveTaskFn execaOptions: {
cwd: '/Users/user/work/ruby/example-rubocop',
preferLocal: true,
reject: false,
shell: false
} +0ms
lint-staged:chunkFiles Resolved an argument string length of 41 characters from 1 files +2ms
lint-staged:chunkFiles Creating 1 chunks for maxArgLength of 131072 +0ms
[STARTED] Preparing lint-staged...
lint-staged:GitWorkflow Backing up original state... +0ms
lint-staged:GitWorkflow Getting partially staged files... +0ms
lint-staged:execGit Running git command [ 'status', '-z' ] +13ms
lint-staged:GitWorkflow Found partially staged files: [] +5ms
lint-staged:GitWorkflow Backing up merge state... +0ms
lint-staged:file Reading file `/Users/user/work/ruby/example-rubocop/.git/MERGE_HEAD` +0ms
lint-staged:file Reading file `/Users/user/work/ruby/example-rubocop/.git/MERGE_MODE` +0ms
lint-staged:file Reading file `/Users/user/work/ruby/example-rubocop/.git/MERGE_MSG` +0ms
lint-staged:file File `/Users/user/work/ruby/example-rubocop/.git/MERGE_HEAD` doesn't exist, ignoring... +0ms
lint-staged:file File `/Users/user/work/ruby/example-rubocop/.git/MERGE_MODE` doesn't exist, ignoring... +0ms
lint-staged:file File `/Users/user/work/ruby/example-rubocop/.git/MERGE_MSG` doesn't exist, ignoring... +0ms
lint-staged:GitWorkflow Done backing up merge state! +0ms
lint-staged:GitWorkflow Getting deleted files... +0ms
lint-staged:execGit Running git command [ 'ls-files', '--deleted' ] +5ms
lint-staged:GitWorkflow Found deleted files: [] +4ms
lint-staged:execGit Running git command [ 'stash', 'create' ] +4ms
lint-staged:execGit Running git command [
'stash',
'store',
'--quiet',
'--message',
'lint-staged automatic backup',
'c678441708c03f1361be5bf4be437162bd82ab98'
] +11ms
lint-staged:GitWorkflow Done backing up original state! +17ms
[SUCCESS] Preparing lint-staged...
[STARTED] Running tasks for staged files...
[STARTED] .lintstagedrc — 1 file
[STARTED] * — 1 file
[STARTED] bundle exec rubocop --version
Environment
- OS: macOS 13.3.1 (a)
- Node.js: v18.16.0
lint-staged
: v13.2.2- execa v7.1.1
- rubocop v1.50.2