Repository: okonet/lint-staged
Pull request #344 (2017-11-26 07:42:46)

feat: Add debug logs
This integrates [`debug`](https://github.com/visionmedia/debug) which can be enabled by setting the environment variable `$DEBUG` to `lint-staged*`. It can also be specified inline by doing the following:

```
# on *nix
$ DEBUG=lint-staged* git commit

# on Windows
λ set DEBUG=lint-staged* && git commit
```

Example output:
```
λ node . --debug
  lint-staged:bin Running `lint-staged@0.0.0-development` +0ms
  lint-staged Loading config using `cosmiconfig` +0ms
  lint-staged Successfully loaded config from `E:\Projects\repos\lint-staged\.lintstagedrc`:
  lint-staged { linters: { '*.js': [ 'eslint --fix', 'git add' ], '.*rc': 'jsonlint' } } +34ms
  lint-staged:cfg Normalizing config +0ms
  lint-staged:cfg Validating config +11ms
Running lint-staged with the following config:
{
  linters: {
    '*.js': [
      'eslint --fix',
      'git add'
    ],
    '.*rc': 'jsonlint'
  },
  concurrent: true,
  chunkSize: 9007199254740991,
  globOptions: {
    matchBase: true,
    dot: true
  },
  subTaskConcurrency: 1,
  renderer: 'verbose'
}
  lint-staged Loaded scripts from package.json:
  lint-staged { precommit: 'remove-lockfiles && node index.js',
  lint-staged   cz: 'git-cz',
  lint-staged   lint: 'eslint .',
  lint-staged   'lint:fix': 'npm run lint -- --fix',
  lint-staged   pretest: 'npm run lint',
  lint-staged   test: 'jest --coverage',
  lint-staged   'test:watch': 'jest --watch' } +80ms
  lint-staged:run Running all linter scripts +0ms
  lint-staged:run Resolved git directory to be `E:\Projects\repos\lint-staged` +4ms
  lint-staged:run Loaded list of staged files in git:
  lint-staged:run [ 'test/runScript.spec.js',
  lint-staged:run   'test/index.spec.js',
  lint-staged:run   'test/getConfig.spec.js',
  lint-staged:run   'test/findBin.spec.js',
  lint-staged:run   'test/__snapshots__/index.spec.js.snap',
  lint-staged:run   'test/__snapshots__/getConfig.spec.js.snap',
  lint-staged:run   'test/__mocks__/my-config.json',
  lint-staged:run   'src/runScript.js',
  lint-staged:run   'src/runAll.js',
  lint-staged:run   'src/index.js',
  lint-staged:run   'src/getConfig.js',
  lint-staged:run   'src/findBin.js',
  lint-staged:run   'index.js',
  lint-staged:run   'README.md' ] +205ms
  lint-staged:gen-tasks Generating linter tasks +0ms
  lint-staged:cfg Normalizing config +322ms
  lint-staged:gen-tasks Generated task:
  lint-staged:gen-tasks { pattern: '*.js',
  lint-staged:gen-tasks   commands: [ 'eslint --fix', 'git add' ],
  lint-staged:gen-tasks   fileList:
  lint-staged:gen-tasks    [ 'E:\\Projects\\repos\\lint-staged\\test\\runScript.spec.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\test\\index.spec.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\test\\getConfig.spec.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\test\\findBin.spec.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\src\\runScript.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\src\\runAll.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\src\\index.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\src\\getConfig.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\src\\findBin.js',
  lint-staged:gen-tasks      'E:\\Projects\\repos\\lint-staged\\index.js' ] } +25ms
  lint-staged:gen-tasks Generated task:
  lint-staged:gen-tasks { pattern: '.*rc', commands: 'jsonlint', fileList: [] } +41ms
Running tasks for *.js [started]
Running tasks for .*rc [started]
  lint-staged:run-script Running script with commands [ 'eslint --fix', 'git add' ] +0ms
  lint-staged:cfg Normalizing config +96ms
Running tasks for .*rc [skipped]
→ No staged files match .*rc
eslint --fix [started]
  lint-staged:find-bin Resolving binary for command `eslint --fix` +0ms
  lint-staged:find-bin Binary for `eslint --fix` resolved to `E:\Projects\repos\lint-staged\node_modules\.bin\eslint.CMD` +50ms
  lint-staged:run-script bin: E:\Projects\repos\lint-staged\node_modules\.bin\eslint.CMD +73ms
  lint-staged:run-script args: [ '--fix',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\test\\runScript.spec.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\test\\index.spec.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\test\\getConfig.spec.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\test\\findBin.spec.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\runScript.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\runAll.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\index.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\getConfig.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\findBin.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\index.js' ] +3ms
  lint-staged:run-script opts: {} +28ms
eslint --fix [completed]
git add [started]
  lint-staged:find-bin Resolving binary for command `git add` +8s
  lint-staged:find-bin Binary for `git add` resolved to `C:\Program Files\Git\cmd\git.EXE` +62ms
  lint-staged:run-script bin: C:\Program Files\Git\cmd\git.EXE +8s
  lint-staged:run-script args: [ 'add',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\test\\runScript.spec.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\test\\index.spec.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\test\\getConfig.spec.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\test\\findBin.spec.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\runScript.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\runAll.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\index.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\getConfig.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\src\\findBin.js',
  lint-staged:run-script   'E:\\Projects\\repos\\lint-staged\\index.js' ] +2ms
  lint-staged:run-script opts: {} +25ms
```

Edit: Closes #319.

codecov[bot]: # [Codecov](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=h1) Report
> Merging [#344](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=desc) into [master](https://codecov.io/gh/okonet/lint-staged/commit/9a74d0a2174bc33c9437f99fa39b1c26a8eea5f7?src=pr&el=desc) will **increase** coverage by `0.28%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/okonet/lint-staged/pull/344/graphs/tree.svg?src=pr&token=LSoEgsjk4O&width=650&height=150)](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #344      +/-   ##
==========================================
+ Coverage    97.8%   98.08%   +0.28%     
==========================================
  Files          10       10              
  Lines         182      209      +27     
  Branches       23       23              
==========================================
+ Hits          178      205      +27     
  Misses          4        4
```


| [Impacted Files](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/generateTasks.js](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=tree#diff-c3JjL2dlbmVyYXRlVGFza3MuanM=) | `100% <100%> (ø)` | :arrow_up: |
| [src/findBin.js](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=tree#diff-c3JjL2ZpbmRCaW4uanM=) | `100% <100%> (ø)` | :arrow_up: |
| [src/runAll.js](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=tree#diff-c3JjL3J1bkFsbC5qcw==) | `100% <100%> (ø)` | :arrow_up: |
| [src/getConfig.js](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=tree#diff-c3JjL2dldENvbmZpZy5qcw==) | `100% <100%> (ø)` | :arrow_up: |
| [src/index.js](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=tree#diff-c3JjL2luZGV4Lmpz) | `90.47% <100%> (+1.58%)` | :arrow_up: |
| [src/runScript.js](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=tree#diff-c3JjL3J1blNjcmlwdC5qcw==) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=footer). Last update [9a74d0a...ba93313](https://codecov.io/gh/okonet/lint-staged/pull/344?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

okonet: @sudo-suhas this looks amazing. I'm wondering if we should close #319 in favor of this?
sudo-suhas: We could. I also felt that `debug` and `verbose` have some over lapping functionality. One thing which is missing here is the ability to enable debug logs using a command line flag. If we wanted to, we would need to modify `process.env` if the flag is present(I think). Thoughts?
okonet: Overriding the `process.env` sounds legit to me in case if flag is present. Let's do that!
sudo-suhas: Here's what I am going to do:
- Remove `verbose` config option
- Use `--debug` to override `process.env` and set `config.renderer` to `verbose`.

Let me know if you have any concerns or any suggestions.
luftywiranda13: what do you guys think about [meow](https://github.com/sindresorhus/meow)? I use it in some of my CLI projects and I love it

IMO it'll make our jobs easier here
sudo-suhas: I am not clear on how it is better. In any case, even if we do wish to switch to it, it probably shouldn't be a part of this PR. 
okonet: @sudo-suhas your plan sounds good to me! Please go ahead since I'll need this work in https://github.com/okonet/lint-staged/pull/75
sudo-suhas: @okonet This PR is ready for a review. I have done the changes we discussed in b1a228f. 
sudo-suhas: Please note that I have marked it as a breaking change in the commit message. We should take care while squashing and merging. 
okonet: Looks good!
okonet: Please merge it. I’m on my 📱 

Patch:
diff --git a/README.md b/README.md
index 8345f48..c9f7df3 100644
--- a/README.md
+++ b/README.md
@@ -50,6 +50,28 @@ See [examples](#examples) and [configuration](#configuration) below.
 >
 > To mitigate this rename your `commit` npm script to something non git hook namespace like, for example `{ cz: git-cz }`
 
+## Command line flags
+
+```
+$ ./node_modules/.bin/lint-staged --help
+
+  Usage: lint-staged [options]
+
+
+  Options:
+
+    -V, --version        output the version number
+    -c, --config [path]  Path to configuration file
+    -d, --debug          Enable debug mode
+    -h, --help           output usage information
+```
+
+* **`--config [path]`**: This can be used to manually specify the `lint-staged` config file location. However, if the specified file cannot be found, it will error out instead of performing the usual search.
+* **`--debug`**: Enabling the debug mode does the following:
+  - `lint-staged` uses the [debug](https://github.com/visionmedia/debug) module internally to log information about staged files, commands being executed, location of binaries etc. Debug logs, which are automatically enabled by passing the flag, can also be enabled by setting the environment variable `$DEBUG` to `lint-staged*`.
+  - Use the [`verbose` renderer](https://github.com/SamVerschueren/listr-verbose-renderer) for `listr`.
+  - Do not pass `--silent` to npm scripts.
+
 ## Configuration
 
 Starting with v3.1 you can now use different ways of configuring it:
@@ -102,7 +124,6 @@ To set options and keep lint-staged extensible, advanced format can be used. Thi
 * `concurrent` — *true* — runs linters for each glob pattern simultaneously. If you don’t want this, you can set `concurrent: false`
 * `chunkSize` — Max allowed chunk size based on number of files for glob pattern. This is important on windows based systems to avoid command length limitations. See [#147](https://github.com/okonet/lint-staged/issues/147)
 * `subTaskConcurrency` — `1` — Controls concurrency for processing chunks generated for each linter. Execution is **not** concurrent by default(see [#225](https://github.com/okonet/lint-staged/issues/225))
-* `verbose` — *false* — runs lint-staged in verbose mode. When `true` it will use https://github.com/SamVerschueren/listr-verbose-renderer.
 * `globOptions` — `{ matchBase: true, dot: true }` — [minimatch options](https://github.com/isaacs/minimatch#options) to customize how glob patterns match files.
 
 ## Filtering files
diff --git a/index.js b/index.js
index ae4632d..0c1c23e 100755
--- a/index.js
+++ b/index.js
@@ -3,11 +3,21 @@
 'use strict'
 
 const cmdline = require('commander')
+const debugLib = require('debug')
 const pkg = require('./package.json')
 
+const debug = debugLib('lint-staged:bin')
+
 cmdline
   .version(pkg.version)
   .option('-c, --config [path]', 'Path to configuration file')
+  .option('-d, --debug', 'Enable debug mode')
   .parse(process.argv)
 
-require('./src')(console, cmdline.config)
+if (cmdline.debug) {
+  debugLib.enable('lint-staged*')
+}
+
+debug('Running `lint-staged@%s`', pkg.version)
+
+require('./src')(console, cmdline.config, cmdline.debug)
diff --git a/package.json b/package.json
index 1d7e437..c6d1a42 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
     "chalk": "^2.1.0",
     "commander": "^2.11.0",
     "cosmiconfig": "^3.1.0",
+    "debug": "^3.1.0",
     "dedent": "^0.7.0",
     "execa": "^0.8.0",
     "find-parent-dir": "^0.3.0",
diff --git a/src/findBin.js b/src/findBin.js
index 294b658..0f644a8 100644
--- a/src/findBin.js
+++ b/src/findBin.js
@@ -2,11 +2,14 @@
 
 const npmWhich = require('npm-which')(process.cwd())
 
-module.exports = function findBin(cmd, scripts, options) {
+const debug = require('debug')('lint-staged:find-bin')
+
+module.exports = function findBin(cmd, scripts, debugMode) {
+  debug('Resolving binary for command `%s`', cmd)
   const npmArgs = (bin, args) =>
     // We always add `--` even if args are not defined. This is required
     // because we pass filenames later.
-    ['run', options && options.verbose ? undefined : '--silent', bin, '--']
+    ['run', debugMode ? undefined : '--silent', bin, '--']
       // args could be undefined but we filter that out.
       .concat(args)
       .filter(arg => arg !== undefined)
@@ -39,6 +42,7 @@ module.exports = function findBin(cmd, scripts, options) {
    */
   if (scripts[cmd] !== undefined) {
     // Support for scripts from package.json
+    debug('`%s` resolved to npm script - `%s`', cmd, scripts[cmd])
     return { bin: 'npm', args: npmArgs(cmd) }
   }
 
@@ -47,6 +51,7 @@ module.exports = function findBin(cmd, scripts, options) {
   const args = parts.splice(1)
 
   if (scripts[bin] !== undefined) {
+    debug('`%s` resolved to npm script - `%s`', bin, scripts[bin])
     return { bin: 'npm', args: npmArgs(bin, args) }
   }
 
@@ -76,5 +81,6 @@ module.exports = function findBin(cmd, scripts, options) {
     throw new Error(`${bin} could not be found. Try \`npm install ${bin}\`.`)
   }
 
