Repository: okonet/lint-staged
Pull request #1176 (2022-06-15 14:00:06)

Extract diff string generation to unify diffs across library
Closes issue https://github.com/okonet/lint-staged/issues/1175


Patch:
diff --git a/lib/getDiffCommand.js b/lib/getDiffCommand.js
new file mode 100644
index 0000000..531b6ff
--- /dev/null
+++ b/lib/getDiffCommand.js
@@ -0,0 +1,18 @@
+export function getDiffCommand(diff, diffFilter) {
+  /**
+   *  Docs for --diff-filter option:
+   * @see https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---diff-filterACDMRTUXB82308203
+   */
+  const diffFilterArg = diffFilter !== undefined ? diffFilter.trim() : 'ACMR'
+
+  /** Use `--diff branch1...branch2` or `--diff="branch1 branch2", or fall back to default staged files */
+  const diffArgs = diff !== undefined ? diff.trim().split(' ') : ['--staged']
+
+  /**
+   * Docs for -z option:
+   * @see https://git-scm.com/docs/git-diff#Documentation/git-diff.txt--z
+   */
+  const diffCommand = ['diff', '--name-only', '-z', `--diff-filter=${diffFilterArg}`, ...diffArgs]
+
+  return diffCommand
+}
diff --git a/lib/getStagedFiles.js b/lib/getStagedFiles.js
index b301d42..8cbb83b 100644
--- a/lib/getStagedFiles.js
+++ b/lib/getStagedFiles.js
@@ -3,27 +3,12 @@ import path from 'node:path'
 import normalize from 'normalize-path'
 
 import { execGit } from './execGit.js'
+import { getDiffCommand } from './getDiffCommand.js'
 import { parseGitZOutput } from './parseGitZOutput.js'
 
 export const getStagedFiles = async ({ cwd = process.cwd(), diff, diffFilter } = {}) => {
   try {
-    /**
-     *  Docs for --diff-filter option:
-     * @see https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---diff-filterACDMRTUXB82308203
-     */
-    const diffFilterArg = diffFilter !== undefined ? diffFilter.trim() : 'ACMR'
-
-    /** Use `--diff branch1...branch2` or `--diff="branch1 branch2", or fall back to default staged files */
-    const diffArgs = diff !== undefined ? diff.trim().split(' ') : ['--staged']
-
-    /**
-     * Docs for -z option:
-     * @see https://git-scm.com/docs/git-diff#Documentation/git-diff.txt--z
-     */
-    const lines = await execGit(
-      ['diff', '--name-only', '-z', `--diff-filter=${diffFilterArg}`, ...diffArgs],
-      { cwd }
-    )
+    const lines = await execGit(getDiffCommand(diff, diffFilter), { cwd })
     if (!lines) return []
 
     return parseGitZOutput(lines).map((file) => normalize(path.resolve(cwd, file)))
diff --git a/lib/gitWorkflow.js b/lib/gitWorkflow.js
index 8ae95e7..9813aa4 100644
--- a/lib/gitWorkflow.js
+++ b/lib/gitWorkflow.js
@@ -4,6 +4,7 @@ import debug from 'debug'
 
 import { execGit } from './execGit.js'
 import { readFile, unlink, writeFile } from './file.js'
+import { getDiffCommand } from './getDiffCommand.js'
 import {
   GitError,
   RestoreOriginalStateError,
@@ -65,12 +66,13 @@ const handleError = (error, ctx, symbol) => {
 }
 
 export class GitWorkflow {
-  constructor({ allowEmpty, gitConfigDir, gitDir, matchedFileChunks }) {
+  constructor({ allowEmpty, gitConfigDir, gitDir, matchedFileChunks, diff, diffFilter }) {
     this.execGit = (args, options = {}) => execGit(args, { ...options, cwd: gitDir })
     this.deletedFiles = []
     this.gitConfigDir = gitConfigDir
     this.gitDir = gitDir
-    this.unstagedDiff = null
+    this.diff = diff
+    this.diffFilter = diffFilter
     this.allowEmpty = allowEmpty
     this.matchedFileChunks = matchedFileChunks
 
@@ -262,7 +264,7 @@ export class GitWorkflow {
 
     debugLog('Done adding task modifications to index!')
 
-    const stagedFilesAfterAdd = await this.execGit(['diff', '--name-only', '--cached'])
+    const stagedFilesAfterAdd = await this.execGit(getDiffCommand(this.diff, this.diffFilter))
     if (!stagedFilesAfterAdd && !this.allowEmpty) {
       // Tasks reverted all staged changes and the commit would be empty
       // Throw error to stop commit unless `--allow-empty` was used
diff --git a/lib/runAll.js b/lib/runAll.js
index 4edd829..f0ff203 100644
--- a/lib/runAll.js
+++ b/lib/runAll.js
@@ -262,7 +262,14 @@ export const runAll = async (
     relative: false,
   })
 
-  const git = new GitWorkflow({ allowEmpty, gitConfigDir, gitDir, matchedFileChunks })
+  const git = new GitWorkflow({
+    allowEmpty,
+    gitConfigDir,
+    gitDir,
+    matchedFileChunks,
+    diff,
+    diffFilter,
+  })
 
   const runner = new Listr(
     [


Test patch:
diff --git a/test/unit/getDiffCommand.spec.js b/test/unit/getDiffCommand.spec.js
new file mode 100644
index 0000000..4709623
--- /dev/null
+++ b/test/unit/getDiffCommand.spec.js
@@ -0,0 +1,51 @@
+import { getDiffCommand } from '../../lib/getDiffCommand.js'
+
+describe('chunkFiles', () => {
+  const customDiffString = 'origin/main..custom-branch'
+  const customDiffSpaceSeparatedString = 'origin/main custom-branch'
+  const customDiffFilter = 'a'
+
+  it('should default to sane value', () => {
+    const diff = getDiffCommand()
+    expect(diff).toEqual(['diff', '--name-only', '-z', `--diff-filter=ACMR`, '--staged'])
+  })
+
+  it('should work only with diff set as string', () => {
+    const diff = getDiffCommand(customDiffString)
+    expect(diff).toEqual([
+      'diff',
+      '--name-only',
+      '-z',
+      `--diff-filter=ACMR`,
+      'origin/main..custom-branch',
+    ])
+  })
+
+  it('should work only with diff set as space separated string', () => {
+    const diff = getDiffCommand(customDiffSpaceSeparatedString)
+    expect(diff).toEqual([
+      'diff',
+      '--name-only',
+      '-z',
+      `--diff-filter=ACMR`,
+      'origin/main',
+      'custom-branch',
+    ])
+  })
+
+  it('should work only with diffFilter set', () => {
+    const diff = getDiffCommand(undefined, customDiffFilter)
+    expect(diff).toEqual(['diff', '--name-only', '-z', `--diff-filter=a`, '--staged'])
+  })
+
+  it('should work with both diff and diffFilter set', () => {
+    const diff = getDiffCommand(customDiffString, customDiffFilter)
+    expect(diff).toEqual([
+      'diff',
+      '--name-only',
+      '-z',
+      `--diff-filter=a`,
+      'origin/main..custom-branch',
+    ])
+  })
+})