diff --git a/.gitignore b/.gitignore index bf05e3d5..8f2d01e2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ build stats.html tsconfig.build.tsbuildinfo .ultra.cache.json -.nyc_output \ No newline at end of file +.nyc_output +.idea \ No newline at end of file diff --git a/.ultraignore b/.ultraignore new file mode 100644 index 00000000..bb947bc4 --- /dev/null +++ b/.ultraignore @@ -0,0 +1,2 @@ +# Used only for cache unit tests +__tests__/**/file-to-ignore.js \ No newline at end of file diff --git a/__tests__/git.ts b/__tests__/git.ts index 0ed7e879..20959fec 100644 --- a/__tests__/git.ts +++ b/__tests__/git.ts @@ -41,15 +41,19 @@ test("getGitFiles", async () => { expect(files["__tests__/workspace/apps/app2/package.json"]).toMatch( /^[a-z0-9]*$/u ) + expect(files["__tests__/workspace/apps/app1/file-to-ignore.js"]).toMatch( + /^[a-z0-9]*$/u + ) expect(files[""]).toMatch(/^\d+\.\d+$/u) - expect(Object.keys(files)).toHaveLength(3) + expect(Object.keys(files)).toHaveLength(4) }) test("cache", async () => { const files = f(await cache.getFiles(path.resolve(workspaceRoot, "apps"))) expect(files["app1/package.json"]).toMatch(/^[a-z0-9]*$/u) expect(files["app2/package.json"]).toMatch(/^[a-z0-9]*$/u) + expect(files["app1/file-to-ignore.js"]).toBeUndefined() expect(Object.keys(files)).toHaveLength(2) expect(cache.cache.size).not.toBe(0) await cache.getFiles(path.resolve(workspaceRoot, "apps")) diff --git a/__tests__/workspace/apps/app1/file-to-ignore.js b/__tests__/workspace/apps/app1/file-to-ignore.js new file mode 100644 index 00000000..45a202a6 --- /dev/null +++ b/__tests__/workspace/apps/app1/file-to-ignore.js @@ -0,0 +1 @@ +export const FOO = 'foo' diff --git a/package.json b/package.json index 72269121..1acde00d 100644 --- a/package.json +++ b/package.json @@ -118,6 +118,7 @@ "cross-spawn": "^7.0.3", "fast-glob": "^3.2.5", "globrex": "^0.1.2", + "ignore": "^5.1.8", "json5": "^2.2.0", "micro-memoize": "^4.0.9", "npm-run-path": "4.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index efb53c73..39aab9f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,7 @@ dependencies: cross-spawn: 7.0.3 fast-glob: 3.2.5 globrex: 0.1.2 + ignore: 5.1.8 json5: 2.2.0 micro-memoize: 4.0.9 npm-run-path: 4.0.1 @@ -4312,7 +4313,6 @@ packages: resolution: integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== /ignore/5.1.8: - dev: true engines: node: '>= 4' resolution: @@ -8921,6 +8921,7 @@ specifiers: fast-glob: ^3.2.5 globrex: ^0.1.2 husky: 5.1.1 + ignore: ^5.1.8 jest: 26.6.3 json5: ^2.2.0 markdownlint-cli: 0.26.0 diff --git a/src/git.ts b/src/git.ts index cc456548..18353b2d 100644 --- a/src/git.ts +++ b/src/git.ts @@ -1,6 +1,7 @@ import { exec } from "child_process" import fs from "fs" import path from "path" +import ignore, { Ignore } from "ignore" import { findUp } from "./package" import { HASH_FILE } from "./options" @@ -10,6 +11,18 @@ type GitFiles = Record export class NoGitError extends Error {} +function getUltraIgnore(root: string): Ignore { + const ultraIgnorePath = path.resolve(root, ".ultraignore") + const ultraIgnoreExists = fs.existsSync(ultraIgnorePath) + + const ultraIgnore = ignore() + if (ultraIgnoreExists) { + ultraIgnore.add(fs.readFileSync(ultraIgnorePath).toString()) + } + + return ultraIgnore +} + export function parseFiles(data: string, root: string): GitFiles { const ret: GitFiles = {} data.split("\n").forEach((line) => { @@ -36,12 +49,8 @@ export function parseFiles(data: string, root: string): GitFiles { export async function getGitFiles(root: string): Promise { return new Promise((resolve, reject) => { - const ultraIgnoreExists = fs.existsSync(path.resolve(root, ".ultraignore")) - const lsFiles = `git ls-files --full-name -s -d -c -m -o ${ - ultraIgnoreExists ? "-X .ultraignore" : "" - } --directory -t` exec( - lsFiles, + "git ls-files --full-name -s -d -c -m -o --directory -t", { cwd: root, maxBuffer: 1024 * 1024 * 1024 }, (error, stdout) => { if (error) return reject(error) @@ -68,6 +77,8 @@ class FilesCache { const files = this.cache.get(root) || {} const ret: GitFiles = {} + const ultraIgnore = getUltraIgnore(root) + Object.entries(files) .filter(([file]) => { const filePath = path.resolve(root, file) @@ -75,6 +86,7 @@ class FilesCache { filePath == directory || filePath.startsWith(directory + path.sep) ) }) + .filter(([file]) => !ultraIgnore.ignores(file)) .map(([file, hash]) => [ path.relative(directory, path.resolve(root, file)), hash,