diff --git a/packages/eas-cli/src/vcs/__tests__/local-test.ts b/packages/eas-cli/src/vcs/__tests__/local-test.ts index abb9796e8b..9e7622e702 100644 --- a/packages/eas-cli/src/vcs/__tests__/local-test.ts +++ b/packages/eas-cli/src/vcs/__tests__/local-test.ts @@ -79,6 +79,32 @@ describe(Ignore, () => { const ignore = await Ignore.createForCopyingAsync('/root'); expect(ignore.ignores('.git')).toBe(true); }); + + it('applies ignore rules from .gitignore files in dot-directories', async () => { + vol.fromJSON( + { + '.eas/.gitignore': 'secrets.txt\n', + }, + '/root' + ); + + const ignore = await Ignore.createForCopyingAsync('/root'); + expect(ignore.ignores('.eas/secrets.txt')).toBe(true); + expect(ignore.ignores('.eas/other.txt')).toBe(false); + }); + + it('does not throw an error if there is a trailing backslash in the gitignore', async () => { + vol.fromJSON( + { + '.gitignore': 'dir\\', + }, + '/root' + ); + + const ignore = await Ignore.createForCopyingAsync('/root'); + expect(() => ignore.ignores('dir/test')).not.toThrowError(); + }); + describe('for checking', () => { it('does not necessarily ignore .git', async () => { vol.fromJSON({}, '/root'); @@ -100,15 +126,45 @@ describe(Ignore, () => { }); }); - it('does not throw an error if there is a trailing backslash in the gitignore', async () => { - vol.fromJSON( - { - '.gitignore': 'dir\\', - }, - '/root' - ); + describe('negation patterns', () => { + it('does not ignore a path negated by a directory pattern in the same .gitignore', async () => { + vol.fromJSON( + { + '.gitignore': '.eas/*\n!.eas/build/\n', + }, + '/root' + ); - const ignore = await Ignore.createForCopyingAsync('/root'); - expect(() => ignore.ignores('dir/test')).not.toThrowError(); + const ignore = await Ignore.createForCopyingAsync('/root'); + expect(ignore.ignores('.eas/build/')).toBe(false); + expect(ignore.ignores('.eas/build/foo.txt')).toBe(false); + expect(ignore.ignores('.eas/other/')).toBe(true); + expect(ignore.ignores('.eas/other.txt')).toBe(true); + }); + + it('ignores a file inside a directory matched by a glob with no negation', async () => { + vol.fromJSON( + { + '.gitignore': '.eas/*\n', + }, + '/root' + ); + + const ignore = await Ignore.createForCopyingAsync('/root'); + expect(ignore.ignores('.eas/build/foo.txt')).toBe(true); + }); + + it('does not un-ignore a file whose name matches a directory negation pattern', async () => { + vol.fromJSON( + { + '.gitignore': 'build\n!build/\n', + }, + '/root' + ); + + const ignore = await Ignore.createForCopyingAsync('/root'); + expect(ignore.ignores('build')).toBe(true); + expect(ignore.ignores('build/')).toBe(false); + }); }); }); diff --git a/packages/eas-cli/src/vcs/local.ts b/packages/eas-cli/src/vcs/local.ts index 2e8abf47c2..68ad30db86 100644 --- a/packages/eas-cli/src/vcs/local.ts +++ b/packages/eas-cli/src/vcs/local.ts @@ -62,6 +62,7 @@ node_modules cwd: this.rootDir, ignore: ['node_modules'], followSymbolicLinks: false, + dot: true, }) ) // ensure that parent dir is before child directories @@ -84,12 +85,15 @@ node_modules } public ignores(relativePath: string): boolean { + let ignored = false; for (const [prefix, ignore] of this.ignoreMapping) { - if (relativePath.startsWith(prefix) && ignore.ignores(relativePath.slice(prefix.length))) { - return true; - } + if (!relativePath.startsWith(prefix)) continue; + const slicedPath = relativePath.slice(prefix.length); + const result = ignore.test(slicedPath); + if (result.ignored) ignored = true; + else if (result.unignored) ignored = false; } - return false; + return ignored; } } @@ -115,7 +119,10 @@ export async function makeShallowCopyAsync(_src: string, dst: string): Promise