diff --git a/.lintstagedrc.json b/.lintstagedrc.json index e52d997e7..144f4ebbf 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,5 +1,5 @@ { - "*.{js,json,md}": ["prettier --write"], - "*.js": ["npm run lint:base --fix"], - ".*{rc, json}": ["jsonlint --in-place"] + "*.{js,json,md}": "prettier --write", + "*.js": "npm run lint:base --fix", + ".*{rc, json}": "jsonlint --in-place" } diff --git a/lib/makeCmdTasks.js b/lib/makeCmdTasks.js index 958ac9230..d68dea7a5 100644 --- a/lib/makeCmdTasks.js +++ b/lib/makeCmdTasks.js @@ -11,9 +11,10 @@ const debug = require('debug')('lint-staged:make-cmd-tasks') * @param {Array|string|Function} options.commands * @param {Array} options.files * @param {string} options.gitDir + * @param {Function} [options.logger] * @param {Boolean} shell */ -module.exports = async function makeCmdTasks({ commands, files, gitDir, shell }) { +module.exports = async function makeCmdTasks({ commands, files, gitDir, logger, shell }) { debug('Creating listr tasks for commands %o', commands) const commandsArray = Array.isArray(commands) ? commands : [commands] @@ -41,7 +42,7 @@ module.exports = async function makeCmdTasks({ commands, files, gitDir, shell }) title = mockCommands[i].replace(/\[file\].*\[file\]/, '[file]') } - const task = { title, task: resolveTaskFn({ gitDir, isFn, command, files, shell }) } + const task = { title, task: resolveTaskFn({ command, files, gitDir, isFn, logger, shell }) } tasks.push(task) }) diff --git a/lib/resolveTaskFn.js b/lib/resolveTaskFn.js index 39d999629..f9be525ad 100644 --- a/lib/resolveTaskFn.js +++ b/lib/resolveTaskFn.js @@ -62,14 +62,30 @@ function makeErr(linter, result, context = {}) { * @param {String} options.gitDir - Current git repo path * @param {Boolean} options.isFn - Whether the linter task is a function * @param {Array} options.files — Filepaths to run the linter task against + * @param {Function} [options.logger] * @param {Boolean} [options.relative] — Whether the filepaths should be relative * @param {Boolean} [options.shell] — Whether to skip parsing linter task for better shell support * @returns {function(): Promise>} */ -module.exports = function resolveTaskFn({ command, files, gitDir, isFn, relative, shell = false }) { +module.exports = function resolveTaskFn({ + command, + files, + gitDir, + isFn, + logger, + relative, + shell = false +}) { const cmd = isFn ? command : `${command} ${files.join(' ')}` debug('cmd:', cmd) + if (logger && cmd.includes('git add')) { + logger.warn(` + ${symbols.warning} ${chalk.yellow( + `Detected a task using \`git add\`. Lint-staged version 10 will automatically add any task modifications to the git index, and you should remove this command.` + )}`) + } + const execaOptions = { preferLocal: true, reject: false, shell } if (relative) { execaOptions.cwd = process.cwd() diff --git a/lib/runAll.js b/lib/runAll.js index 2704ed0e7..20d9b9ad7 100644 --- a/lib/runAll.js +++ b/lib/runAll.js @@ -72,7 +72,13 @@ module.exports = async function runAll( title: `Running tasks for ${task.pattern}`, task: async () => new Listr( - await makeCmdTasks({ commands: task.commands, files: task.fileList, gitDir, shell }), + await makeCmdTasks({ + commands: task.commands, + files: task.fileList, + gitDir, + logger, + shell + }), { // In sub-tasks we don't want to run concurrently // and we want to abort on errors diff --git a/test/makeCmdTasks.spec.js b/test/makeCmdTasks.spec.js index f1121b256..0c94e1d65 100644 --- a/test/makeCmdTasks.spec.js +++ b/test/makeCmdTasks.spec.js @@ -1,4 +1,5 @@ import execa from 'execa' + import makeCmdTasks from '../lib/makeCmdTasks' describe('makeCmdTasks', () => { diff --git a/test/resolveTaskFn.spec.js b/test/resolveTaskFn.spec.js index 11f482709..cd038a59b 100644 --- a/test/resolveTaskFn.spec.js +++ b/test/resolveTaskFn.spec.js @@ -1,4 +1,6 @@ import execa from 'execa' +import makeConsoleMock from 'consolemock' + import resolveTaskFn from '../lib/resolveTaskFn' const defaultOpts = { files: ['test.js'] } @@ -80,13 +82,13 @@ describe('resolveTaskFn', () => { expect.assertions(2) const taskFn = resolveTaskFn({ ...defaultOpts, - command: 'git add', + command: 'git diff', gitDir: '../' }) await taskFn() expect(execa).toHaveBeenCalledTimes(1) - expect(execa).lastCalledWith('git add test.js', { + expect(execa).lastCalledWith('git diff test.js', { cwd: '../', preferLocal: true, reject: false, @@ -111,13 +113,13 @@ describe('resolveTaskFn', () => { expect.assertions(2) const taskFn = resolveTaskFn({ ...defaultOpts, - command: 'git add', + command: 'git diff', relative: true }) await taskFn() expect(execa).toHaveBeenCalledTimes(1) - expect(execa).lastCalledWith('git add test.js', { + expect(execa).lastCalledWith('git diff test.js', { cwd: process.cwd(), preferLocal: true, reject: false, @@ -140,12 +142,12 @@ describe('resolveTaskFn', () => { await taskFn() } catch (err) { expect(err.privateMsg).toMatchInlineSnapshot(` -" + " -× mock-fail-linter found some errors. Please fix them and try committing again. -Mock error" -`) + × mock-fail-linter found some errors. Please fix them and try committing again. + Mock error" + `) } }) @@ -166,11 +168,11 @@ Mock error" await taskFn() } catch (err) { expect(err.privateMsg).toMatchInlineSnapshot(` -" + " -‼ mock-killed-linter was terminated with SIGINT" -`) + ‼ mock-killed-linter was terminated with SIGINT" + `) } }) @@ -199,4 +201,19 @@ Mock error" expect(context.hasErrors).toEqual(true) } }) + + it('should warn when tasks include git add', async () => { + const logger = makeConsoleMock() + await resolveTaskFn({ + ...defaultOpts, + command: 'git add', + logger, + relative: true + }) + expect(logger.printHistory()).toMatchInlineSnapshot(` + " + WARN + ‼ Detected a task using \`git add\`. Lint-staged version 10 will automatically add any task modifications to the git index, and you should remove this command." + `) + }) }) diff --git a/test/runAll.unmocked.spec.js b/test/runAll.unmocked.spec.js index 8c693e6ad..044c54dee 100644 --- a/test/runAll.unmocked.spec.js +++ b/test/runAll.unmocked.spec.js @@ -339,16 +339,18 @@ describe('runAll', () => { } catch (error) { expect(error.message).toMatch('Another git process seems to be running in this repository') expect(console.printHistory()).toMatchInlineSnapshot(` - " - ERROR - × lint-staged failed due to a git error. - Any lost modifications can be restored from a git stash: - - > git stash list - stash@{0}: On master: automatic lint-staged backup - > git stash pop stash@{0} - " - `) + " + WARN + ‼ Detected a task using \`git add\`. Lint-staged version 10 will automatically add any task modifications to the git index, and you should remove this command. + ERROR + × lint-staged failed due to a git error. + Any lost modifications can be restored from a git stash: + + > git stash list + stash@{0}: On master: automatic lint-staged backup + > git stash pop stash@{0} + " + `) } // Something was wrong so new commit wasn't created @@ -358,17 +360,17 @@ describe('runAll', () => { // But local modifications are gone expect(await execGit(['diff'])).not.toEqual(diff) expect(await execGit(['diff'])).toMatchInlineSnapshot(` - "diff --git a/test.js b/test.js - index f80f875..1c5643c 100644 - --- a/test.js - +++ b/test.js - @@ -1,3 +1,3 @@ - module.exports = { - - 'foo': 'bar', - -} - + foo: \\"bar\\" - +};" - `) + "diff --git a/test.js b/test.js + index f80f875..1c5643c 100644 + --- a/test.js + +++ b/test.js + @@ -1,3 +1,3 @@ + module.exports = { + - 'foo': 'bar', + -} + + foo: \\"bar\\" + +};" + `) expect(await readFile('test.js')).not.toEqual(testJsFileUgly + appended) expect(await readFile('test.js')).toEqual(testJsFilePretty) @@ -422,13 +424,13 @@ describe('runAll', () => { } expect(await readFile('test.js')).toMatchInlineSnapshot(` - "<<<<<<< HEAD - module.exports = \\"foo\\"; - ======= - module.exports = \\"bar\\"; - >>>>>>> branch-b - " - `) + "<<<<<<< HEAD + module.exports = \\"foo\\"; + ======= + module.exports = \\"bar\\"; + >>>>>>> branch-b + " + `) // Fix conflict and commit using lint-staged await writeFile('test.js', fileInBranchB) @@ -442,12 +444,12 @@ describe('runAll', () => { // Nothing is wrong, so a new commit is created and file is pretty expect(await execGit(['rev-list', '--count', 'HEAD'])).toEqual('4') expect(await execGit(['log', '-1', '--pretty=%B'])).toMatchInlineSnapshot(` - "Merge branch 'branch-b' + "Merge branch 'branch-b' - # Conflicts: - # test.js - " - `) + # Conflicts: + # test.js + " + `) expect(await readFile('test.js')).toEqual(fileInBranchBFixed) }) @@ -488,13 +490,13 @@ describe('runAll', () => { expect(await execGit(['rev-list', '--count', 'HEAD'])).toEqual('1') expect(await execGit(['log', '-1', '--pretty=%B'])).toMatch('initial commit') expect(await readFile('README.md')).toMatchInlineSnapshot(` - "# Test + "# Test - ## Amended + ## Amended - ## Edited - " - `) + ## Edited + " + `) expect(await readFile('test-untracked.js')).toEqual(testJsFilePretty) const status = await execGit(['status']) expect(status).toMatch('modified: README.md')