+  debug('Binary for `%s` resolved to `%s`', cmd, bin)
   return { bin, args }
 }
diff --git a/src/generateTasks.js b/src/generateTasks.js
index 25f0e07..5d3fe73 100644
--- a/src/generateTasks.js
+++ b/src/generateTasks.js
@@ -6,7 +6,11 @@ const pathIsInside = require('path-is-inside')
 const getConfig = require('./getConfig').getConfig
 const resolveGitDir = require('./resolveGitDir')
 
+const debug = require('debug')('lint-staged:gen-tasks')
+
 module.exports = function generateTasks(config, relFiles) {
+  debug('Generating linter tasks')
+
   const normalizedConfig = getConfig(config) // Ensure we have a normalized config
   const linters = normalizedConfig.linters
   const globOptions = normalizedConfig.globOptions
@@ -29,10 +33,9 @@ module.exports = function generateTasks(config, relFiles) {
       // Return absolute path after the filter is run
       .map(file => path.resolve(cwd, file))
 
-    return {
-      pattern,
-      commands,
-      fileList
-    }
+    const task = { pattern, commands, fileList }
+    debug('Generated task: \n%O', task)
+
+    return task
   })
 }
diff --git a/src/getConfig.js b/src/getConfig.js
index 53b38e5..f9536ec 100644
--- a/src/getConfig.js
+++ b/src/getConfig.js
@@ -12,10 +12,12 @@ const logValidationWarning = require('jest-validate').logValidationWarning
 const unknownOptionWarning = require('jest-validate/build/warnings').unknownOptionWarning
 const isGlob = require('is-glob')
 
