diff --git a/lib/gitWorkflow.js b/lib/gitWorkflow.js index 8cd971cd1..e79578b1b 100644 --- a/lib/gitWorkflow.js +++ b/lib/gitWorkflow.js @@ -176,7 +176,7 @@ class GitWorkflow { /** * Create a diff of partially staged files and backup stash if enabled. */ - async prepare(ctx, shouldBackup) { + async prepare(ctx) { try { debug('Backing up original state...') @@ -194,7 +194,7 @@ class GitWorkflow { /** * If backup stash should be skipped, no need to continue */ - if (!shouldBackup) return + if (!ctx.shouldBackup) return // When backup is enabled, the revert will clear ongoing merge status. await this.backupMergeStatus() diff --git a/lib/messages.js b/lib/messages.js index c7cd7b156..d5a99fdf3 100644 --- a/lib/messages.js +++ b/lib/messages.js @@ -17,7 +17,9 @@ const DEPRECATED_GIT_ADD = `${symbols.warning} ${chalk.yellow( const TASK_ERROR = 'Skipped because of errors from tasks.' -const GIT_ERROR = 'Skipped because of previous git error.' +const SKIPPED_GIT_ERROR = 'Skipped because of previous git error.' + +const GIT_ERROR = `\n ${symbols.error} ${chalk.red(`lint-staged failed due to a git error.`)}` const PREVENTED_EMPTY_COMMIT = ` ${symbols.warning} ${chalk.yellow(`lint-staged prevented an empty git commit. @@ -36,6 +38,7 @@ module.exports = { skippingBackup, DEPRECATED_GIT_ADD, TASK_ERROR, + SKIPPED_GIT_ERROR, GIT_ERROR, PREVENTED_EMPTY_COMMIT, RESTORE_STASH_EXAMPLE diff --git a/lib/runAll.js b/lib/runAll.js index 02cd4b569..c6ee040dc 100644 --- a/lib/runAll.js +++ b/lib/runAll.js @@ -2,9 +2,7 @@ /** @typedef {import('./index').Logger} Logger */ -const chalk = require('chalk') const { Listr } = require('listr2') -const symbols = require('log-symbols') const chunkFiles = require('./chunkFiles') const execGit = require('./execGit') @@ -18,18 +16,19 @@ const { NO_STAGED_FILES, PREVENTED_EMPTY_COMMIT, RESTORE_STASH_EXAMPLE, - TASK_ERROR, + SKIPPED_GIT_ERROR, skippingBackup } = require('./messages') const resolveGitRepo = require('./resolveGitRepo') +const { ApplyEmptyCommitError, GetBackupStashError, GitError } = require('./symbols') const { - ApplyEmptyCommitError, - TaskError, - RestoreOriginalStateError, - GetBackupStashError, - GitError, - RestoreUnstagedChangesError -} = require('./symbols') + applyModificationsSkipped, + cleanupSkipped, + hasPartiallyStagedFiles, + restoreOriginalStateEnabled, + restoreOriginalStateSkipped, + restoreUnstagedChangesSkipped +} = require('./state') const debugLog = require('debug')('lint-staged:run') @@ -41,43 +40,6 @@ const getRenderer = ({ debug, quiet }) => { return 'update' } -const shouldSkipApplyModifications = (ctx) => { - // Should be skipped in case of git errors - if (ctx.errors.has(GitError)) { - return GIT_ERROR - } - // Should be skipped when tasks fail - if (ctx.errors.has(TaskError)) { - return TASK_ERROR - } -} - -const shouldSkipRevert = (ctx) => { - // Should be skipped in case of unknown git errors - if ( - ctx.errors.has(GitError) && - !ctx.errors.has(ApplyEmptyCommitError) && - !ctx.errors.has(RestoreUnstagedChangesError) - ) { - return GIT_ERROR - } -} - -const shouldSkipCleanup = (ctx) => { - // Should be skipped in case of unknown git errors - if ( - ctx.errors.has(GitError) && - !ctx.errors.has(ApplyEmptyCommitError) && - !ctx.errors.has(RestoreUnstagedChangesError) - ) { - return GIT_ERROR - } - // Should be skipped when reverting to original state fails - if (ctx.errors.has(RestoreOriginalStateError)) { - return GIT_ERROR - } -} - /** * Executes all tasks and either resolves or rejects the promise * @@ -146,6 +108,7 @@ const runAll = async ( const listrCtx = { hasPartiallyStagedFiles: false, + shouldBackup, errors: new Set([]) } @@ -208,7 +171,7 @@ const runAll = async ( task: () => new Listr(chunkListrTasks, { ...listrOptions, concurrent }), skip: () => { // Skip if the first step (backup) failed - if (listrCtx.errors.has(GitError)) return GIT_ERROR + if (listrCtx.errors.has(GitError)) return SKIPPED_GIT_ERROR // Skip chunk when no every task is skipped (due to no matches) if (chunkListrTasks.every((task) => task.skip())) return 'No tasks to run.' return false @@ -233,41 +196,36 @@ const runAll = async ( [ { title: 'Preparing...', - task: (ctx) => git.prepare(ctx, shouldBackup) + task: (ctx) => git.prepare(ctx) }, { title: 'Hiding unstaged changes to partially staged files...', task: (ctx) => git.hideUnstagedChanges(ctx), - enabled: (ctx) => ctx.hasPartiallyStagedFiles + enabled: hasPartiallyStagedFiles }, ...listrTasks, { title: 'Applying modifications...', task: (ctx) => git.applyModifications(ctx), - // Always apply back unstaged modifications when skipping backup - skip: (ctx) => shouldBackup && shouldSkipApplyModifications(ctx) + skip: applyModificationsSkipped }, { title: 'Restoring unstaged changes to partially staged files...', task: (ctx) => git.restoreUnstagedChanges(ctx), - enabled: (ctx) => ctx.hasPartiallyStagedFiles, - skip: shouldSkipApplyModifications + enabled: hasPartiallyStagedFiles, + skip: restoreUnstagedChangesSkipped }, { title: 'Reverting to original state because of errors...', task: (ctx) => git.restoreOriginalState(ctx), - enabled: (ctx) => - shouldBackup && - (ctx.errors.has(TaskError) || - ctx.errors.has(ApplyEmptyCommitError) || - ctx.errors.has(RestoreUnstagedChangesError)), - skip: shouldSkipRevert + enabled: restoreOriginalStateEnabled, + skip: restoreOriginalStateSkipped }, { title: 'Cleaning up...', task: (ctx) => git.cleanup(ctx), enabled: () => shouldBackup, - skip: shouldSkipCleanup + skip: cleanupSkipped } ], listrOptions @@ -279,8 +237,7 @@ const runAll = async ( if (context.errors.has(ApplyEmptyCommitError)) { logger.warn(PREVENTED_EMPTY_COMMIT) } else if (context.errors.has(GitError) && !context.errors.has(GetBackupStashError)) { - logger.error(`\n ${symbols.error} ${chalk.red(`lint-staged failed due to a git error.`)}`) - + logger.error(GIT_ERROR) if (shouldBackup) { // No sense to show this if the backup stash itself is missing. logger.error(RESTORE_STASH_EXAMPLE) @@ -292,10 +249,3 @@ const runAll = async ( } module.exports = runAll - -// Exported for testing -module.exports.shouldSkip = { - shouldSkipApplyModifications, - shouldSkipRevert, - shouldSkipCleanup -} diff --git a/lib/state.js b/lib/state.js new file mode 100644 index 000000000..0edefd8a8 --- /dev/null +++ b/lib/state.js @@ -0,0 +1,77 @@ +'use strict' + +const { GIT_ERROR, TASK_ERROR } = require('./messages') +const { + ApplyEmptyCommitError, + TaskError, + RestoreOriginalStateError, + GitError, + RestoreUnstagedChangesError +} = require('./symbols') + +const hasPartiallyStagedFiles = (ctx) => ctx.hasPartiallyStagedFiles + +const applyModificationsSkipped = (ctx) => { + // Always apply back unstaged modifications when skipping backup + if (!ctx.shouldBackup) return false + // Should be skipped in case of git errors + if (ctx.errors.has(GitError)) { + return GIT_ERROR + } + // Should be skipped when tasks fail + if (ctx.errors.has(TaskError)) { + return TASK_ERROR + } +} + +const restoreUnstagedChangesSkipped = (ctx) => { + // Should be skipped in case of git errors + if (ctx.errors.has(GitError)) { + return GIT_ERROR + } + // Should be skipped when tasks fail + if (ctx.errors.has(TaskError)) { + return TASK_ERROR + } +} + +const restoreOriginalStateEnabled = (ctx) => + ctx.shouldBackup && + (ctx.errors.has(TaskError) || + ctx.errors.has(ApplyEmptyCommitError) || + ctx.errors.has(RestoreUnstagedChangesError)) + +const restoreOriginalStateSkipped = (ctx) => { + // Should be skipped in case of unknown git errors + if ( + ctx.errors.has(GitError) && + !ctx.errors.has(ApplyEmptyCommitError) && + !ctx.errors.has(RestoreUnstagedChangesError) + ) { + return GIT_ERROR + } +} + +const cleanupSkipped = (ctx) => { + // Should be skipped in case of unknown git errors + if ( + ctx.errors.has(GitError) && + !ctx.errors.has(ApplyEmptyCommitError) && + !ctx.errors.has(RestoreUnstagedChangesError) + ) { + return GIT_ERROR + } + // Should be skipped when reverting to original state fails + if (ctx.errors.has(RestoreOriginalStateError)) { + return GIT_ERROR + } +} + +module.exports = { + hasPartiallyStagedFiles, + applyModificationsSkipped, + restoreUnstagedChangesSkipped, + restoreOriginalStateEnabled, + restoreOriginalStateSkipped, + cleanupSkipped +} diff --git a/test/index2.spec.js b/test/index2.spec.js index 6c1590948..71eaa271e 100644 --- a/test/index2.spec.js +++ b/test/index2.spec.js @@ -27,6 +27,7 @@ describe('lintStaged', () => { "ctx": Object { "errors": Set {}, "hasPartiallyStagedFiles": false, + "shouldBackup": true, }, "dateFormat": false, "exitOnError": false, @@ -49,6 +50,7 @@ describe('lintStaged', () => { "ctx": Object { "errors": Set {}, "hasPartiallyStagedFiles": false, + "shouldBackup": true, }, "dateFormat": false, "exitOnError": false, diff --git a/test/runAll.spec.js b/test/runAll.spec.js index 2d73bca67..d005ae014 100644 --- a/test/runAll.spec.js +++ b/test/runAll.spec.js @@ -6,8 +6,8 @@ import path from 'path' import getStagedFiles from '../lib/getStagedFiles' import GitWorkflow from '../lib/gitWorkflow' import resolveGitRepo from '../lib/resolveGitRepo' -import runAll, { shouldSkip } from '../lib/runAll' -import { GitError, RestoreOriginalStateError } from '../lib/symbols' +import runAll from '../lib/runAll' +import { GitError } from '../lib/symbols' jest.mock('../lib/file') jest.mock('../lib/getStagedFiles') @@ -190,26 +190,3 @@ describe('runAll', () => { `) }) }) - -describe('shouldSkip', () => { - describe('shouldSkipApplyModifications', () => { - it('should return error message when there is an unkown git error', () => { - const result = shouldSkip.shouldSkipApplyModifications({ errors: new Set([GitError]) }) - expect(typeof result === 'string').toEqual(true) - }) - }) - - describe('shouldSkipRevert', () => { - it('should return error message when there is an unkown git error', () => { - const result = shouldSkip.shouldSkipRevert({ errors: new Set([GitError]) }) - expect(typeof result === 'string').toEqual(true) - }) - }) - - describe('shouldSkipCleanup', () => { - it('should return error message when reverting to original state fails', () => { - const result = shouldSkip.shouldSkipCleanup({ errors: new Set([RestoreOriginalStateError]) }) - expect(typeof result === 'string').toEqual(true) - }) - }) -}) diff --git a/test/state.spec.js b/test/state.spec.js new file mode 100644 index 000000000..e5528a0ee --- /dev/null +++ b/test/state.spec.js @@ -0,0 +1,40 @@ +import { + applyModificationsSkipped, + cleanupSkipped, + restoreOriginalStateSkipped, + restoreUnstagedChangesSkipped +} from '../lib/state' +import { GitError, RestoreOriginalStateError } from '../lib/symbols' + +describe('applyModificationsSkipped', () => { + it('should return false when backup is disabled', () => { + const result = applyModificationsSkipped({ shouldBackup: false }) + expect(result).toEqual(false) + }) + + it('should return error message when there is an unkown git error', () => { + const result = applyModificationsSkipped({ shouldBackup: true, errors: new Set([GitError]) }) + expect(typeof result === 'string').toEqual(true) + }) +}) + +describe('restoreUnstagedChangesSkipped', () => { + it('should return error message when there is an unkown git error', () => { + const result = restoreUnstagedChangesSkipped({ errors: new Set([GitError]) }) + expect(typeof result === 'string').toEqual(true) + }) +}) + +describe('restoreOriginalStateSkipped', () => { + it('should return error message when there is an unkown git error', () => { + const result = restoreOriginalStateSkipped({ errors: new Set([GitError]) }) + expect(typeof result === 'string').toEqual(true) + }) +}) + +describe('shouldSkipCleanup', () => { + it('should return error message when reverting to original state fails', () => { + const result = cleanupSkipped({ errors: new Set([RestoreOriginalStateError]) }) + expect(typeof result === 'string').toEqual(true) + }) +})