diff --git a/__tests__/unit/lib/post-processor/flowTranslationProcessor.test.js b/__tests__/unit/lib/post-processor/flowTranslationProcessor.test.js index 4c9f75d1..fc17cc16 100644 --- a/__tests__/unit/lib/post-processor/flowTranslationProcessor.test.js +++ b/__tests__/unit/lib/post-processor/flowTranslationProcessor.test.js @@ -13,11 +13,18 @@ const { isSubDir, readFile, } = require('../../../../src/utils/fsHelper') -const { forPath } = require('../../../../src/utils/ignoreHelper') const { pathExists } = require('fs-extra') jest.mock('fs-extra') jest.mock('../../../../src/utils/fsHelper') -jest.mock('../../../../src/utils/ignoreHelper') + +const mockIgnores = jest.fn() +jest.mock('../../../../src/utils/ignoreHelper', () => ({ + buildIgnoreHelper: jest.fn(() => ({ + globalIgnore: { + ignores: mockIgnores, + }, + })), +})) jest.mock('../../../../src/utils/fxpHelper', () => { const originalModule = jest.requireActual('../../../../src/utils/fxpHelper') @@ -43,6 +50,7 @@ describe('FlowTranslationProcessor', () => { let sut let flap beforeEach(() => { + mockIgnores.mockReset() work = { diffs: { package: new Map(), @@ -314,7 +322,7 @@ describe('FlowTranslationProcessor', () => { beforeEach(() => { // Arrange work.config.ignore = '.forceignore' - forPath.mockResolvedValue({ ignores: () => true }) + mockIgnores.mockReturnValue(true) }) it('should not add translation file', async () => { // Act @@ -328,7 +336,6 @@ describe('FlowTranslationProcessor', () => { EXTENSION, work.config ) - expect(forPath).toHaveBeenCalledTimes(1) expect(parseXmlFileToJson).not.toHaveBeenCalled() expect(writeFile).not.toHaveBeenCalled() }) @@ -341,7 +348,7 @@ describe('FlowTranslationProcessor', () => { [FLOW_XML_NAME, new Set([flowFullName])], ]) work.config.ignore = '.forceignore' - forPath.mockResolvedValue({ ignores: () => false }) + mockIgnores.mockReturnValue(false) }) it('should add translation file', async () => { // Act @@ -355,7 +362,6 @@ describe('FlowTranslationProcessor', () => { EXTENSION, work.config ) - expect(forPath).toHaveBeenCalledTimes(1) expect(parseXmlFileToJson).toHaveBeenCalledTimes(1) expect(writeFile).toHaveBeenCalledTimes(1) }) diff --git a/__tests__/unit/lib/utils/ignoreHelper.test.js b/__tests__/unit/lib/utils/ignoreHelper.test.js index ec01b447..03083f65 100644 --- a/__tests__/unit/lib/utils/ignoreHelper.test.js +++ b/__tests__/unit/lib/utils/ignoreHelper.test.js @@ -1,6 +1,6 @@ const { - forPath, buildIgnoreHelper, + resetInstance, } = require('../../../../src/utils/ignoreHelper') const { readFile } = require('../../../../src/utils/fsHelper') const { @@ -11,64 +11,9 @@ const { jest.mock('../../../../src/utils/fsHelper') describe('ignoreHelper', () => { - beforeEach(() => {}) - describe('forPath', () => { - describe('when path exist', () => { - it('returns an ignore instance', async () => { - // Arrange - expect.assertions(2) - readFile.mockImplementationOnce(() => { - return '' - }) - - // Act - const actual = await forPath('.forceignore') - - // Assert - expect(actual).toBeTruthy() - expect(readFile).toHaveBeenCalledTimes(1) - }) - }) - - describe('when path is asked multiple times', () => { - it('returns the same ignore instance', async () => { - // Arrange - expect.assertions(3) - const ignorePath = '.ignore' - readFile.mockImplementationOnce(() => { - return '' - }) - const expected = await forPath(ignorePath) - - // Act - const actual = await forPath(ignorePath) - - // Assert - expect(actual).toBeTruthy() - expect(expected).toBe(actual) - expect(readFile).toHaveBeenCalledTimes(1) - }) - }) - - describe('when path does not exist', () => { - it('throws exception', async () => { - // Arrange - expect.assertions(2) - readFile.mockRejectedValue(new Error()) - - // Act - let actual - try { - actual = await forPath('.notexist') - } catch (e) { - // Assert - expect(actual).toBeFalsy() - expect(readFile).toHaveBeenCalledTimes(1) - } - }) - }) + afterEach(() => { + jest.resetAllMocks() }) - describe('buildIgnoreHelper', () => { describe('when config does not have ignore neither destructive ignore', () => { let sut @@ -77,15 +22,18 @@ describe('ignoreHelper', () => { const config = {} sut = await buildIgnoreHelper(config) }) + afterAll(() => { + resetInstance() + }) - it('helper should not have globalInstance', () => { + it('global helper should be defined', () => { // Assert - expect(sut.globalIgnore).toBeUndefined() + expect(sut.globalIgnore).toBeDefined() }) - it('helper should not have destructiveInstance', () => { + it('destructive helper should be defined', () => { // Assert - expect(sut.destructiveIgnore).toBeUndefined() + expect(sut.destructiveIgnore).toBeDefined() }) it.each([ @@ -105,17 +53,21 @@ describe('ignoreHelper', () => { let sut beforeAll(async () => { // Arrange - readFile.mockImplementationOnce(() => Promise.resolve('*ignoreFile*')) + readFile.mockImplementation(() => Promise.resolve('*ignoreFile*')) const config = { ignoreDestructive: 'path' } sut = await buildIgnoreHelper(config) }) - it('helper should not have globalInstance', () => { + afterAll(() => { + resetInstance() + }) + + it('global helper should be defined', () => { // Assert - expect(sut.globalIgnore).toBeUndefined() + expect(sut.globalIgnore).toBeDefined() }) - it('helper should have destructiveInstance', () => { + it('destructive helper should be defined', () => { // Assert expect(sut.destructiveIgnore).toBeDefined() }) @@ -146,6 +98,19 @@ describe('ignoreHelper', () => { } ) + it.each([ + `${DELETION} path/to/objects/Account/recordTypes/IT.recordType-meta.xml`, + ])( + 'should not keep deleted "%s" line matching default ignore pattern', + line => { + // Act + const keep = sut.keep(line) + + // Assert + expect(keep).toBe(false) + } + ) + it.each([ `${ADDITION} path/to/file.ext`, `${MODIFICATION} path/to/file.ext`, @@ -161,20 +126,24 @@ describe('ignoreHelper', () => { let sut beforeAll(async () => { // Arrange - readFile.mockImplementationOnce(() => Promise.resolve('*ignoreFile*')) + readFile.mockImplementation(() => Promise.resolve('*ignoreFile*')) const config = { ignore: 'path' } sut = await buildIgnoreHelper(config) }) + afterAll(() => { + resetInstance() + }) + it('helper should have globalInstance', () => { // Assert expect(sut.globalIgnore).toBeDefined() }) - it('helper should have destructiveInstance (same as globalInstance)', () => { + it('helper should have destructiveInstance (with default ignore)', () => { // Assert expect(sut.destructiveIgnore).toBeDefined() - expect(sut.destructiveIgnore).toStrictEqual(sut.globalIgnore) + expect(sut.destructiveIgnore._rules).toHaveLength(2) }) it.each([ @@ -222,6 +191,19 @@ describe('ignoreHelper', () => { // Assert expect(keep).toBe(false) }) + + it.each([ + `${DELETION} path/to/objects/Account/recordTypes/IT.recordType-meta.xml`, + ])( + 'should not keep deleted "%s" line matching default ignore pattern', + line => { + // Act + const keep = sut.keep(line) + + // Assert + expect(keep).toBe(false) + } + ) }) describe('when config has ignore and destructive ignore', () => { let sut @@ -233,6 +215,10 @@ describe('ignoreHelper', () => { sut = await buildIgnoreHelper(config) }) + afterAll(() => { + resetInstance() + }) + it('helper should have globalInstance', () => { // Assert expect(sut.globalIgnore).toBeDefined() @@ -288,6 +274,19 @@ describe('ignoreHelper', () => { // Assert expect(keep).toBe(false) }) + + it.each([ + `${DELETION} path/to/objects/Account/recordTypes/IT.recordType-meta.xml`, + ])( + 'should not keep deleted "%s" line matching default ignore pattern', + line => { + // Act + const keep = sut.keep(line) + + // Assert + expect(keep).toBe(false) + } + ) }) }) }) diff --git a/__tests__/unit/lib/utils/repoGitDiff.test.js b/__tests__/unit/lib/utils/repoGitDiff.test.js index f6846b13..37337e13 100644 --- a/__tests__/unit/lib/utils/repoGitDiff.test.js +++ b/__tests__/unit/lib/utils/repoGitDiff.test.js @@ -1,4 +1,5 @@ 'use strict' +const { resetInstance } = require('../../../../src/utils/ignoreHelper') const RepoGitDiff = require('../../../../src/utils/repoGitDiff') const { ADDITION, @@ -23,6 +24,7 @@ describe(`test if repoGitDiff`, () => { beforeEach(() => { child_process.__setOutput([]) child_process.__setError(false) + resetInstance() }) test('can parse git correctly', async () => { const output = [] diff --git a/src/post-processor/flowTranslationProcessor.js b/src/post-processor/flowTranslationProcessor.js index 72d3b33e..412f40eb 100644 --- a/src/post-processor/flowTranslationProcessor.js +++ b/src/post-processor/flowTranslationProcessor.js @@ -15,7 +15,7 @@ const { } = require('../utils/fsHelper') const { pathExists } = require('fs-extra') const { parse, join } = require('path') -const { forPath } = require('../utils/ignoreHelper') +const { buildIgnoreHelper } = require('../utils/ignoreHelper') const { asArray, parseXmlFileToJson, @@ -62,11 +62,11 @@ class FlowTranslationProcessor extends BaseProcessor { this.work.config ) - const ign = await this._getIgnoreInstance() + const ignoreHelper = await buildIgnoreHelper(this.config) for await (const translationPath of translationsIterator) { if ( - !ign?.ignores(translationPath) && + !ignoreHelper?.globalIgnore?.ignores(translationPath) && !isSubDir(this.config.output, translationPath) ) { this._parseTranslationFile(translationPath) @@ -154,14 +154,6 @@ class FlowTranslationProcessor extends BaseProcessor { _shouldProcess() { return this.work.diffs.package.has(FLOW_XML_NAME) } - - async _getIgnoreInstance() { - let ign - if (this.config.ignore) { - ign = await forPath(this.config.ignore) - } - return ign - } } module.exports = FlowTranslationProcessor diff --git a/src/utils/ignoreHelper.js b/src/utils/ignoreHelper.js index e81478c8..c04a4086 100644 --- a/src/utils/ignoreHelper.js +++ b/src/utils/ignoreHelper.js @@ -6,13 +6,16 @@ const { MODIFICATION, GIT_DIFF_TYPE_REGEX, } = require('./gitConstants') + +const BASE_DESTRUCTIVE_IGNORE = ['recordTypes/'] + class IgnoreHelper { globalIgnore destructiveIgnore constructor(globalIgnore, destructiveIgnore) { this.globalIgnore = globalIgnore - this.destructiveIgnore = destructiveIgnore ?? globalIgnore + this.destructiveIgnore = destructiveIgnore } keep(line) { @@ -31,25 +34,37 @@ class IgnoreHelper { } } +let instance const buildIgnoreHelper = async config => { - const globalIgnore = await forPath(config.ignore) - const destructiveIgnore = await forPath(config.ignoreDestructive) + if (!instance) { + const globalIgnore = await _buildIgnore(config.ignore) + let destructiveIgnore = config.ignoreDestructive + ? await _buildIgnore(config.ignoreDestructive) + : await _buildIgnore(config.ignore) - return new IgnoreHelper(globalIgnore, destructiveIgnore) + await _addDefaultDestructiveIgnore(destructiveIgnore) + + instance = new IgnoreHelper(globalIgnore, destructiveIgnore) + } + return instance } -const ignorePerPath = new Map() -const forPath = async ignorePath => { - let ign = null - if (ignorePath && !ignorePerPath.has(ignorePath)) { - ign = ignore() +const _buildIgnore = async ignorePath => { + const ign = ignore() + if (ignorePath) { const content = await readFile(ignorePath) ign.add(content.toString()) - ignorePerPath.set(ignorePath, ign) } + return ign +} + +const _addDefaultDestructiveIgnore = async destructiveIgnore => { + destructiveIgnore.add(BASE_DESTRUCTIVE_IGNORE) +} - return ignorePerPath.get(ignorePath) +const resetInstance = () => { + instance = null } -module.exports.forPath = forPath module.exports.buildIgnoreHelper = buildIgnoreHelper +module.exports.resetInstance = resetInstance