Skip to content

Commit

Permalink
feat: expose --max-arg-length cli option
Browse files Browse the repository at this point in the history
  • Loading branch information
iiroj committed Apr 20, 2022
1 parent d8fdf1d commit e8291b0
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 20 deletions.
21 changes: 2 additions & 19 deletions bin/lint-staged.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ cmdline
.option('-c, --config [path]', 'path to configuration file, or - to read from stdin')
.option('--cwd [path]', 'run all tasks in specific directory, instead of the current')
.option('-d, --debug', 'print additional debug information', false)
.option('--max-arg-length', 'maximum length of the command-line argument string')
.option('--no-stash', 'disable the backup stash, and do not revert in case of errors', false)
.option('-q, --quiet', 'disable lint-staged’s own console output', false)
.option('-r, --relative', 'pass relative filepaths to tasks', false)
Expand All @@ -54,31 +55,13 @@ if (cmdlineOptions.debug) {
const debugLog = debug('lint-staged:bin')
debugLog('Running `lint-staged@%s`', version)

/**
* Get the maximum length of a command-line argument string based on current platform
*
* https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x
* https://support.microsoft.com/en-us/help/830473/command-prompt-cmd-exe-command-line-string-limitation
* https://unix.stackexchange.com/a/120652
*/
const getMaxArgLength = () => {
switch (process.platform) {
case 'darwin':
return 262144
case 'win32':
return 8191
default:
return 131072
}
}

const options = {
allowEmpty: !!cmdlineOptions.allowEmpty,
concurrent: JSON.parse(cmdlineOptions.concurrent),
configPath: cmdlineOptions.config,
cwd: cmdlineOptions.cwd,
debug: !!cmdlineOptions.debug,
maxArgLength: getMaxArgLength() / 2,
maxArgLength: JSON.parse(cmdlineOptions.maxArgLength || null),
quiet: !!cmdlineOptions.quiet,
relative: !!cmdlineOptions.relative,
shell: cmdlineOptions.shell /* Either a boolean or a string pointing to the shell */,
Expand Down
20 changes: 19 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ import { validateOptions } from './validateOptions.js'

const debugLog = debug('lint-staged')

/**
* Get the maximum length of a command-line argument string based on current platform
*
* https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x
* https://support.microsoft.com/en-us/help/830473/command-prompt-cmd-exe-command-line-string-limitation
* https://unix.stackexchange.com/a/120652
*/
const getMaxArgLength = () => {
switch (process.platform) {
case 'darwin':
return 262144
case 'win32':
return 8191
default:
return 131072
}
}

/**
* @typedef {(...any) => void} LogFunction
* @typedef {{ error: LogFunction, log: LogFunction, warn: LogFunction }} Logger
Expand Down Expand Up @@ -49,7 +67,7 @@ const lintStaged = async (
configPath,
cwd,
debug = false,
maxArgLength,
maxArgLength = getMaxArgLength() / 2,
quiet = false,
relative = false,
shell = false,
Expand Down
142 changes: 142 additions & 0 deletions test/index3.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import makeConsoleMock from 'consolemock'

import lintStaged from '../lib/index'
import { runAll } from '../lib/runAll'
import { getInitialState } from '../lib/state'
import { ApplyEmptyCommitError, ConfigNotFoundError, GitError } from '../lib/symbols'

jest.mock('../lib/validateOptions.js', () => ({
validateOptions: jest.fn(async () => {}),
}))

jest.mock('../lib/runAll.js', () => ({
runAll: jest.fn(async () => {}),
}))

describe('lintStaged', () => {
it('should log error when configuration not found', async () => {
const ctx = getInitialState()
ctx.errors.add(ConfigNotFoundError)
runAll.mockImplementationOnce(async () => {
throw { ctx }
})

const logger = makeConsoleMock()

await expect(lintStaged({}, logger)).resolves.toEqual(false)

expect(logger.printHistory()).toMatchInlineSnapshot(`
"
ERROR ✖ No valid configuration found."
`)
})

it('should log error when preventing empty commit', async () => {
const ctx = getInitialState()
ctx.errors.add(ApplyEmptyCommitError)
runAll.mockImplementationOnce(async () => {
throw { ctx }
})

const logger = makeConsoleMock()

await expect(lintStaged({}, logger)).resolves.toEqual(false)

expect(logger.printHistory()).toMatchInlineSnapshot(`
"
WARN
⚠ lint-staged prevented an empty git commit.
Use the --allow-empty option to continue, or check your task configuration
"
`)
})

it('should log error when preventing empty commit', async () => {
const ctx = getInitialState()
ctx.errors.add(ApplyEmptyCommitError)
runAll.mockImplementationOnce(async () => {
throw { ctx }
})

const logger = makeConsoleMock()

await expect(lintStaged({}, logger)).resolves.toEqual(false)

expect(logger.printHistory()).toMatchInlineSnapshot(`
"
WARN
⚠ lint-staged prevented an empty git commit.
Use the --allow-empty option to continue, or check your task configuration
"
`)
})

it('should log error when a git operation failed', async () => {
const ctx = getInitialState()
ctx.shouldBackup = true
ctx.errors.add(GitError)
runAll.mockImplementationOnce(async () => {
throw { ctx }
})

const logger = makeConsoleMock()

await expect(lintStaged({}, logger)).resolves.toEqual(false)

expect(logger.printHistory()).toMatchInlineSnapshot(`
"
ERROR
✖ lint-staged failed due to a git error.
ERROR Any lost modifications can be restored from a git stash:
> git stash list
stash@{0}: automatic lint-staged backup
> git stash apply --index stash@{0}
"
`)
})

it('should throw when context is malformed', async () => {
expect.assertions(2)

const testError = Symbol()

runAll.mockImplementationOnce(async () => {
throw testError
})

const logger = makeConsoleMock()

await lintStaged({}, logger).catch((error) => {
expect(error).toEqual(testError)
})

expect(logger.printHistory()).toMatchInlineSnapshot(`""`)
})

it.each`
platform | maxArgLength
${'darwin'} | ${262144 / 2}
${'win32'} | ${8191 / 2}
${'others'} | ${131072 / 2}
`(
'should use default max arg length of $maxArgLength on $platform',
async ({ platform, maxArgLength }) => {
const realPlatform = process.platform
Object.defineProperty(process, 'platform', {
value: platform,
})

await lintStaged({}, makeConsoleMock())

expect(runAll).toHaveBeenLastCalledWith(
expect.objectContaining({ maxArgLength }),
expect.objectContaining({})
)

Object.defineProperty(process, 'platform', {
value: realPlatform,
})
}
)
})

0 comments on commit e8291b0

Please sign in to comment.