'use strict' const sgf = require('staged-git-files') const Listr = require('listr') const has = require('lodash/has') const pify = require('pify') const makeCmdTasks = require('./makeCmdTasks') const generateTasks = require('./generateTasks') const resolveGitDir = require('./resolveGitDir') const git = require('./gitWorkflow') const debug = require('debug')('lint-staged:run') /** * Executes all tasks and either resolves or rejects the promise * @param config {Object} * @returns {Promise} */ module.exports = function runAll(config) { debug('Running all linter scripts') // Config validation if (!config || !has(config, 'concurrent') || !has(config, 'renderer')) { throw new Error('Invalid config provided to runAll! Use getConfig instead.') } const { concurrent, renderer, chunkSize, subTaskConcurrency } = config const gitDir = resolveGitDir() debug('Resolved git directory to be `%s`', gitDir) sgf.cwd = gitDir return pify(sgf)('ACM').then(files => { /* files is an Object{ filename: String, status: String } */ const filenames = files.map(file => file.filename) debug('Loaded list of staged files in git:\n%O', filenames) const tasks = generateTasks(config, filenames).map(task => ({ title: `Running tasks for ${task.pattern}`, task: () => new Listr( makeCmdTasks(task.commands, task.fileList, { chunkSize, subTaskConcurrency }), { // In sub-tasks we don't want to run concurrently // and we want to abort on errors dateFormat: false, concurrent: false, exitOnError: true } ), skip: () => { if (task.fileList.length === 0) { return `No staged files match ${task.pattern}` } return false } })) const listrBaseOptions = { dateFormat: false, renderer } // If all of the configured "linters" should be skipped // avoid executing any lint-staged logic if (tasks.every(task => task.skip())) { console.log('No staged files match any of provided globs.') return 'No tasks to run.' } // Do not terminate main Listr process on SIGINT process.on('SIGINT', () => {}) return new Listr( [ { title: 'Stashing changes...', skip: async () => { const hasPSF = await git.hasPartiallyStagedFiles() if (!hasPSF) { return 'No partially staged files found...' } return false }, task: ctx => { ctx.hasStash = true return git.gitStashSave() } }, { title: 'Running linters...', task: () => new Listr(tasks, { ...listrBaseOptions, concurrent, exitOnError: !concurrent // Wait for all errors when running concurrently }) }, { title: 'Updating stash...', enabled: ctx => ctx.hasStash, skip: ctx => ctx.hasErrors && 'Skipping stash update since some tasks exited with errors', task: () => git.updateStash() }, { title: 'Restoring local changes...', enabled: ctx => ctx.hasStash, task: () => git.gitStashPop() } ], listrBaseOptions ).run() }) }