Skip to content

Commit

Permalink
fix: all lint-staged output respects the quiet option
Browse files Browse the repository at this point in the history
  • Loading branch information
iiroj committed Apr 27, 2020
1 parent b8df31a commit aba3421
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 24 deletions.
7 changes: 5 additions & 2 deletions lib/resolveTaskFn.js
Expand Up @@ -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)
}
}

Expand Down
10 changes: 5 additions & 5 deletions lib/runAll.js
Expand Up @@ -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)
}
Expand All @@ -95,15 +95,15 @@ 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)
}
debugLog('Loaded list of staged files in git:\n%O', files)

// 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
}

Expand Down Expand Up @@ -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
}

Expand Down
3 changes: 2 additions & 1 deletion lib/state.js
Expand Up @@ -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
Expand Down
22 changes: 6 additions & 16 deletions test/__snapshots__/index.spec.js.snap
Expand Up @@ -5,31 +5,25 @@ 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`] = `
"
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`] = `
Expand All @@ -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`] = `
Expand Down Expand Up @@ -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`] = `
"
Expand Down
4 changes: 4 additions & 0 deletions test/gitWorkflow.spec.js
Expand Up @@ -91,6 +91,7 @@ describe('gitWorkflow', () => {
},
"hasPartiallyStagedFiles": true,
"output": Array [],
"quiet": false,
"shouldBackup": null,
}
`)
Expand All @@ -115,6 +116,7 @@ describe('gitWorkflow', () => {
},
"hasPartiallyStagedFiles": null,
"output": Array [],
"quiet": false,
"shouldBackup": null,
}
`)
Expand All @@ -141,6 +143,7 @@ describe('gitWorkflow', () => {
},
"hasPartiallyStagedFiles": null,
"output": Array [],
"quiet": false,
"shouldBackup": null,
}
`)
Expand All @@ -167,6 +170,7 @@ describe('gitWorkflow', () => {
},
"hasPartiallyStagedFiles": null,
"output": Array [],
"quiet": false,
"shouldBackup": null,
}
`)
Expand Down
2 changes: 2 additions & 0 deletions test/index2.spec.js
Expand Up @@ -28,6 +28,7 @@ describe('lintStaged', () => {
"errors": Set {},
"hasPartiallyStagedFiles": null,
"output": Array [],
"quiet": true,
"shouldBackup": true,
},
"dateFormat": false,
Expand All @@ -52,6 +53,7 @@ describe('lintStaged', () => {
"errors": Set {},
"hasPartiallyStagedFiles": null,
"output": Array [],
"quiet": false,
"shouldBackup": true,
},
"dateFormat": false,
Expand Down
10 changes: 10 additions & 0 deletions test/integration.test.js
Expand Up @@ -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
Expand Down
85 changes: 85 additions & 0 deletions test/resolveTaskFn.spec.js
Expand Up @@ -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({
Expand All @@ -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,
}
`)
Expand Down
21 changes: 21 additions & 0 deletions test/runAll.spec.js
Expand Up @@ -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,
}
`)
Expand All @@ -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'])
Expand Down

0 comments on commit aba3421

Please sign in to comment.