+const debug = require('debug')('lint-staged:cfg')
+
 /**
  * Default config object
  *
- * @type {{concurrent: boolean, chunkSize: number, globOptions: {matchBase: boolean, dot: boolean}, linters: {}, subTaskConcurrency: number, renderer: string, verbose: boolean}}
+ * @type {{concurrent: boolean, chunkSize: number, globOptions: {matchBase: boolean, dot: boolean}, linters: {}, subTaskConcurrency: number, renderer: string}}
  */
 const defaultConfig = {
   concurrent: true,
@@ -26,8 +28,7 @@ const defaultConfig = {
   },
   linters: {},
   subTaskConcurrency: 1,
-  renderer: 'update',
-  verbose: false
+  renderer: 'update'
 }
 
 /**
@@ -88,10 +89,11 @@ function unknownValidationReporter(config, example, option, options) {
  *
  * @param {Object} sourceConfig
  * @returns {{
- *  concurrent: boolean, chunkSize: number, globOptions: {matchBase: boolean, dot: boolean}, linters: {}, subTaskConcurrency: number, renderer: string, verbose: boolean
+ *  concurrent: boolean, chunkSize: number, globOptions: {matchBase: boolean, dot: boolean}, linters: {}, subTaskConcurrency: number, renderer: string
  * }}
  */
