From aba3421b0ec7335e49bc3f06a71441037bb2ae8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iiro=20J=C3=A4ppinen?= Date: Mon, 27 Apr 2020 15:35:12 +0300 Subject: [PATCH] fix: all lint-staged output respects the `quiet` option --- lib/resolveTaskFn.js | 7 ++- lib/runAll.js | 10 ++-- lib/state.js | 3 +- test/__snapshots__/index.spec.js.snap | 22 ++----- test/gitWorkflow.spec.js | 4 ++ test/index2.spec.js | 2 + test/integration.test.js | 10 ++++ test/resolveTaskFn.spec.js | 85 +++++++++++++++++++++++++++ test/runAll.spec.js | 21 +++++++ 9 files changed, 140 insertions(+), 24 deletions(-) diff --git a/lib/resolveTaskFn.js b/lib/resolveTaskFn.js index 4a3efb19a..8c67a6937 100644 --- a/lib/resolveTaskFn.js +++ b/lib/resolveTaskFn.js @@ -30,13 +30,16 @@ const handleOutput = (command, result, ctx, isError = false) => { if (hasOutput) { const outputTitle = isError ? redBright(`${error} ${command}:`) : `${info} ${command}:` - const output = ['', outputTitle].concat(stderr ? [stderr] : []).concat(stdout ? [stdout] : []) + const output = [] + .concat(ctx.quiet ? [] : ['', outputTitle]) + .concat(stderr ? stderr : []) + .concat(stdout ? stdout : []) ctx.output.push(output.join('\n')) } else if (isError) { // Show generic error when task had no output const tag = getTag(result) const message = redBright(`\n${error} ${command} failed without output (${tag}).`) - ctx.output.push(message) + if (!ctx.quiet) ctx.output.push(message) } } diff --git a/lib/runAll.js b/lib/runAll.js index f0e60b6d6..d2fafb6fd 100644 --- a/lib/runAll.js +++ b/lib/runAll.js @@ -72,11 +72,11 @@ const runAll = async ( ) => { debugLog('Running all linter scripts') - const ctx = getInitialState() + const ctx = getInitialState({ quiet }) const { gitDir, gitConfigDir } = await resolveGitRepo(cwd) if (!gitDir) { - ctx.output.push(NOT_GIT_REPO) + if (!quiet) ctx.output.push(NOT_GIT_REPO) ctx.errors.add(GitRepoError) throw createError(ctx) } @@ -95,7 +95,7 @@ const runAll = async ( const files = await getStagedFiles({ cwd: gitDir }) if (!files) { - ctx.output.push(FAILED_GET_STAGED_FILES) + if (!quiet) ctx.output.push(FAILED_GET_STAGED_FILES) ctx.errors.add(GetStagedFilesError) throw createError(ctx, GetStagedFilesError) } @@ -103,7 +103,7 @@ const runAll = async ( // If there are no files avoid executing any lint-staged logic if (files.length === 0) { - ctx.output.push(NO_STAGED_FILES) + if (!quiet) ctx.output.push(NO_STAGED_FILES) return ctx } @@ -189,7 +189,7 @@ const runAll = async ( // If all of the configured tasks should be skipped // avoid executing any lint-staged logic if (listrTasks.every((task) => task.skip())) { - ctx.output.push(NO_TASKS) + if (!quiet) ctx.output.push(NO_TASKS) return ctx } diff --git a/lib/state.js b/lib/state.js index 21311e386..1485968cc 100644 --- a/lib/state.js +++ b/lib/state.js @@ -9,11 +9,12 @@ const { RestoreUnstagedChangesError, } = require('./symbols') -const getInitialState = () => ({ +const getInitialState = ({ quiet = false } = {}) => ({ hasPartiallyStagedFiles: null, shouldBackup: null, errors: new Set([]), output: [], + quiet, }) const hasPartiallyStagedFiles = (ctx) => ctx.hasPartiallyStagedFiles diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index f29b66693..fab8a387c 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -5,8 +5,7 @@ exports[`lintStaged should load an npm config package when specified 1`] = ` LOG Running lint-staged with the following config: LOG { '*': 'mytask' -} -ERROR × Failed to get staged files!" +}" `; exports[`lintStaged should load config file when specified 1`] = ` @@ -14,22 +13,17 @@ exports[`lintStaged should load config file when specified 1`] = ` LOG Running lint-staged with the following config: LOG { '*': 'mytask' -} -ERROR × Failed to get staged files!" +}" `; -exports[`lintStaged should not output config in normal mode 1`] = ` -" -ERROR × Failed to get staged files!" -`; +exports[`lintStaged should not output config in normal mode 1`] = `""`; exports[`lintStaged should output config in debug mode 1`] = ` " LOG Running lint-staged with the following config: LOG { '*': 'mytask' -} -ERROR × Failed to get staged files!" +}" `; exports[`lintStaged should parse function linter from js config 1`] = ` @@ -38,8 +32,7 @@ LOG Running lint-staged with the following config: LOG { '*.css': filenames => \`echo \${filenames.join(' ')}\`, '*.js': filenames => filenames.map(filename => \`echo \${filename}\`) -} -ERROR × Failed to get staged files!" +}" `; exports[`lintStaged should print helpful error message when config file is not found 2`] = ` @@ -70,10 +63,7 @@ ERROR Please make sure you have created it correctly. See https://github.com/okonet/lint-staged#configuration." `; -exports[`lintStaged should use config object 1`] = ` -" -ERROR × Failed to get staged files!" -`; +exports[`lintStaged should use config object 1`] = `""`; exports[`lintStaged should use cosmiconfig if no params are passed 1`] = ` " diff --git a/test/gitWorkflow.spec.js b/test/gitWorkflow.spec.js index 3a94d650b..e63ad5cdb 100644 --- a/test/gitWorkflow.spec.js +++ b/test/gitWorkflow.spec.js @@ -91,6 +91,7 @@ describe('gitWorkflow', () => { }, "hasPartiallyStagedFiles": true, "output": Array [], + "quiet": false, "shouldBackup": null, } `) @@ -115,6 +116,7 @@ describe('gitWorkflow', () => { }, "hasPartiallyStagedFiles": null, "output": Array [], + "quiet": false, "shouldBackup": null, } `) @@ -141,6 +143,7 @@ describe('gitWorkflow', () => { }, "hasPartiallyStagedFiles": null, "output": Array [], + "quiet": false, "shouldBackup": null, } `) @@ -167,6 +170,7 @@ describe('gitWorkflow', () => { }, "hasPartiallyStagedFiles": null, "output": Array [], + "quiet": false, "shouldBackup": null, } `) diff --git a/test/index2.spec.js b/test/index2.spec.js index a5d87146b..95c28ea52 100644 --- a/test/index2.spec.js +++ b/test/index2.spec.js @@ -28,6 +28,7 @@ describe('lintStaged', () => { "errors": Set {}, "hasPartiallyStagedFiles": null, "output": Array [], + "quiet": true, "shouldBackup": true, }, "dateFormat": false, @@ -52,6 +53,7 @@ describe('lintStaged', () => { "errors": Set {}, "hasPartiallyStagedFiles": null, "output": Array [], + "quiet": false, "shouldBackup": true, }, "dateFormat": false, diff --git a/test/integration.test.js b/test/integration.test.js index b14a994ac..df4847af0 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -90,6 +90,16 @@ describe('lint-staged', () => { `) await removeTempDir(nonGitDir) }) + + it('should fail without output when not in a git directory and quiet', async () => { + const nonGitDir = await createTempDir() + const logger = makeConsoleMock() + await expect( + lintStaged({ ...fixJsConfig, cwd: nonGitDir, quiet: true }, logger) + ).resolves.toEqual(false) + expect(logger.printHistory()).toMatchInlineSnapshot(`""`) + await removeTempDir(nonGitDir) + }) }) const globalConsoleTemp = console diff --git a/test/resolveTaskFn.spec.js b/test/resolveTaskFn.spec.js index e01a4a66f..82b077655 100644 --- a/test/resolveTaskFn.spec.js +++ b/test/resolveTaskFn.spec.js @@ -203,6 +203,32 @@ describe('resolveTaskFn', () => { expect(context.errors.has(TaskError)).toEqual(true) }) + it('should not add output when there is none', async () => { + expect.assertions(2) + execa.mockResolvedValueOnce({ + stdout: '', + stderr: '', + code: 0, + failed: false, + killed: false, + signal: undefined, + cmd: 'mock cmd', + }) + + const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock cmd', verbose: true }) + const context = getInitialState() + await expect(taskFn(context)).resolves.toMatchInlineSnapshot(`undefined`) + expect(context).toMatchInlineSnapshot(` + Object { + "errors": Set {}, + "hasPartiallyStagedFiles": null, + "output": Array [], + "quiet": false, + "shouldBackup": null, + } + `) + }) + it('should add output even when task succeeds if `verbose: true`', async () => { expect.assertions(2) execa.mockResolvedValueOnce({ @@ -227,6 +253,65 @@ describe('resolveTaskFn', () => { i mock cmd: Mock success", ], + "quiet": false, + "shouldBackup": null, + } + `) + }) + + it('should not add title to output when task errors while quiet', async () => { + expect.assertions(2) + execa.mockResolvedValueOnce({ + stdout: '', + stderr: 'stderr', + code: 1, + failed: true, + killed: false, + signal: undefined, + cmd: 'mock cmd', + }) + + const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock cmd' }) + const context = getInitialState({ quiet: true }) + await expect(taskFn(context)).rejects.toThrowErrorMatchingInlineSnapshot(`"mock cmd [1]"`) + expect(context).toMatchInlineSnapshot(` + Object { + "errors": Set { + Symbol(TaskError), + }, + "hasPartiallyStagedFiles": null, + "output": Array [ + "stderr", + ], + "quiet": true, + "shouldBackup": null, + } + `) + }) + + it('should not print anything when task errors without output while quiet', async () => { + expect.assertions(2) + execa.mockResolvedValueOnce({ + stdout: '', + stderr: '', + code: 1, + failed: true, + killed: false, + signal: undefined, + cmd: 'mock cmd', + }) + + const taskFn = resolveTaskFn({ ...defaultOpts, command: 'mock cmd' }) + const context = getInitialState({ quiet: true }) + await expect(taskFn(context)).rejects.toThrowErrorMatchingInlineSnapshot(`"mock cmd [1]"`) + expect(context).toMatchInlineSnapshot(` + Object { + "errors": Set { + Symbol(TaskError), + }, + "hasPartiallyStagedFiles": null, + "output": Array [], + "quiet": true, "shouldBackup": null, } `) diff --git a/test/runAll.spec.js b/test/runAll.spec.js index 5c6d26d3b..87e9f6dc5 100644 --- a/test/runAll.spec.js +++ b/test/runAll.spec.js @@ -45,6 +45,20 @@ describe('runAll', () => { "output": Array [ "i No staged files found.", ], + "quiet": false, + "shouldBackup": true, + } + `) + }) + + it('should not print output when no staged files and quiet', async () => { + expect.assertions(1) + await expect(runAll({ config: {}, quiet: true })).resolves.toMatchInlineSnapshot(` + Object { + "errors": Set {}, + "hasPartiallyStagedFiles": null, + "output": Array [], + "quiet": true, "shouldBackup": true, } `) @@ -63,6 +77,13 @@ describe('runAll', () => { expect(logger.printHistory()).toMatchInlineSnapshot(`""`) }) + it('should exit without output when no staged files match configured tasks and quiet', async () => { + expect.assertions(1) + getStagedFiles.mockImplementationOnce(async () => ['sample.js']) + await runAll({ config: { '*.css': ['echo "sample"'] }, quiet: true }) + expect(console.printHistory()).toMatchInlineSnapshot(`""`) + }) + it('should not skip tasks if there are files', async () => { expect.assertions(1) getStagedFiles.mockImplementationOnce(async () => ['sample.js'])