diff --git a/src/resolve/forceIgnore.ts b/src/resolve/forceIgnore.ts index 299fc69470..40f6c601d2 100644 --- a/src/resolve/forceIgnore.ts +++ b/src/resolve/forceIgnore.ts @@ -21,22 +21,19 @@ export class ForceIgnore { public constructor(forceIgnorePath = '') { try { - let contents = readFileSync(forceIgnorePath, 'utf-8'); + const contents = readFileSync(forceIgnorePath, 'utf-8'); // check if file `.forceignore` exists if (contents !== undefined) { // check for windows style separators (\) and warn if (contents.includes('\\')) { - const lifecycle = Lifecycle.getInstance(); - // cannot await a method in a constructor - void lifecycle.emitWarning( - 'Your .forceignore file incorrectly uses the backslash ("\\") as a folder separator; it should use the slash ("/") instead. We currently accept both separators, but we plan to stop supporting the backslash soon.' + // void because you cannot await a method in a constructor + void Lifecycle.getInstance().emitWarning( + 'Your .forceignore file incorrectly uses the backslash ("\\") as a folder separator; it should use the slash ("/") instead. The ignore rules will not work as expected until you fix this.' ); - // TODO: change this in v56 to only emit warning but NOT fix file - contents = contents.replace(/\\/g, '/'); } - // add the default ignore paths, and then parse the .forceignore file - this.parser = ignore().add(`${contents}\n${this.DEFAULT_IGNORE.join('\n')}`); + this.parser = ignore().add(`${this.DEFAULT_IGNORE.join('\n')}\n${contents}`); + this.forceIgnoreDirectory = dirname(forceIgnorePath); } } catch (e) { diff --git a/test/resolve/forceIgnore.test.ts b/test/resolve/forceIgnore.test.ts index 3a58cd8064..47df03ffa6 100644 --- a/test/resolve/forceIgnore.test.ts +++ b/test/resolve/forceIgnore.test.ts @@ -9,7 +9,7 @@ import { expect } from 'chai'; import { createSandbox } from 'sinon'; import * as fs from 'graceful-fs'; import { Lifecycle } from '@salesforce/core'; -import { ForceIgnore } from '../../src'; +import { ForceIgnore } from '../../src/resolve/forceIgnore'; import * as fsUtil from '../../src/utils/fileSystemHandler'; const env = createSandbox(); @@ -29,14 +29,13 @@ describe('ForceIgnore', () => { }); it('Should ignore files with a given pattern', () => { - const readStub = env.stub(fs, 'readFileSync'); - readStub.withArgs(forceIgnorePath).returns(testPattern); + env.stub(fs, 'readFileSync').returns(testPattern); const forceIgnore = new ForceIgnore(forceIgnorePath); expect(forceIgnore.accepts(testPath)).to.be.false; expect(forceIgnore.denies(testPath)).to.be.true; }); - it('Should ignore files with windows separators', () => { + it('windows separators no longer have any effect', () => { const lifecycleStub = env.stub(Lifecycle.prototype, 'emitWarning'); const forceIgnoreEntry = 'force-app\\main\\default\\classes\\myApex.*'; const pathToClass = join('force-app', 'main', 'default', 'classes', 'myApex.cls'); @@ -44,7 +43,7 @@ describe('ForceIgnore', () => { const forceIgnore = new ForceIgnore(); - expect(forceIgnore.accepts(pathToClass)).to.be.false; + expect(forceIgnore.accepts(pathToClass)).to.be.true; expect(lifecycleStub.callCount).to.equal(1); }); @@ -110,5 +109,16 @@ describe('ForceIgnore', () => { expect(forceIgnore.accepts(manifestPath)).to.be.false; expect(forceIgnore.denies(manifestPath)).to.be.true; }); + + it('Should allow .forceignore file to override defaults', () => { + // tamper with the file + env.restore(); + env.stub(fs, 'readFileSync').returns('!**/.*'); + forceIgnore = new ForceIgnore(); + + const dotFilePath = join(root, '.foo'); + expect(forceIgnore.accepts(dotFilePath)).to.be.true; + expect(forceIgnore.denies(dotFilePath)).to.be.false; + }); }); });