-function getConfig(sourceConfig) {
+function getConfig(sourceConfig, debugMode) {
+  debug('Normalizing config')
   const config = defaultsDeep(
     {}, // Do not mutate sourceConfig!!!
     isSimple(sourceConfig) ? { linters: sourceConfig } : sourceConfig,
@@ -100,18 +102,25 @@ function getConfig(sourceConfig) {
 
   // Check if renderer is set in sourceConfig and if not, set accordingly to verbose
   if (isObject(sourceConfig) && !sourceConfig.hasOwnProperty('renderer')) {
-    config.renderer = config.verbose ? 'verbose' : 'update'
+    config.renderer = debugMode ? 'verbose' : 'update'
   }
 
   return config
 }
 
+const optRmMsg = (opt, helpMsg) => `  Option ${chalk.bold(opt)} was removed.
+
+  ${helpMsg}
+
+  Please remove ${chalk.bold(opt)} from your configuration.`
+
 /**
  * Runs config validation. Throws error if the config is not valid.
  * @param config {Object}
  * @returns config {Object}
  */
 function validateConfig(config) {
+  debug('Validating config')
   const exampleConfig = Object.assign({}, defaultConfig, {
     linters: {
       '*.js': ['eslint --fix', 'git add'],
@@ -120,11 +129,9 @@ function validateConfig(config) {
   })
 
   const deprecatedConfig = {
-    gitDir: () => `  Option ${chalk.bold('gitDir')} was removed.
-
-  lint-staged now automatically resolves '.git' directory.
-
-  Please remove ${chalk.bold('gitDir')} from your configuration.`
+    gitDir: () => optRmMsg('gitDir', "lint-staged now automatically resolves '.git' directory."),
+    verbose: () =>
+      optRmMsg('verbose', `Use the command line flag ${chalk.bold('--debug')} instead.`)
   }
 
   validate(config, {
diff --git a/src/index.js b/src/index.js
index cb4d2df..8346880 100644
--- a/src/index.js
+++ b/src/index.js
@@ -11,6 +11,8 @@ const validateConfig = require('./getConfig').validateConfig
 const printErrors = require('./printErrors')
 const runAll = require('./runAll')
 
+const debug = require('debug')('lint-staged')
+
 // Find the right package.json at the root of the project
 const packageJson = require(appRoot.resolve('package.json'))
 
@@ -25,7 +27,8 @@ const errConfigNotFound = new Error('Config could not be found')
 /**
  * Root lint-staged function that is called from .bin
  */
-module.exports = function lintStaged(injectedLogger, configPath) {
+module.exports = function lintStaged(injectedLogger, configPath, debugMode) {
+  debug('Loading config using `cosmiconfig`')
   const logger = injectedLogger || console
 
   const explorer = cosmiconfig('lint-staged', {
@@ -39,19 +42,26 @@ module.exports = function lintStaged(injectedLogger, configPath) {
     .then(result => {
       if (result == null) throw errConfigNotFound
 
+      debug('Successfully loaded config from `%s`:\n%O', result.filepath, result.config)
       // result.config is the parsed configuration object
       // result.filepath is the path to the config file that was found
-      const config = validateConfig(getConfig(result.config))
-
-      if (config.verbose) {
+      const config = validateConfig(getConfig(result.config, debugMode))
+      if (debugMode) {
+        // Log using logger to be able to test through `consolemock`.
         logger.log('Running lint-staged with the following config:')
         logger.log(stringifyObject(config, { indent: '  ' }))
+      } else {
+        // We might not be in debug mode but `DEBUG=lint-staged*` could have
+        // been set.
+        debug('Normalized config:\n%O', config)
       }
 
       const scripts = packageJson.scripts || {}
+      debug('Loaded scripts from package.json:\n%O', scripts)
 
-      runAll(scripts, config)
+      runAll(scripts, config, debugMode)
         .then(() => {
+          debug('linters were executed successfully!')
           // No errors, exiting with 0
           process.exitCode = 0
         })
diff --git a/src/runAll.js b/src/runAll.js
index 6985791..c5dc527 100644
--- a/src/runAll.js
+++ b/src/runAll.js
@@ -8,13 +8,16 @@ const runScript = require('./runScript')
 const generateTasks = require('./generateTasks')
 const resolveGitDir = require('./resolveGitDir')
 
+const debug = require('debug')('lint-staged:run')
+
 /**
  * Executes all tasks and either resolves or rejects the promise
  * @param scripts
  * @param config {Object}
  * @returns {Promise}
  */
-module.exports = function runAll(scripts, config) {
+module.exports = function runAll(scripts, config, debugMode) {
+  debug('Running all linter scripts')
   // Config validation
   if (!config || !has(config, 'concurrent') || !has(config, 'renderer')) {
     throw new Error('Invalid config provided to runAll! Use getConfig instead.')
@@ -22,15 +25,19 @@ module.exports = function runAll(scripts, config) {
 
   const concurrent = config.concurrent
   const renderer = config.renderer
-  sgf.cwd = resolveGitDir()
+  const gitDir = resolveGitDir()
+  debug('Resolved git directory to be `%s`', gitDir)
 
+  sgf.cwd = gitDir
   return pify(sgf)('ACM').then(files => {
     /* files is an Object{ filename: String, status: String } */
     const filenames = files.map(file => file.filename)
+    debug('Loaded list of staged files in git:\n%O', filenames)
+
     const tasks = generateTasks(config, filenames).map(task => ({
       title: `Running tasks for ${task.pattern}`,
       task: () =>
-        new Listr(runScript(task.commands, task.fileList, scripts, config), {
+        new Listr(runScript(task.commands, task.fileList, scripts, config, debugMode), {
           // In sub-tasks we don't want to run concurrently
           // and we want to abort on errors
           dateFormat: false,
diff --git a/src/runScript.js b/src/runScript.js
index 8956a85..61b7787 100644
--- a/src/runScript.js
+++ b/src/runScript.js
@@ -10,7 +10,11 @@ const calcChunkSize = require('./calcChunkSize')
 const findBin = require('./findBin')
 const resolveGitDir = require('./resolveGitDir')
 
-module.exports = function runScript(commands, pathsToLint, scripts, config) {
+const debug = require('debug')('lint-staged:run-script')
+
+module.exports = function runScript(commands, pathsToLint, scripts, config, debugMode) {
+  debug('Running script with commands %o', commands)
+
   const normalizedConfig = getConfig(config)
   const chunkSize = normalizedConfig.chunkSize
   const concurrency = normalizedConfig.subTaskConcurrency
@@ -24,7 +28,7 @@ module.exports = function runScript(commands, pathsToLint, scripts, config) {
     title: linter,
     task: () => {
       try {
-        const res = findBin(linter, scripts, config)
+        const res = findBin(linter, scripts, debugMode)
 
         // Only use gitDir as CWD if we are using the git binary
         // e.g `npm` should run tasks in the actual CWD
@@ -35,6 +39,10 @@ module.exports = function runScript(commands, pathsToLint, scripts, config) {
         const mapper = pathsChunk => {
           const args = res.args.concat(pathsChunk)
 
+          debug('bin:', res.bin)
+          debug('args: %O', args)
+          debug('opts: %o', execaOptions)
+
           return (
             execa(res.bin, args, Object.assign({}, execaOptions))
               /* If we don't catch, pMap will terminate on first rejection */


Test patch:
diff --git a/test/__mocks__/my-config.json b/test/__mocks__/my-config.json
index a5695fd..cb997df 100644
--- a/test/__mocks__/my-config.json
+++ b/test/__mocks__/my-config.json
@@ -1,5 +1,4 @@
 {
-  "verbose": true,
   "linters": {
     "*": "mytask"
   }
diff --git a/test/__snapshots__/getConfig.spec.js.snap b/test/__snapshots__/getConfig.spec.js.snap
index 7da8d91..511c5c6 100644
--- a/test/__snapshots__/getConfig.spec.js.snap
+++ b/test/__snapshots__/getConfig.spec.js.snap
@@ -11,7 +11,6 @@ Object {
   "linters": Object {},
   "renderer": "update",
   "subTaskConcurrency": 1,
-  "verbose": false,
 }
 `;
 
@@ -26,7 +25,6 @@ Object {
   "linters": Object {},
   "renderer": "update",
   "subTaskConcurrency": 1,
-  "verbose": false,
 }
 `;
 
@@ -47,7 +45,6 @@ Object {
   },
   "renderer": "update",
   "subTaskConcurrency": 1,
-  "verbose": false,
 }
 `;
 
@@ -72,7 +69,7 @@ WARN ● Validation Warning:
 Please refer to https://github.com/okonet/lint-staged#configuration for more information..."
 `;
 
-exports[`validateConfig should print deprecation warning for gitDir option 1`] = `
+exports[`validateConfig should print deprecation warning for deprecated options 1`] = `
 "
 WARN ● Deprecation Warning:
 
@@ -82,6 +79,15 @@ WARN ● Deprecation Warning:
 
   Please remove gitDir from your configuration.
 
+Please refer to https://github.com/okonet/lint-staged#configuration for more information...
+WARN ● Deprecation Warning:
+
+  Option verbose was removed.
+
+  Use the command line flag --debug instead.
+
+  Please remove verbose from your configuration.
+
 Please refer to https://github.com/okonet/lint-staged#configuration for more information..."
 `;
 
diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap
index dbbb083..39f2d21 100644
--- a/test/__snapshots__/index.spec.js.snap
+++ b/test/__snapshots__/index.spec.js.snap
@@ -4,7 +4,6 @@ exports[`lintStaged should load config file when specified 1`] = `
 "
 LOG Running lint-staged with the following config:
 LOG {
-  verbose: true,
   linters: {
     '*': 'mytask'
   },
@@ -19,13 +18,12 @@ LOG {
 }"
 `;
 
-exports[`lintStaged should not output config in non verbose mode 1`] = `""`;
+exports[`lintStaged should not output config in normal mode 1`] = `""`;
 
-exports[`lintStaged should output config in verbose mode 1`] = `
+exports[`lintStaged should output config in debug mode 1`] = `
 "
 LOG Running lint-staged with the following config:
 LOG {
-  verbose: true,
   linters: {
     '*': 'mytask'
   },
diff --git a/test/findBin.spec.js b/test/findBin.spec.js
index 5ea8246..b5bc6ac 100644
--- a/test/findBin.spec.js
+++ b/test/findBin.spec.js
@@ -11,8 +11,8 @@ describe('findBin', () => {
     expect(args).toEqual(['run', '--silent', 'my-linter', '--'])
   })
 
-  it('should return npm run command without --silent in verbose mode', () => {
-    const { bin, args } = findBin('eslint', { eslint: 'eslint' }, { verbose: true })
+  it('should return npm run command without --silent in debug mode', () => {
+    const { bin, args } = findBin('eslint', { eslint: 'eslint' }, true)
     expect(bin).toEqual('npm')
     expect(args).toEqual(['run', 'eslint', '--'])
   })
diff --git a/test/getConfig.spec.js b/test/getConfig.spec.js
index 35ec7c4..8f14de8 100644
--- a/test/getConfig.spec.js
+++ b/test/getConfig.spec.js
@@ -11,34 +11,6 @@ describe('getConfig', () => {
     expect(getConfig({})).toMatchSnapshot()
   })
 
-  it('should set verbose', () => {
-    expect(getConfig({})).toEqual(
-      expect.objectContaining({
-        verbose: false
-      })
-    )
-
-    expect(
-      getConfig({
-        verbose: false
-      })
-    ).toEqual(
-      expect.objectContaining({
-        verbose: false
-      })
-    )
-
-    expect(
-      getConfig({
-        verbose: true
-      })
-    ).toEqual(
-      expect.objectContaining({
-        verbose: true
-      })
-    )
-  })
-
   it('should set concurrent', () => {
     expect(getConfig({})).toEqual(
       expect.objectContaining({
@@ -67,7 +39,7 @@ describe('getConfig', () => {
     )
   })
 
-  it('should set renderer based on verbose key', () => {
+  it('should set renderer based on debug mode', () => {
     expect(getConfig({})).toEqual(
       expect.objectContaining({
         renderer: 'update'
@@ -84,21 +56,7 @@ describe('getConfig', () => {
       })
     )
 
-    expect(
-      getConfig({
-        verbose: false
-      })
-    ).toEqual(
-      expect.objectContaining({
-        renderer: 'update'
-      })
-    )
-
-    expect(
-      getConfig({
-        verbose: true
-      })
-    ).toEqual(
+    expect(getConfig({}, true)).toEqual(
       expect.objectContaining({
         renderer: 'verbose'
       })
@@ -182,8 +140,7 @@ describe('getConfig', () => {
         '*.js': 'eslint'
       },
       subTaskConcurrency: 10,
-      renderer: 'custom',
-      verbose: true
+      renderer: 'custom'
     }
     expect(getConfig(cloneDeep(src))).toEqual(src)
   })
@@ -220,14 +177,17 @@ describe('validateConfig', () => {
     expect(console.printHistory()).toMatchSnapshot()
   })
 
-  it('should print deprecation warning for gitDir option', () => {
-    const configWithDeprecatedOpt = {
-      gitDir: '../',
+  it('should print deprecation warning for deprecated options', () => {
+    const baseConfig = {
       linters: {
         '*.js': ['eslint --fix', 'git add']
       }
     }
-    expect(() => validateConfig(getConfig(configWithDeprecatedOpt))).not.toThrow()
+    const opts = [{ gitDir: '../' }, { verbose: true }]
+    opts.forEach(opt => {
+      const configWithDeprecatedOpt = Object.assign(opt, baseConfig)
+      expect(() => validateConfig(getConfig(configWithDeprecatedOpt))).not.toThrow()
+    })
     expect(console.printHistory()).toMatchSnapshot()
   })
 
diff --git a/test/index.spec.js b/test/index.spec.js
index c4c95d7..01593a9 100644
--- a/test/index.spec.js
+++ b/test/index.spec.js
@@ -15,29 +15,24 @@ const mockCosmiconfigWith = result => {
 }
 
 describe('lintStaged', () => {
-  let logger
-
-  beforeAll(() => {
-    logger = makeConsoleMock()
-  })
+  const logger = makeConsoleMock()
 
   beforeEach(() => {
     logger.clearHistory()
   })
 
-  it('should output config in verbose mode', async () => {
+  it('should output config in debug mode', async () => {
     const config = {
-      verbose: true,
       linters: {
         '*': 'mytask'
       }
     }
     mockCosmiconfigWith({ config })
-    await lintStaged(logger)
+    await lintStaged(logger, undefined, true)
     expect(logger.printHistory()).toMatchSnapshot()
   })
 
-  it('should not output config in non verbose mode', async () => {
+  it('should not output config in normal mode', async () => {
     const config = {
       '*': 'mytask'
     }
@@ -47,7 +42,7 @@ describe('lintStaged', () => {
   })
 
   it('should load config file when specified', async () => {
-    await lintStaged(logger, path.join(__dirname, '__mocks__', 'my-config.json'))
+    await lintStaged(logger, path.join(__dirname, '__mocks__', 'my-config.json'), true)
     expect(logger.printHistory()).toMatchSnapshot()
   })
 
diff --git a/test/runScript.spec.js b/test/runScript.spec.js
index 2230103..d933212 100644
--- a/test/runScript.spec.js
+++ b/test/runScript.spec.js
@@ -109,15 +109,15 @@ describe('runScript', () => {
     process.cwd = processCwdBkp
   })
 
-  it('should use --silent in non-verbose mode', async () => {
-    const [linter] = runScript('test', ['test.js'], scripts, { verbose: false })
+  it('should use --silent in normal mode', async () => {
+    const [linter] = runScript('test', ['test.js'], scripts, {}, false)
     await linter.task()
     expect(mockFn).toHaveBeenCalledTimes(1)
     expect(mockFn).lastCalledWith('npm', ['run', '--silent', 'test', '--', 'test.js'], {})
   })
 
-  it('should not use --silent in verbose mode', async () => {
-    const [linter] = runScript('test', ['test.js'], scripts, { verbose: true })
+  it('should not use --silent in debug mode', async () => {
+    const [linter] = runScript('test', ['test.js'], scripts, {}, true)
     await linter.task()
     expect(mockFn).toHaveBeenCalledTimes(1)
     expect(mockFn).lastCalledWith('npm', ['run', 'test', '--', 'test.js'], {})