From 9e39753bb32f2472e734cc7c08619dd95e6294af Mon Sep 17 00:00:00 2001 From: Lau Kondrup Date: Tue, 16 Sep 2025 21:52:25 +0200 Subject: [PATCH 1/2] fix: only look at .gitignores from within the current repository --- .../__tests__/common/getFilesList.test.ts | 36 +++++++++++++++ packages/core/src/getFilesList.ts | 46 +++++++++++++++---- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/packages/core/__tests__/common/getFilesList.test.ts b/packages/core/__tests__/common/getFilesList.test.ts index 5c8b144..8945b62 100644 --- a/packages/core/__tests__/common/getFilesList.test.ts +++ b/packages/core/__tests__/common/getFilesList.test.ts @@ -273,6 +273,41 @@ it('should return files for project root with omitting gitignore', async () => { ) }) +it('should use .gitignore only within the current repository', async () => { + mockFs({ + [root]: { + '.git': {}, + project: { + 'fileA.ts': 'content', + '.gitignore': 'packageA/*', + packageA: { + '.git': {}, + '.env': 'content', + '.gitignore': ` + .env + `, + src: { + 'fileE.json': '', + }, + }, + }, + }, + }) + + const filesList = removeCwd( + await getFilesList({ + searchRoot: toPlatformSpecificPath(`${root}/project/packageA`), + }), + ) + mockFs.restore() + + expect(filesList.sort()).toMatchObject( + [`${root}/project/packageA/src/fileE.json`] + .sort() + .map(toPlatformSpecificPath), + ) +}) + // We will add option to search in ignored files, so that exception is not needed it.skip('should return files for project root ignored by parent gitignore, but ignore the nested directories', async () => { mockFs({ @@ -321,6 +356,7 @@ it.skip('should return files for project root ignored by parent gitignore, but i it('should ignore files from parent .gitignore', async () => { mockFs({ [root]: { + '.git': {}, project: { 'fileA.ts': 'content', 'fileB.js': 'content', diff --git a/packages/core/src/getFilesList.ts b/packages/core/src/getFilesList.ts index 96dffd9..9828c51 100644 --- a/packages/core/src/getFilesList.ts +++ b/packages/core/src/getFilesList.ts @@ -179,6 +179,30 @@ export type GetFilesListArgs = { extensionTester?: RegExp } +// Helper to find the repository root (directory containing .git) +const findRepoRoot = async ( + startDir: string, + fsRoot: string, +): Promise => { + let currentDir = path.resolve(startDir) + while (true) { + try { + const gitDir = path.join(currentDir, '.git') + const stat = await fs.lstat(gitDir) + if (stat.isDirectory() || stat.isFile()) { + return currentDir + } + } catch (_e) { + // .git not found, continue + } + if (currentDir === fsRoot) break + const parentDir = path.dirname(currentDir) + if (parentDir === currentDir) break + currentDir = parentDir + } + return startDir // fallback: treat startDir as repo root +} + export const getFilesList = async ({ searchRoot: _searchRoot, entryPoint = undefined, @@ -204,25 +228,29 @@ export const getFilesList = async ({ } else { const InitialIgnore = ignoreNodeModules ? ['node_modules'] : [] - // Get parent to root gitignore + // Get parent to root gitignore, but stop at repo root if (!omitGitIgnore) { + // Find the repo root (directory containing .git) + const repoRoot = await findRepoRoot(searchRoot, fsRoot) const searchRootSegments = searchRoot .replace(fsRoot, '') .split(pathSeparatorChar) - - const pathSegmentsToSystemRoot = [] - + const pathSegmentsToRepoRoot = [] for (let i = 0; i < searchRootSegments.length; i++) { let currentPath = searchRootSegments.slice(0, i).join(pathSeparatorChar) - currentPath = fsRoot + currentPath - - pathSegmentsToSystemRoot.push(currentPath) + // Only add if currentPath is within repoRoot + if (path.resolve(currentPath).startsWith(path.resolve(repoRoot))) { + pathSegmentsToRepoRoot.push(currentPath) + } + } + // Always include the repoRoot itself + if (!pathSegmentsToRepoRoot.includes(repoRoot)) { + pathSegmentsToRepoRoot.push(repoRoot) } - const parentDirsIgnore = ( await Promise.all( - pathSegmentsToSystemRoot.map((parentPath) => + pathSegmentsToRepoRoot.map((parentPath) => getGitIgnoreContentForDirectory(parentPath), ), ) From f2de031e365f1bf6f3eac65be9df83249d09ca8f Mon Sep 17 00:00:00 2001 From: Lau Kondrup Date: Fri, 19 Sep 2025 12:32:12 +0200 Subject: [PATCH 2/2] simplify a bit --- packages/core/src/getFilesList.ts | 56 +++++++++++++------------------ 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/packages/core/src/getFilesList.ts b/packages/core/src/getFilesList.ts index 9828c51..f351111 100644 --- a/packages/core/src/getFilesList.ts +++ b/packages/core/src/getFilesList.ts @@ -2,7 +2,7 @@ import path from 'path' import { promises as fs } from 'fs' import ignore from 'ignore' -import { asyncFilter, measureStart } from './utils' +import { measureStart } from './utils' import minimatch from 'minimatch' import { parseDependencyTree } from 'dpdm/lib/index.js' import { spawnSync } from 'child_process' @@ -179,28 +179,27 @@ export type GetFilesListArgs = { extensionTester?: RegExp } -// Helper to find the repository root (directory containing .git) -const findRepoRoot = async ( - startDir: string, - fsRoot: string, -): Promise => { - let currentDir = path.resolve(startDir) - while (true) { +const findRepoRoot = async ({ + searchRoot, + fsRoot, +}: { + searchRoot: string + fsRoot: string +}) => { + let currentDir = path.resolve(searchRoot) + while (currentDir !== fsRoot) { try { const gitDir = path.join(currentDir, '.git') const stat = await fs.lstat(gitDir) - if (stat.isDirectory() || stat.isFile()) { + if (stat.isDirectory()) { return currentDir } } catch (_e) { // .git not found, continue } - if (currentDir === fsRoot) break - const parentDir = path.dirname(currentDir) - if (parentDir === currentDir) break - currentDir = parentDir + currentDir = path.dirname(currentDir) } - return startDir // fallback: treat startDir as repo root + return searchRoot } export const getFilesList = async ({ @@ -228,29 +227,20 @@ export const getFilesList = async ({ } else { const InitialIgnore = ignoreNodeModules ? ['node_modules'] : [] - // Get parent to root gitignore, but stop at repo root if (!omitGitIgnore) { - // Find the repo root (directory containing .git) - const repoRoot = await findRepoRoot(searchRoot, fsRoot) - const searchRootSegments = searchRoot - .replace(fsRoot, '') - .split(pathSeparatorChar) - const pathSegmentsToRepoRoot = [] - for (let i = 0; i < searchRootSegments.length; i++) { - let currentPath = searchRootSegments.slice(0, i).join(pathSeparatorChar) - currentPath = fsRoot + currentPath - // Only add if currentPath is within repoRoot - if (path.resolve(currentPath).startsWith(path.resolve(repoRoot))) { - pathSegmentsToRepoRoot.push(currentPath) - } - } - // Always include the repoRoot itself - if (!pathSegmentsToRepoRoot.includes(repoRoot)) { - pathSegmentsToRepoRoot.push(repoRoot) + const repoRoot = await findRepoRoot({ searchRoot, fsRoot }) + const parentPaths = [] + let currentPath = searchRoot + + while (currentPath !== repoRoot) { + parentPaths.push(currentPath) + currentPath = path.dirname(currentPath) } + parentPaths.push(repoRoot) + const parentDirsIgnore = ( await Promise.all( - pathSegmentsToRepoRoot.map((parentPath) => + parentPaths.map((parentPath) => getGitIgnoreContentForDirectory(parentPath), ), )