lint-staged 10.0.4 → 10.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/file.js +48 -35
- package/lib/getStagedFiles.js +1 -1
- package/lib/gitWorkflow.js +37 -27
- package/lib/index.js +1 -1
- package/lib/makeCmdTasks.js +20 -17
- package/lib/resolveGitRepo.js +26 -22
- package/lib/runAll.js +52 -25
- package/lib/validateConfig.js +2 -15
- package/package.json +1 -1
package/lib/file.js
CHANGED
|
@@ -2,67 +2,80 @@
|
|
|
2
2
|
|
|
3
3
|
const debug = require('debug')('lint-staged:file')
|
|
4
4
|
const fs = require('fs')
|
|
5
|
+
const { promisify } = require('util')
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
+
const fsAccess = promisify(fs.access)
|
|
8
|
+
const fsReadFile = promisify(fs.readFile)
|
|
9
|
+
const fsUnlink = promisify(fs.unlink)
|
|
10
|
+
const fsWriteFile = promisify(fs.writeFile)
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
|
-
* Check if a file exists. Returns the
|
|
10
|
-
* @param {
|
|
13
|
+
* Check if a file exists. Returns the filename if exists.
|
|
14
|
+
* @param {String} filename
|
|
15
|
+
* @returns {String|Boolean}
|
|
11
16
|
*/
|
|
12
|
-
const exists = async
|
|
17
|
+
const exists = async filename => {
|
|
13
18
|
try {
|
|
14
|
-
await
|
|
15
|
-
return
|
|
19
|
+
await fsAccess(filename)
|
|
20
|
+
return filename
|
|
16
21
|
} catch {
|
|
17
22
|
return false
|
|
18
23
|
}
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
/**
|
|
27
|
+
* Read contents of a file to buffer
|
|
22
28
|
* @param {String} filename
|
|
23
|
-
* @
|
|
29
|
+
* @param {Boolean} [ignoreENOENT=true] — Whether to throw if the file doesn't exist
|
|
30
|
+
* @returns {Promise<Buffer>}
|
|
24
31
|
*/
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
}
|
|
32
|
+
const readFile = async (filename, ignoreENOENT = true) => {
|
|
33
|
+
debug('Reading file `%s`', filename)
|
|
34
|
+
try {
|
|
35
|
+
return await fsReadFile(filename)
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (ignoreENOENT && error.code === 'ENOENT') {
|
|
38
|
+
debug("File `%s` doesn't exist, ignoring...", filename)
|
|
39
|
+
return null // no-op file doesn't exist
|
|
40
|
+
} else {
|
|
41
|
+
throw error
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
37
45
|
|
|
38
46
|
/**
|
|
39
47
|
* Unlink a file if it exists
|
|
40
|
-
* @param {
|
|
48
|
+
* @param {String} filename
|
|
49
|
+
* @param {Boolean} [ignoreENOENT=true] — Whether to throw if the file doesn't exist
|
|
41
50
|
*/
|
|
42
|
-
const unlink = async
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
const unlink = async (filename, ignoreENOENT = true) => {
|
|
52
|
+
if (filename) {
|
|
53
|
+
debug('Unlinking file `%s`', filename)
|
|
54
|
+
try {
|
|
55
|
+
await fsUnlink(filename)
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (ignoreENOENT && error.code === 'ENOENT') {
|
|
58
|
+
debug("File `%s` doesn't exist, ignoring...", filename)
|
|
59
|
+
} else {
|
|
60
|
+
throw error
|
|
61
|
+
}
|
|
62
|
+
}
|
|
46
63
|
}
|
|
47
64
|
}
|
|
48
65
|
|
|
49
66
|
/**
|
|
67
|
+
* Write buffer to file
|
|
50
68
|
* @param {String} filename
|
|
51
69
|
* @param {Buffer} buffer
|
|
52
|
-
* @returns {Promise<Void>}
|
|
53
70
|
*/
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
debug('Done writing buffer to file `%s`!', filename)
|
|
59
|
-
resolve()
|
|
60
|
-
})
|
|
61
|
-
})
|
|
71
|
+
const writeFile = async (filename, buffer) => {
|
|
72
|
+
debug('Writing file `%s`', filename)
|
|
73
|
+
await fsWriteFile(filename, buffer)
|
|
74
|
+
}
|
|
62
75
|
|
|
63
76
|
module.exports = {
|
|
64
77
|
exists,
|
|
65
|
-
|
|
78
|
+
readFile,
|
|
66
79
|
unlink,
|
|
67
|
-
|
|
80
|
+
writeFile
|
|
68
81
|
}
|
package/lib/getStagedFiles.js
CHANGED
package/lib/gitWorkflow.js
CHANGED
|
@@ -4,7 +4,7 @@ const debug = require('debug')('lint-staged:git')
|
|
|
4
4
|
const path = require('path')
|
|
5
5
|
|
|
6
6
|
const execGit = require('./execGit')
|
|
7
|
-
const { exists,
|
|
7
|
+
const { exists, readFile, unlink, writeFile } = require('./file')
|
|
8
8
|
|
|
9
9
|
const MERGE_HEAD = 'MERGE_HEAD'
|
|
10
10
|
const MERGE_MODE = 'MERGE_MODE'
|
|
@@ -18,23 +18,6 @@ const PATCH_UNTRACKED = 'lint-staged_untracked.patch'
|
|
|
18
18
|
const GIT_APPLY_ARGS = ['apply', '-v', '--whitespace=nowarn', '--recount', '--unidiff-zero']
|
|
19
19
|
const GIT_DIFF_ARGS = ['--binary', '--unified=0', '--no-color', '--no-ext-diff', '--patch']
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
* Delete untracked files using `git clean`
|
|
23
|
-
* @param {Function} execGit function for executing git commands using execa
|
|
24
|
-
* @returns {Promise<void>}
|
|
25
|
-
*/
|
|
26
|
-
const cleanUntrackedFiles = async execGit => {
|
|
27
|
-
const untrackedFiles = await execGit(['ls-files', '--others', '--exclude-standard'])
|
|
28
|
-
if (untrackedFiles) {
|
|
29
|
-
debug('Detected unstaged, untracked files: ', untrackedFiles)
|
|
30
|
-
debug(
|
|
31
|
-
'This is probably due to a bug in git =< 2.13.0 where `git stash --keep-index` resurrects deleted files.'
|
|
32
|
-
)
|
|
33
|
-
debug('Deleting the files using `git clean`...')
|
|
34
|
-
await execGit(['clean', '--force', ...untrackedFiles.split('\n')])
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
21
|
const handleError = (error, ctx) => {
|
|
39
22
|
ctx.gitError = true
|
|
40
23
|
throw error
|
|
@@ -44,6 +27,7 @@ class GitWorkflow {
|
|
|
44
27
|
constructor({ allowEmpty, gitConfigDir, gitDir, stagedFileChunks }) {
|
|
45
28
|
this.execGit = (args, options = {}) => execGit(args, { ...options, cwd: gitDir })
|
|
46
29
|
this.gitConfigDir = gitConfigDir
|
|
30
|
+
this.gitDir = gitDir
|
|
47
31
|
this.unstagedDiff = null
|
|
48
32
|
this.allowEmpty = allowEmpty
|
|
49
33
|
this.stagedFileChunks = stagedFileChunks
|
|
@@ -73,7 +57,7 @@ class GitWorkflow {
|
|
|
73
57
|
const resolved = this.getHiddenFilepath(filename)
|
|
74
58
|
const pathIfExists = await exists(resolved)
|
|
75
59
|
if (!pathIfExists) return false
|
|
76
|
-
const buffer = await
|
|
60
|
+
const buffer = await readFile(pathIfExists)
|
|
77
61
|
const patch = buffer.toString().trim()
|
|
78
62
|
return patch.length ? filename : false
|
|
79
63
|
}
|
|
@@ -97,9 +81,9 @@ class GitWorkflow {
|
|
|
97
81
|
async backupMergeStatus() {
|
|
98
82
|
debug('Backing up merge state...')
|
|
99
83
|
await Promise.all([
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
84
|
+
readFile(this.mergeHeadFilename).then(buffer => (this.mergeHeadBuffer = buffer)),
|
|
85
|
+
readFile(this.mergeModeFilename).then(buffer => (this.mergeModeBuffer = buffer)),
|
|
86
|
+
readFile(this.mergeMsgFilename).then(buffer => (this.mergeMsgBuffer = buffer))
|
|
103
87
|
])
|
|
104
88
|
debug('Done backing up merge state!')
|
|
105
89
|
}
|
|
@@ -111,9 +95,9 @@ class GitWorkflow {
|
|
|
111
95
|
debug('Restoring merge state...')
|
|
112
96
|
try {
|
|
113
97
|
await Promise.all([
|
|
114
|
-
this.mergeHeadBuffer &&
|
|
115
|
-
this.mergeModeBuffer &&
|
|
116
|
-
this.mergeMsgBuffer &&
|
|
98
|
+
this.mergeHeadBuffer && writeFile(this.mergeHeadFilename, this.mergeHeadBuffer),
|
|
99
|
+
this.mergeModeBuffer && writeFile(this.mergeModeFilename, this.mergeModeBuffer),
|
|
100
|
+
this.mergeMsgBuffer && writeFile(this.mergeMsgFilename, this.mergeMsgBuffer)
|
|
117
101
|
])
|
|
118
102
|
debug('Done restoring merge state!')
|
|
119
103
|
} catch (error) {
|
|
@@ -123,6 +107,18 @@ class GitWorkflow {
|
|
|
123
107
|
}
|
|
124
108
|
}
|
|
125
109
|
|
|
110
|
+
/**
|
|
111
|
+
* List and delete untracked files
|
|
112
|
+
*/
|
|
113
|
+
async cleanUntrackedFiles() {
|
|
114
|
+
const lsFiles = await this.execGit(['ls-files', '--others', '--exclude-standard'])
|
|
115
|
+
const untrackedFiles = lsFiles
|
|
116
|
+
.split('\n')
|
|
117
|
+
.filter(Boolean)
|
|
118
|
+
.map(file => path.resolve(this.gitDir, file))
|
|
119
|
+
await Promise.all(untrackedFiles.map(file => unlink(file)))
|
|
120
|
+
}
|
|
121
|
+
|
|
126
122
|
/**
|
|
127
123
|
* Create backup stashes, one of everything and one of only staged changes
|
|
128
124
|
* Staged files are left in the index for running tasks
|
|
@@ -135,6 +131,14 @@ class GitWorkflow {
|
|
|
135
131
|
// Manually check and backup if necessary
|
|
136
132
|
await this.backupMergeStatus()
|
|
137
133
|
|
|
134
|
+
// Get a list of unstaged deleted files, because certain bugs might cause them to reappear:
|
|
135
|
+
// - in git versions =< 2.13.0 the `--keep-index` flag resurrects deleted files
|
|
136
|
+
// - git stash can't infer RD or MD states correctly, and will lose the deletion
|
|
137
|
+
this.deletedFiles = (await this.execGit(['ls-files', '--deleted']))
|
|
138
|
+
.split('\n')
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.map(file => path.resolve(this.gitDir, file))
|
|
141
|
+
|
|
138
142
|
// Save stash of entire original state, including unstaged and untracked changes.
|
|
139
143
|
// `--keep-index leaves only staged files on disk, for tasks.`
|
|
140
144
|
await this.execGit(['stash', 'save', '--include-untracked', '--keep-index', STASH])
|
|
@@ -144,7 +148,7 @@ class GitWorkflow {
|
|
|
144
148
|
|
|
145
149
|
// There is a bug in git =< 2.13.0 where `--keep-index` resurrects deleted files.
|
|
146
150
|
// These files should be listed and deleted before proceeding.
|
|
147
|
-
await cleanUntrackedFiles(
|
|
151
|
+
await this.cleanUntrackedFiles()
|
|
148
152
|
|
|
149
153
|
// Get a diff of unstaged changes by diffing the saved stash against what's left on disk.
|
|
150
154
|
await this.execGit([
|
|
@@ -238,6 +242,9 @@ class GitWorkflow {
|
|
|
238
242
|
ctx.gitRestoreUntrackedError = true
|
|
239
243
|
handleError(error, ctx)
|
|
240
244
|
}
|
|
245
|
+
|
|
246
|
+
// If stashing resurrected deleted files, clean them out
|
|
247
|
+
await Promise.all(this.deletedFiles.map(file => unlink(file)))
|
|
241
248
|
}
|
|
242
249
|
|
|
243
250
|
/**
|
|
@@ -251,9 +258,13 @@ class GitWorkflow {
|
|
|
251
258
|
await this.execGit(['stash', 'apply', '--quiet', '--index', backupStash])
|
|
252
259
|
debug('Done restoring original state!')
|
|
253
260
|
|
|
261
|
+
// If stashing resurrected deleted files, clean them out
|
|
262
|
+
await Promise.all(this.deletedFiles.map(file => unlink(file)))
|
|
263
|
+
|
|
254
264
|
// Restore meta information about ongoing git merge
|
|
255
265
|
await this.restoreMergeStatus()
|
|
256
266
|
} catch (error) {
|
|
267
|
+
ctx.gitRestoreOriginalStateError = true
|
|
257
268
|
handleError(error, ctx)
|
|
258
269
|
}
|
|
259
270
|
}
|
|
@@ -278,4 +289,3 @@ class GitWorkflow {
|
|
|
278
289
|
}
|
|
279
290
|
|
|
280
291
|
module.exports = GitWorkflow
|
|
281
|
-
module.exports.cleanUntrackedFiles = cleanUntrackedFiles
|
package/lib/index.js
CHANGED
package/lib/makeCmdTasks.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const resolveTaskFn = require('./resolveTaskFn')
|
|
4
|
+
const { createError } = require('./validateConfig')
|
|
4
5
|
|
|
5
6
|
const debug = require('debug')('lint-staged:make-cmd-tasks')
|
|
6
7
|
|
|
@@ -15,32 +16,34 @@ const debug = require('debug')('lint-staged:make-cmd-tasks')
|
|
|
15
16
|
*/
|
|
16
17
|
module.exports = async function makeCmdTasks({ commands, files, gitDir, shell }) {
|
|
17
18
|
debug('Creating listr tasks for commands %o', commands)
|
|
18
|
-
const
|
|
19
|
+
const commandArray = Array.isArray(commands) ? commands : [commands]
|
|
19
20
|
const cmdTasks = []
|
|
20
21
|
|
|
21
|
-
for (const cmd of
|
|
22
|
+
for (const cmd of commandArray) {
|
|
22
23
|
// command function may return array of commands that already include `stagedFiles`
|
|
23
24
|
const isFn = typeof cmd === 'function'
|
|
24
25
|
const resolved = isFn ? await cmd(files) : cmd
|
|
25
26
|
|
|
26
27
|
const resolvedArray = Array.isArray(resolved) ? resolved : [resolved] // Wrap non-array command as array
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
// because the resolved string it might be very long
|
|
30
|
-
// Create a matching command array with [file] in place of file names
|
|
31
|
-
let mockCmdTasks
|
|
32
|
-
if (isFn) {
|
|
33
|
-
const mockFileList = Array(files.length).fill('[file]')
|
|
34
|
-
const resolved = await cmd(mockFileList)
|
|
35
|
-
mockCmdTasks = Array.isArray(resolved) ? resolved : [resolved]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
for (const [i, command] of resolvedArray.entries()) {
|
|
29
|
+
for (const command of resolvedArray) {
|
|
39
30
|
let title = isFn ? '[Function]' : command
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
|
|
31
|
+
|
|
32
|
+
if (isFn) {
|
|
33
|
+
// If the function linter didn't return string | string[] it won't work
|
|
34
|
+
// Do the validation here instead of `validateConfig` to skip evaluating the function multiple times
|
|
35
|
+
if (typeof command !== 'string') {
|
|
36
|
+
throw new Error(
|
|
37
|
+
createError(
|
|
38
|
+
title,
|
|
39
|
+
'Function task should return a string or an array of strings',
|
|
40
|
+
resolved
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const [startOfFn] = command.split(' ')
|
|
46
|
+
title += ` ${startOfFn} ...` // Append function name, like `[Function] eslint ...`
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
cmdTasks.push({
|
package/lib/resolveGitRepo.js
CHANGED
|
@@ -1,48 +1,52 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const normalize = require('normalize-path')
|
|
4
|
+
const debugLog = require('debug')('lint-staged:resolveGitRepo')
|
|
5
|
+
const fs = require('fs')
|
|
4
6
|
const path = require('path')
|
|
7
|
+
const { promisify } = require('util')
|
|
5
8
|
|
|
6
9
|
const execGit = require('./execGit')
|
|
7
|
-
const {
|
|
10
|
+
const { readFile } = require('./file')
|
|
11
|
+
|
|
12
|
+
const fsLstat = promisify(fs.lstat)
|
|
8
13
|
|
|
9
14
|
/**
|
|
10
15
|
* Resolve path to the .git directory, with special handling for
|
|
11
|
-
* submodules
|
|
16
|
+
* submodules and worktrees
|
|
12
17
|
*/
|
|
13
|
-
const resolveGitConfigDir = async
|
|
18
|
+
const resolveGitConfigDir = async gitDir => {
|
|
14
19
|
const defaultDir = path.resolve(gitDir, '.git')
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
return
|
|
20
|
+
const stats = await fsLstat(defaultDir)
|
|
21
|
+
// If .git is a directory, use it
|
|
22
|
+
if (stats.isDirectory()) return defaultDir
|
|
23
|
+
// Otherwise .git is a file containing path to real location
|
|
24
|
+
const file = (await readFile(defaultDir)).toString()
|
|
25
|
+
return path.resolve(gitDir, file.replace(/^gitdir: /, '')).trim()
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
/**
|
|
24
29
|
* Resolve git directory and possible submodule paths
|
|
25
30
|
*/
|
|
26
|
-
|
|
31
|
+
const resolveGitRepo = async cwd => {
|
|
27
32
|
try {
|
|
33
|
+
debugLog('Resolving git repo from `%s`', cwd)
|
|
28
34
|
// git cli uses GIT_DIR to fast track its response however it might be set to a different path
|
|
29
35
|
// depending on where the caller initiated this from, hence clear GIT_DIR
|
|
36
|
+
debugLog('Deleting GIT_DIR from env with value `%s`', process.env.GIT_DIR)
|
|
30
37
|
delete process.env.GIT_DIR
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
const
|
|
39
|
+
const gitDir = normalize(await execGit(['rev-parse', '--show-toplevel'], { cwd }))
|
|
40
|
+
const gitConfigDir = normalize(await resolveGitConfigDir(gitDir))
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
['rev-parse', '--show-superproject-working-tree'],
|
|
38
|
-
options
|
|
39
|
-
)
|
|
42
|
+
debugLog('Resolved git directory to be `%s`', gitDir)
|
|
43
|
+
debugLog('Resolved git config directory to be `%s`', gitConfigDir)
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
const gitConfigDir = await resolveGitConfigDir({ gitDir, isSubmodule })
|
|
43
|
-
|
|
44
|
-
return { gitDir: normalize(gitDir), gitConfigDir, isSubmodule }
|
|
45
|
+
return { gitDir, gitConfigDir }
|
|
45
46
|
} catch (error) {
|
|
46
|
-
|
|
47
|
+
debugLog('Failed to resolve git repo with error:', error)
|
|
48
|
+
return { error, gitDir: null, gitConfigDir: null }
|
|
47
49
|
}
|
|
48
50
|
}
|
|
51
|
+
|
|
52
|
+
module.exports = resolveGitRepo
|
package/lib/runAll.js
CHANGED
|
@@ -23,6 +23,40 @@ const getRenderer = ({ debug, quiet }) => {
|
|
|
23
23
|
return 'update'
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
const MESSAGES = {
|
|
27
|
+
TASK_ERROR: 'Skipped because of errors from tasks.',
|
|
28
|
+
GIT_ERROR: 'Skipped because of previous git error.'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const shouldSkipApplyModifications = ctx => {
|
|
32
|
+
// Should be skipped in case of git errors
|
|
33
|
+
if (ctx.gitError) {
|
|
34
|
+
return MESSAGES.GIT_ERROR
|
|
35
|
+
}
|
|
36
|
+
// Should be skipped when tasks fail
|
|
37
|
+
if (ctx.taskError) {
|
|
38
|
+
return MESSAGES.TASK_ERROR
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const shouldSkipRevert = ctx => {
|
|
43
|
+
// Should be skipped in case of unknown git errors
|
|
44
|
+
if (ctx.gitError && !ctx.gitApplyEmptyCommit && !ctx.gitApplyModificationsError) {
|
|
45
|
+
return MESSAGES.GIT_ERROR
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const shouldSkipCleanup = ctx => {
|
|
50
|
+
// Should be skipped in case of unknown git errors
|
|
51
|
+
if (ctx.gitError && !ctx.gitApplyEmptyCommit && !ctx.gitApplyModificationsError) {
|
|
52
|
+
return MESSAGES.GIT_ERROR
|
|
53
|
+
}
|
|
54
|
+
// Should be skipped when reverting to original state fails
|
|
55
|
+
if (ctx.gitRestoreOriginalStateError) {
|
|
56
|
+
return MESSAGES.GIT_ERROR
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
26
60
|
/**
|
|
27
61
|
* Executes all tasks and either resolves or rejects the promise
|
|
28
62
|
*
|
|
@@ -39,7 +73,7 @@ const getRenderer = ({ debug, quiet }) => {
|
|
|
39
73
|
* @param {Logger} logger
|
|
40
74
|
* @returns {Promise}
|
|
41
75
|
*/
|
|
42
|
-
|
|
76
|
+
const runAll = async (
|
|
43
77
|
{
|
|
44
78
|
allowEmpty = false,
|
|
45
79
|
config,
|
|
@@ -52,14 +86,11 @@ module.exports = async function runAll(
|
|
|
52
86
|
concurrent = true
|
|
53
87
|
},
|
|
54
88
|
logger = console
|
|
55
|
-
) {
|
|
89
|
+
) => {
|
|
56
90
|
debugLog('Running all linter scripts')
|
|
57
91
|
|
|
58
|
-
const { gitDir, gitConfigDir
|
|
92
|
+
const { gitDir, gitConfigDir } = await resolveGitRepo(cwd)
|
|
59
93
|
if (!gitDir) throw new Error('Current directory is not a git directory!')
|
|
60
|
-
debugLog('Resolved git directory to be `%s`', gitDir)
|
|
61
|
-
debugLog('Resolved git config directory to be `%s`', gitConfigDir)
|
|
62
|
-
if (isSubmodule) debugLog('Current git directory is a submodule')
|
|
63
94
|
|
|
64
95
|
const files = await getStagedFiles({ cwd: gitDir })
|
|
65
96
|
if (!files) throw new Error('Unable to get staged files!')
|
|
@@ -130,7 +161,7 @@ module.exports = async function runAll(
|
|
|
130
161
|
task: () => new Listr(chunkListrTasks, { ...listrOptions, concurrent }),
|
|
131
162
|
skip: (ctx = {}) => {
|
|
132
163
|
// Skip if the first step (backup) failed
|
|
133
|
-
if (ctx.gitError) return
|
|
164
|
+
if (ctx.gitError) return MESSAGES.GIT_ERROR
|
|
134
165
|
// Skip chunk when no every task is skipped (due to no matches)
|
|
135
166
|
if (chunkListrTasks.every(task => task.skip())) return 'No tasks to run.'
|
|
136
167
|
return false
|
|
@@ -154,15 +185,6 @@ module.exports = async function runAll(
|
|
|
154
185
|
|
|
155
186
|
const git = new GitWorkflow({ allowEmpty, gitConfigDir, gitDir, stagedFileChunks })
|
|
156
187
|
|
|
157
|
-
// Running git reset or dropping the backup stash should be skipped
|
|
158
|
-
// when there are git errors NOT related to applying unstaged modifications.
|
|
159
|
-
// In the latter case, the original state is restored.
|
|
160
|
-
const cleanupNotSafe = ctx =>
|
|
161
|
-
ctx.gitError &&
|
|
162
|
-
!ctx.gitApplyEmptyCommit &&
|
|
163
|
-
!ctx.gitApplyModificationsError &&
|
|
164
|
-
'Skipped because of previous git error.'
|
|
165
|
-
|
|
166
188
|
const runner = new Listr(
|
|
167
189
|
[
|
|
168
190
|
{
|
|
@@ -172,22 +194,19 @@ module.exports = async function runAll(
|
|
|
172
194
|
...listrTasks,
|
|
173
195
|
{
|
|
174
196
|
title: 'Applying modifications...',
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (ctx.taskError) return 'Skipped because of errors from tasks.'
|
|
178
|
-
},
|
|
179
|
-
task: ctx => git.applyModifications(ctx)
|
|
197
|
+
task: ctx => git.applyModifications(ctx),
|
|
198
|
+
skip: shouldSkipApplyModifications
|
|
180
199
|
},
|
|
181
200
|
{
|
|
182
201
|
title: 'Reverting to original state...',
|
|
202
|
+
task: ctx => git.restoreOriginalState(ctx),
|
|
183
203
|
enabled: ctx => ctx.taskError || ctx.gitApplyEmptyCommit || ctx.gitApplyModificationsError,
|
|
184
|
-
skip:
|
|
185
|
-
task: ctx => git.restoreOriginalState(ctx)
|
|
204
|
+
skip: shouldSkipRevert
|
|
186
205
|
},
|
|
187
206
|
{
|
|
188
207
|
title: 'Cleaning up...',
|
|
189
|
-
|
|
190
|
-
|
|
208
|
+
task: ctx => git.dropBackup(ctx),
|
|
209
|
+
skip: shouldSkipCleanup
|
|
191
210
|
}
|
|
192
211
|
],
|
|
193
212
|
listrOptions
|
|
@@ -222,3 +241,11 @@ module.exports = async function runAll(
|
|
|
222
241
|
throw error
|
|
223
242
|
}
|
|
224
243
|
}
|
|
244
|
+
|
|
245
|
+
module.exports = runAll
|
|
246
|
+
|
|
247
|
+
module.exports.shouldSkip = {
|
|
248
|
+
shouldSkipApplyModifications,
|
|
249
|
+
shouldSkipRevert,
|
|
250
|
+
shouldSkipCleanup
|
|
251
|
+
}
|
package/lib/validateConfig.js
CHANGED
|
@@ -80,21 +80,6 @@ module.exports = function validateConfig(config) {
|
|
|
80
80
|
)
|
|
81
81
|
)
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
entries.forEach(([, task]) => {
|
|
85
|
-
if (typeof task !== 'function') return
|
|
86
|
-
const resolved = task(['[filename]'])
|
|
87
|
-
if (typeof resolved === 'string') return
|
|
88
|
-
if (!Array.isArray(resolved) || resolved.some(subtask => typeof subtask !== 'string')) {
|
|
89
|
-
errors.push(
|
|
90
|
-
createError(
|
|
91
|
-
task,
|
|
92
|
-
'Function task should return a string or an array of strings',
|
|
93
|
-
resolved
|
|
94
|
-
)
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
})
|
|
98
83
|
})
|
|
99
84
|
}
|
|
100
85
|
|
|
@@ -104,3 +89,5 @@ module.exports = function validateConfig(config) {
|
|
|
104
89
|
|
|
105
90
|
return config
|
|
106
91
|
}
|
|
92
|
+
|
|
93
|
+
module.exports.createError = createError
|