Repository: okonet/lint-staged
Pull request #1081 (2022-01-06 14:39:25)

fix: always run non-git tasks in the current working directory
I noticed that the `execa` task spawning linters wasn't getting passed the `cwd` option, this might explain difficulties with ESLint picking up configuration, for example. Previously tasks were always run in the `process.cwd()`, but it might be explicitly something else.

codecov[bot]: # [Codecov](https://codecov.io/gh/okonet/lint-staged/pull/1081?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov) Report
> Merging [#1081](https://codecov.io/gh/okonet/lint-staged/pull/1081?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov) (3022150) into [master](https://codecov.io/gh/okonet/lint-staged/commit/c7ea3594c81f7c2724a7babc8e8d57926b4679c8?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov) (c7ea359) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/okonet/lint-staged/pull/1081/graphs/tree.svg?width=650&height=150&src=pr&token=LSoEgsjk4O&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov)](https://codecov.io/gh/okonet/lint-staged/pull/1081?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov)

```diff
@@            Coverage Diff            @@
##            master     #1081   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           21        21           
  Lines          595       593    -2     
  Branches       159       159           
=========================================
- Hits           595       593    -2     
```


| [Impacted Files](https://codecov.io/gh/okonet/lint-staged/pull/1081?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov) | Coverage Δ | |
|---|---|---|
| [lib/runAll.js](https://codecov.io/gh/okonet/lint-staged/pull/1081/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov#diff-bGliL3J1bkFsbC5qcw==) | `100.00% <ø> (ø)` | |
| [lib/makeCmdTasks.js](https://codecov.io/gh/okonet/lint-staged/pull/1081/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov#diff-bGliL21ha2VDbWRUYXNrcy5qcw==) | `100.00% <100.00%> (ø)` | |
| [lib/resolveTaskFn.js](https://codecov.io/gh/okonet/lint-staged/pull/1081/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov#diff-bGliL3Jlc29sdmVUYXNrRm4uanM=) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/okonet/lint-staged/pull/1081?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/okonet/lint-staged/pull/1081?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov). Last update [c7ea359...3022150](https://codecov.io/gh/okonet/lint-staged/pull/1081?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Andrey+Okonetchnikov).

iiroj: Ping @okonet 

Patch:
diff --git a/lib/makeCmdTasks.js b/lib/makeCmdTasks.js
index 8bac8f7..1de2b92 100644
--- a/lib/makeCmdTasks.js
+++ b/lib/makeCmdTasks.js
@@ -28,13 +28,14 @@ const getTitleLength = (renderer, columns = process.stdout.columns) => {
  *
  * @param {object} options
  * @param {Array<string|Function>|string|Function} options.commands
+ * @param {string} options.cwd
  * @param {Array<string>} options.files
  * @param {string} options.gitDir
  * @param {string} options.renderer
  * @param {Boolean} shell
  * @param {Boolean} verbose
  */
-export const makeCmdTasks = async ({ commands, files, gitDir, renderer, shell, verbose }) => {
+export const makeCmdTasks = async ({ commands, cwd, files, gitDir, renderer, shell, verbose }) => {
   debugLog('Creating listr tasks for commands %o', commands)
   const commandArray = Array.isArray(commands) ? commands : [commands]
   const cmdTasks = []
@@ -61,7 +62,7 @@ export const makeCmdTasks = async ({ commands, files, gitDir, renderer, shell, v
 
       // Truncate title to single line based on renderer
       const title = cliTruncate(command, getTitleLength(renderer))
-      const task = resolveTaskFn({ command, files, gitDir, isFn, shell, verbose })
+      const task = resolveTaskFn({ command, cwd, files, gitDir, isFn, shell, verbose })
       cmdTasks.push({ title, command, task })
     }
   }
diff --git a/lib/resolveTaskFn.js b/lib/resolveTaskFn.js
index a0af026..f39e601 100644
--- a/lib/resolveTaskFn.js
+++ b/lib/resolveTaskFn.js
@@ -68,20 +68,20 @@ const makeErr = (command, result, ctx) => {
  *
  * @param {Object} options
  * @param {string} options.command — Linter task
+ * @param {string} [options.cwd]
  * @param {String} options.gitDir - Current git repo path
  * @param {Boolean} options.isFn - Whether the linter task is a function
  * @param {Array<string>} options.files — Filepaths to run the linter task against
- * @param {Boolean} [options.relative] — Whether the filepaths should be relative
  * @param {Boolean} [options.shell] — Whether to skip parsing linter task for better shell support
  * @param {Boolean} [options.verbose] — Always show task verbose
  * @returns {function(): Promise<Array<string>>}
  */
 export const resolveTaskFn = ({
   command,
+  cwd = process.cwd(),
   files,
   gitDir,
   isFn,
-  relative,
   shell = false,
   verbose = false,
 }) => {
@@ -89,14 +89,15 @@ export const resolveTaskFn = ({
   debugLog('cmd:', cmd)
   debugLog('args:', args)
 
-  const execaOptions = { preferLocal: true, reject: false, shell }
-  if (relative) {
-    execaOptions.cwd = process.cwd()
-  } else if (/^git(\.exe)?/i.test(cmd) && gitDir !== process.cwd()) {
+  const execaOptions = {
     // Only use gitDir as CWD if we are using the git binary
     // e.g `npm` should run tasks in the actual CWD
-    execaOptions.cwd = gitDir
+    cwd: /^git(\.exe)?/i.test(cmd) ? gitDir : cwd,
+    preferLocal: true,
+    reject: false,
+    shell,
   }
+
   debugLog('execaOptions:', execaOptions)
 
   return async (ctx = getInitialState()) => {
diff --git a/lib/runAll.js b/lib/runAll.js
index 08b9d6f..1ba7260 100644
--- a/lib/runAll.js
+++ b/lib/runAll.js
@@ -135,6 +135,7 @@ export const runAll = async (
     for (const task of chunkTasks) {
       const subTasks = await makeCmdTasks({
         commands: task.commands,
+        cwd,
         files: task.fileList,
         gitDir,
         renderer: listrOptions.renderer,


Test patch:
diff --git a/test/makeCmdTasks.spec.js b/test/makeCmdTasks.spec.js
index c591bd5..5d5e316 100644
--- a/test/makeCmdTasks.spec.js
+++ b/test/makeCmdTasks.spec.js
@@ -43,6 +43,7 @@ describe('makeCmdTasks', () => {
     await taskPromise
     expect(execa).toHaveBeenCalledTimes(1)
     expect(execa).lastCalledWith('test', ['test.js'], {
+      cwd: process.cwd(),
       preferLocal: true,
       reject: false,
       shell: false,
@@ -52,6 +53,7 @@ describe('makeCmdTasks', () => {
     await taskPromise
     expect(execa).toHaveBeenCalledTimes(2)
     expect(execa).lastCalledWith('test2', ['test.js'], {
+      cwd: process.cwd(),
       preferLocal: true,
       reject: false,
       shell: false,
diff --git a/test/resolveTaskFn.spec.js b/test/resolveTaskFn.spec.js
index 642d885..1c4e70e 100644
--- a/test/resolveTaskFn.spec.js
+++ b/test/resolveTaskFn.spec.js
@@ -21,6 +21,7 @@ describe('resolveTaskFn', () => {
     await taskFn()
     expect(execa).toHaveBeenCalledTimes(1)
     expect(execa).lastCalledWith('node', ['--arg=true', './myscript.js', 'test.js'], {
+      cwd: process.cwd(),
       preferLocal: true,
       reject: false,
       shell: false,
@@ -38,6 +39,7 @@ describe('resolveTaskFn', () => {
     await taskFn()
     expect(execa).toHaveBeenCalledTimes(1)
     expect(execa).lastCalledWith('node', ['--arg=true', './myscript.js', 'test.js'], {
+      cwd: process.cwd(),
       preferLocal: true,
       reject: false,
       shell: false,
@@ -56,6 +58,7 @@ describe('resolveTaskFn', () => {
     await taskFn()
     expect(execa).toHaveBeenCalledTimes(1)
     expect(execa).lastCalledWith('node --arg=true ./myscript.js test.js', {
+      cwd: process.cwd(),
       preferLocal: true,
       reject: false,
       shell: true,
@@ -73,6 +76,7 @@ describe('resolveTaskFn', () => {
     await taskFn()
     expect(execa).toHaveBeenCalledTimes(1)
     expect(execa).lastCalledWith('node --arg=true ./myscript.js test.js', {
+      cwd: process.cwd(),
       preferLocal: true,
       reject: false,
       shell: true,
@@ -90,6 +94,7 @@ describe('resolveTaskFn', () => {
     await taskFn()
     expect(execa).toHaveBeenCalledTimes(1)
     expect(execa).lastCalledWith('node --arg=true ./myscript.js test.js', {
+      cwd: process.cwd(),
       preferLocal: true,
       reject: false,
       shell: '/bin/bash',
@@ -121,23 +126,6 @@ describe('resolveTaskFn', () => {
     await taskFn()
     expect(execa).toHaveBeenCalledTimes(1)
     expect(execa).lastCalledWith('jest', ['test.js'], {
-      preferLocal: true,
-      reject: false,
-      shell: false,
-    })
-  })
-
-  it('should always pass `process.cwd()` as `cwd` to `execa()` when relative = true', async () => {
-    expect.assertions(2)
-    const taskFn = resolveTaskFn({
-      ...defaultOpts,
-      command: 'git diff',
-      relative: true,
-    })
-
-    await taskFn()
-    expect(execa).toHaveBeenCalledTimes(1)
-    expect(execa).lastCalledWith('git', ['diff', 'test.js'], {
       cwd: process.cwd(),
       preferLocal: true,
       reject: false,