UNPKG

4.33 kBJavaScriptView Raw
1'use strict'
2
3/** @typedef {import('./index').Logger} Logger */
4
5const chalk = require('chalk')
6const dedent = require('dedent')
7const Listr = require('listr')
8const symbols = require('log-symbols')
9
10const generateTasks = require('./generateTasks')
11const getStagedFiles = require('./getStagedFiles')
12const git = require('./gitWorkflow')
13const makeCmdTasks = require('./makeCmdTasks')
14const resolveGitDir = require('./resolveGitDir')
15
16const debug = require('debug')('lint-staged:run')
17
18/**
19 * https://serverfault.com/questions/69430/what-is-the-maximum-length-of-a-command-line-in-mac-os-x
20 * https://support.microsoft.com/en-us/help/830473/command-prompt-cmd-exe-command-line-string-limitation
21 * https://unix.stackexchange.com/a/120652
22 */
23const MAX_ARG_LENGTH =
24 (process.platform === 'darwin' && 262144) || (process.platform === 'win32' && 8191) || 131072
25
26/**
27 * Executes all tasks and either resolves or rejects the promise
28 *
29 * @param config {Object}
30 * @param {Boolean} [shellMode] Use execa’s shell mode to execute linter commands
31 * @param {Boolean} [quietMode] Use Listr’s silent renderer
32 * @param {Boolean} [debugMode] Enable debug mode
33 * @param {Logger} logger
34 * @returns {Promise}
35 */
36module.exports = async function runAll(
37 config,
38 shellMode = false,
39 quietMode = false,
40 debugMode = false,
41 logger = console
42) {
43 debug('Running all linter scripts')
44
45 const gitDir = await resolveGitDir(config)
46
47 if (!gitDir) {
48 throw new Error('Current directory is not a git directory!')
49 }
50
51 debug('Resolved git directory to be `%s`', gitDir)
52
53 const files = await getStagedFiles({ cwd: gitDir })
54
55 if (!files) {
56 throw new Error('Unable to get staged files!')
57 }
58
59 debug('Loaded list of staged files in git:\n%O', files)
60
61 const argLength = files.join(' ').length
62 if (argLength > MAX_ARG_LENGTH) {
63 logger.warn(
64 dedent`${symbols.warning} ${chalk.yellow(
65 `lint-staged generated an argument string of ${argLength} characters, and commands might not run correctly on your platform.
66It is recommended to use functions as linters and split your command based on the number of staged files. For more info, please visit:
67https://github.com/okonet/lint-staged#using-js-functions-to-customize-linter-commands
68 `
69 )}`
70 )
71 }
72
73 const tasks = (await generateTasks(config, gitDir, files)).map(task => ({
74 title: `Running tasks for ${task.pattern}`,
75 task: async () =>
76 new Listr(await makeCmdTasks(task.commands, shellMode, gitDir, task.fileList), {
77 // In sub-tasks we don't want to run concurrently
78 // and we want to abort on errors
79 dateFormat: false,
80 concurrent: false,
81 exitOnError: true
82 }),
83 skip: () => {
84 if (task.fileList.length === 0) {
85 return `No staged files match ${task.pattern}`
86 }
87 return false
88 }
89 }))
90
91 const listrOptions = {
92 dateFormat: false,
93 renderer: (quietMode && 'silent') || (debugMode && 'verbose') || 'update'
94 }
95
96 // If all of the configured "linters" should be skipped
97 // avoid executing any lint-staged logic
98 if (tasks.every(task => task.skip())) {
99 logger.log('No staged files match any of provided globs.')
100 return 'No tasks to run.'
101 }
102
103 // Do not terminate main Listr process on SIGINT
104 process.on('SIGINT', () => {})
105
106 return new Listr(
107 [
108 {
109 title: 'Stashing changes...',
110 skip: async () => {
111 const hasPSF = await git.hasPartiallyStagedFiles({ cwd: gitDir })
112 if (!hasPSF) {
113 return 'No partially staged files found...'
114 }
115 return false
116 },
117 task: ctx => {
118 ctx.hasStash = true
119 return git.gitStashSave({ cwd: gitDir })
120 }
121 },
122 {
123 title: 'Running linters...',
124 task: () => new Listr(tasks, { ...listrOptions, concurrent: true, exitOnError: false })
125 },
126 {
127 title: 'Updating stash...',
128 enabled: ctx => ctx.hasStash,
129 skip: ctx => ctx.hasErrors && 'Skipping stash update since some tasks exited with errors',
130 task: () => git.updateStash({ cwd: gitDir })
131 },
132 {
133 title: 'Restoring local changes...',
134 enabled: ctx => ctx.hasStash,
135 task: () => git.gitStashPop({ cwd: gitDir })
136 }
137 ],
138 listrOptions
139 ).run()
140}