From b3f63ec43c04158e0ba00f541aa8ffb609d037d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iiro=20J=C3=A4ppinen?= Date: Fri, 22 Apr 2022 09:16:05 +0300 Subject: [PATCH] fix: correctly handle symlinked config files --- lib/searchConfigs.js | 41 +++++++++++++++++++------------------- test/integration.test.js | 16 +++++++++++++++ test/searchConfigs.spec.js | 7 ++++--- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/lib/searchConfigs.js b/lib/searchConfigs.js index ada2e426d..ebadd0144 100644 --- a/lib/searchConfigs.js +++ b/lib/searchConfigs.js @@ -14,7 +14,8 @@ const debugLog = debug('lint-staged:searchConfigs') const EXEC_GIT = ['ls-files', '-z', '--full-name'] -const filterPossibleConfigFiles = (file) => searchPlaces.includes(basename(file)) +const filterPossibleConfigFiles = (files) => + files.filter((file) => searchPlaces.includes(basename(file))) const numberOfLevels = (file) => file.split('/').length @@ -58,20 +59,18 @@ export const searchConfigs = async ( return { [configPath]: validateConfig(config, filepath, logger) } } - /** Get all possible config files known to git */ - const cachedFiles = parseGitZOutput(await execGit(EXEC_GIT, { cwd: gitDir })).filter( - filterPossibleConfigFiles - ) - - /** Get all possible config files from uncommitted files */ - const otherFiles = parseGitZOutput( - await execGit([...EXEC_GIT, '--others', '--exclude-standard'], { cwd: gitDir }) - ).filter(filterPossibleConfigFiles) + const [cachedFiles, otherFiles] = await Promise.all([ + /** Get all possible config files known to git */ + execGit(EXEC_GIT, { cwd: gitDir }).then(parseGitZOutput).then(filterPossibleConfigFiles), + /** Get all possible config files from uncommitted files */ + execGit([...EXEC_GIT, '--others', '--exclude-standard'], { cwd: gitDir }) + .then(parseGitZOutput) + .then(filterPossibleConfigFiles), + ]) /** Sort possible config files so that deepest is first */ const possibleConfigFiles = [...cachedFiles, ...otherFiles] - .map((file) => join(gitDir, file)) - .map((file) => normalize(file)) + .map((file) => normalize(join(gitDir, file))) .filter(isInsideDirectory(cwd)) .sort(sortDeepestParth) @@ -85,15 +84,17 @@ export const searchConfigs = async ( /** Load and validate all configs to the above object */ await Promise.all( - possibleConfigFiles - .map((configPath) => loadConfig({ configPath }, logger)) - .map((promise) => - promise.then(({ config, filepath }) => { - if (config) { - configs[filepath] = validateConfig(config, filepath, logger) + Object.keys(configs).map((configPath) => + loadConfig({ configPath }, logger).then(({ config, filepath }) => { + if (config) { + if (configPath !== filepath) { + debugLog('Config file "%s" resolved to "%s"', configPath, filepath) } - }) - ) + + configs[configPath] = validateConfig(config, filepath, logger) + } + }) + ) ) /** Get validated configs from the above object, without any `null` values (not found) */ diff --git a/test/integration.test.js b/test/integration.test.js index 8d427a0fa..b90a35c8e 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -1232,6 +1232,22 @@ describe('lint-staged', () => { expect(await readFile('a/very/deep/file/path/file.js')).toEqual('') }) + it('should work with symlinked config file', async () => { + await appendFile('test.js', testJsFileUgly) + + await writeFile('.config/.lintstagedrc.json', JSON.stringify(fixJsConfig.config)) + await fs.ensureSymlink( + path.join(cwd, '.config/.lintstagedrc.json'), + path.join(cwd, '.lintstagedrc.json') + ) + + await execGit(['add', '.']) + + await gitCommit() + + expect(await readFile('test.js')).toEqual(testJsFilePretty) // file was fixed + }) + it('should support parent globs', async () => { // Add some empty files await writeFile('file.js', '') diff --git a/test/searchConfigs.spec.js b/test/searchConfigs.spec.js index 74be8a143..e7adcc206 100644 --- a/test/searchConfigs.spec.js +++ b/test/searchConfigs.spec.js @@ -78,17 +78,18 @@ describe('searchConfigs', () => { }) it('should return config found from git', async () => { - const configPath = '.lintstagedrc.json' + const configFile = '.lintstagedrc.json' + const configPath = normalize(path.join(process.cwd(), configFile)) const config = { '*.js': 'eslint' } - execGit.mockResolvedValueOnce(`${configPath}\u0000`) + execGit.mockResolvedValueOnce(`${configFile}\u0000`) loadConfig.mockResolvedValueOnce({ config, filepath: configPath }) await expect(searchConfigs({})).resolves.toEqual({ [configPath]: config }) }) it('should return auto-discovered config from cwd when not found from git', async () => { - const configPath = '.lintstagedrc.json' + const configPath = normalize(path.join(process.cwd(), '.lintstagedrc.json')) const config = { '*.js': 'eslint' } loadConfig.mockResolvedValueOnce({ config, filepath: configPath })