Skip to content

Commit e8291b0

Browse files
committed
feat: expose --max-arg-length cli option
1 parent d8fdf1d commit e8291b0

File tree

3 files changed

+163
-20
lines changed

3 files changed

+163
-20
lines changed

bin/lint-staged.js

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ cmdline
3434
.option('-c, --config [path]', 'path to configuration file, or - to read from stdin')
3535
.option('--cwd [path]', 'run all tasks in specific directory, instead of the current')
3636
.option('-d, --debug', 'print additional debug information', false)
37+
.option('--max-arg-length', 'maximum length of the command-line argument string')
3738
.option('--no-stash', 'disable the backup stash, and do not revert in case of errors', false)
3839
.option('-q, --quiet', 'disable lint-staged’s own console output', false)
3940
.option('-r, --relative', 'pass relative filepaths to tasks', false)
@@ -54,31 +55,13 @@ if (cmdlineOptions.debug) {
5455
const debugLog = debug('lint-staged:bin')
5556
debugLog('Running `lint-staged@%s`', version)
5657

57-
/**
58-
* Get the maximum length of a command-line argument string based on current platform
59-
*
60-
* https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x
61-
* https://support.microsoft.com/en-us/help/830473/command-prompt-cmd-exe-command-line-string-limitation
62-
* https://unix.stackexchange.com/a/120652
63-
*/
64-
const getMaxArgLength = () => {
65-
switch (process.platform) {
66-
case 'darwin':
67-
return 262144
68-
case 'win32':
69-
return 8191
70-
default:
71-
return 131072
72-
}
73-
}
74-
7558
const options = {
7659
allowEmpty: !!cmdlineOptions.allowEmpty,
7760
concurrent: JSON.parse(cmdlineOptions.concurrent),
7861
configPath: cmdlineOptions.config,
7962
cwd: cmdlineOptions.cwd,
8063
debug: !!cmdlineOptions.debug,
81-
maxArgLength: getMaxArgLength() / 2,
64+
maxArgLength: JSON.parse(cmdlineOptions.maxArgLength || null),
8265
quiet: !!cmdlineOptions.quiet,
8366
relative: !!cmdlineOptions.relative,
8467
shell: cmdlineOptions.shell /* Either a boolean or a string pointing to the shell */,

lib/index.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ import { validateOptions } from './validateOptions.js'
1818

1919
const debugLog = debug('lint-staged')
2020

21+
/**
22+
* Get the maximum length of a command-line argument string based on current platform
23+
*
24+
* https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x
25+
* https://support.microsoft.com/en-us/help/830473/command-prompt-cmd-exe-command-line-string-limitation
26+
* https://unix.stackexchange.com/a/120652
27+
*/
28+
const getMaxArgLength = () => {
29+
switch (process.platform) {
30+
case 'darwin':
31+
return 262144
32+
case 'win32':
33+
return 8191
34+
default:
35+
return 131072
36+
}
37+
}
38+
2139
/**
2240
* @typedef {(...any) => void} LogFunction
2341
* @typedef {{ error: LogFunction, log: LogFunction, warn: LogFunction }} Logger
@@ -49,7 +67,7 @@ const lintStaged = async (
4967
configPath,
5068
cwd,
5169
debug = false,
52-
maxArgLength,
70+
maxArgLength = getMaxArgLength() / 2,
5371
quiet = false,
5472
relative = false,
5573
shell = false,

test/index3.spec.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import makeConsoleMock from 'consolemock'
2+
3+
import lintStaged from '../lib/index'
4+
import { runAll } from '../lib/runAll'
5+
import { getInitialState } from '../lib/state'
6+
import { ApplyEmptyCommitError, ConfigNotFoundError, GitError } from '../lib/symbols'
7+
8+
jest.mock('../lib/validateOptions.js', () => ({
9+
validateOptions: jest.fn(async () => {}),
10+
}))
11+
12+
jest.mock('../lib/runAll.js', () => ({
13+
runAll: jest.fn(async () => {}),
14+
}))
15+
16+
describe('lintStaged', () => {
17+
it('should log error when configuration not found', async () => {
18+
const ctx = getInitialState()
19+
ctx.errors.add(ConfigNotFoundError)
20+
runAll.mockImplementationOnce(async () => {
21+
throw { ctx }
22+
})
23+
24+
const logger = makeConsoleMock()
25+
26+
await expect(lintStaged({}, logger)).resolves.toEqual(false)
27+
28+
expect(logger.printHistory()).toMatchInlineSnapshot(`
29+
"
30+
ERROR ✖ No valid configuration found."
31+
`)
32+
})
33+
34+
it('should log error when preventing empty commit', async () => {
35+
const ctx = getInitialState()
36+
ctx.errors.add(ApplyEmptyCommitError)
37+
runAll.mockImplementationOnce(async () => {
38+
throw { ctx }
39+
})
40+
41+
const logger = makeConsoleMock()
42+
43+
await expect(lintStaged({}, logger)).resolves.toEqual(false)
44+
45+
expect(logger.printHistory()).toMatchInlineSnapshot(`
46+
"
47+
WARN
48+
⚠ lint-staged prevented an empty git commit.
49+
Use the --allow-empty option to continue, or check your task configuration
50+
"
51+
`)
52+
})
53+
54+
it('should log error when preventing empty commit', async () => {
55+
const ctx = getInitialState()
56+
ctx.errors.add(ApplyEmptyCommitError)
57+
runAll.mockImplementationOnce(async () => {
58+
throw { ctx }
59+
})
60+
61+
const logger = makeConsoleMock()
62+
63+
await expect(lintStaged({}, logger)).resolves.toEqual(false)
64+
65+
expect(logger.printHistory()).toMatchInlineSnapshot(`
66+
"
67+
WARN
68+
⚠ lint-staged prevented an empty git commit.
69+
Use the --allow-empty option to continue, or check your task configuration
70+
"
71+
`)
72+
})
73+
74+
it('should log error when a git operation failed', async () => {
75+
const ctx = getInitialState()
76+
ctx.shouldBackup = true
77+
ctx.errors.add(GitError)
78+
runAll.mockImplementationOnce(async () => {
79+
throw { ctx }
80+
})
81+
82+
const logger = makeConsoleMock()
83+
84+
await expect(lintStaged({}, logger)).resolves.toEqual(false)
85+
86+
expect(logger.printHistory()).toMatchInlineSnapshot(`
87+
"
88+
ERROR
89+
✖ lint-staged failed due to a git error.
90+
ERROR Any lost modifications can be restored from a git stash:
91+
92+
> git stash list
93+
stash@{0}: automatic lint-staged backup
94+
> git stash apply --index stash@{0}
95+
"
96+
`)
97+
})
98+
99+
it('should throw when context is malformed', async () => {
100+
expect.assertions(2)
101+
102+
const testError = Symbol()
103+
104+
runAll.mockImplementationOnce(async () => {
105+
throw testError
106+
})
107+
108+
const logger = makeConsoleMock()
109+
110+
await lintStaged({}, logger).catch((error) => {
111+
expect(error).toEqual(testError)
112+
})
113+
114+
expect(logger.printHistory()).toMatchInlineSnapshot(`""`)
115+
})
116+
117+
it.each`
118+
platform | maxArgLength
119+
${'darwin'} | ${262144 / 2}
120+
${'win32'} | ${8191 / 2}
121+
${'others'} | ${131072 / 2}
122+
`(
123+
'should use default max arg length of $maxArgLength on $platform',
124+
async ({ platform, maxArgLength }) => {
125+
const realPlatform = process.platform
126+
Object.defineProperty(process, 'platform', {
127+
value: platform,
128+
})
129+
130+
await lintStaged({}, makeConsoleMock())
131+
132+
expect(runAll).toHaveBeenLastCalledWith(
133+
expect.objectContaining({ maxArgLength }),
134+
expect.objectContaining({})
135+
)
136+
137+
Object.defineProperty(process, 'platform', {
138+
value: realPlatform,
139+
})
140+
}
141+
)
142+
})

0 commit comments

Comments
 (0)