Skip to content

Commit

Permalink
DXCDT-376: Preserve keywords function (#745)
Browse files Browse the repository at this point in the history
* Adding shouldFieldBePreserved function

* Adding getPreservableFieldsFromAssets function with test

* Adding array keyword replace case

* Adding undefined and null check

* Adding address notation to traversal

* Adding address notation lookup

* Adding stronger tests, cleaning up code

* Adding more context

* Removing unused package

* Adding more tests

* Adding more tests

* Fixing test

* Adding preserve keywords function

* Fixing test

---------

Co-authored-by: Will Vedder <[email protected]>
  • Loading branch information
willvedd and willvedd authored Feb 21, 2023
1 parent e7521f3 commit 75787a7
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 8 deletions.
58 changes: 51 additions & 7 deletions src/keywordPreservation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { get as getByDotNotation, set as setByDotNotation } from 'dot-prop';
import { keywordReplace } from './tools/utils';
import { KeywordMappings } from './types';
import { keywordReplaceArrayRegExp, keywordReplaceStringRegExp } from './tools/utils';
import { cloneDeep } from 'lodash';

/*
RFC for Keyword Preservation: https://github.com/auth0/auth0-deploy-cli/issues/688
Original Github Issue: https://github.com/auth0/auth0-deploy-cli/issues/328
*/

export const shouldFieldBePreserved = (
string: string,
Expand All @@ -15,9 +22,9 @@ export const shouldFieldBePreserved = (
};

export const getPreservableFieldsFromAssets = (
asset: any,
address: string,
keywordMappings: KeywordMappings
asset: object,
keywordMappings: KeywordMappings,
address = ''
): string[] => {
if (typeof asset === 'string') {
if (shouldFieldBePreserved(asset, keywordMappings)) {
Expand All @@ -39,8 +46,8 @@ export const getPreservableFieldsFromAssets = (

return getPreservableFieldsFromAssets(
arrayItem,
`${address}${shouldRenderDot ? '.' : ''}[name=${arrayItem.name}]`,
keywordMappings
keywordMappings,
`${address}${shouldRenderDot ? '.' : ''}[name=${arrayItem.name}]`
);
})
.flat();
Expand All @@ -54,8 +61,8 @@ export const getPreservableFieldsFromAssets = (

return getPreservableFieldsFromAssets(
value,
`${address}${shouldRenderDot ? '.' : ''}${key}`,
keywordMappings
keywordMappings,
`${address}${shouldRenderDot ? '.' : ''}${key}`
);
})
.flat();
Expand Down Expand Up @@ -160,3 +167,40 @@ export const updateAssetsByAddress = (
setByDotNotation(assets, dotNotationAddress, newValue);
return assets;
};

// preserveKeywords is the function that ultimately gets executed during export
// to attempt to preserve keywords (ex: ##KEYWORD##) in local configuration files
// from getting overwritten by remote values during export.
export const preserveKeywords = (
localAssets: object,
remoteAssets: object,
keywordMappings: KeywordMappings
): object => {
const addresses = getPreservableFieldsFromAssets(localAssets, keywordMappings, '');

let updatedRemoteAssets = cloneDeep(remoteAssets);

addresses.forEach((address) => {
const localValue = getAssetsValueByAddress(address, localAssets);
const remoteValue = getAssetsValueByAddress(address, remoteAssets);

const localValueWithReplacement = keywordReplace(localValue, keywordMappings);

const localAndRemoteValuesAreEqual = (() => {
if (typeof remoteValue === 'string') {
return localValueWithReplacement === remoteValue;
}
//TODO: Account for non-string replacements via @@ syntax
})();

if (!localAndRemoteValuesAreEqual) {
console.warn(
`WARNING! The remote value with address of ${address} has value of "${remoteValue}" but will be preserved with "${localValueWithReplacement}" due to keyword preservation.`
);
}

updatedRemoteAssets = updateAssetsByAddress(updatedRemoteAssets, address, localValue);
});

return updatedRemoteAssets;
};
70 changes: 69 additions & 1 deletion test/keywordPreservation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
getAssetsValueByAddress,
convertAddressToDotNotation,
updateAssetsByAddress,
preserveKeywords,
} from '../src/keywordPreservation';
import { cloneDeep } from 'lodash';

describe('#Keyword Preservation', () => {
describe('shouldFieldBePreserved', () => {
Expand Down Expand Up @@ -82,7 +84,6 @@ describe('#Keyword Preservation', () => {
nullField: null,
undefinedField: undefined,
},
'',
{
KEYWORD: 'Travel0',
ARRAY_REPLACE_KEYWORD: ['this value', 'that value'],
Expand Down Expand Up @@ -277,3 +278,70 @@ describe('updateAssetsByAddress', () => {
);
});
});

describe('preserveKeywords', () => {
const mockLocalAssets = {
tenant: {
display_name: 'The ##COMPANY_NAME## Tenant',
allowed_logout_urls: '@@ALLOWED_LOGOUT_URLS@@',
},
roles: null,
hooks: undefined,
actions: [
{
name: 'action-1',
display_name: '##ENV## Action 1',
},
{
name: 'action-2',
display_name: "This action won't exist on remote, will be deleted",
},
],
};

const mockRemoteAssets = {
tenant: {
display_name: 'The Travel0 Tenant',
allowed_logout_urls: ['localhost:3000/logout', 'https://travel0.com/logout'],
},
prompts: {
universal_login_enabled: true,
customText: {},
},
pages: undefined, //TODO: test these cases more thoroughly
rules: null, //TODO: test these cases more thoroughly
actions: [
{
name: 'action-1',
display_name: 'Production Action 1',
},
{
name: 'action-3',
display_name: 'This action exists on remote but not local',
},
],
};

it('should preserve keywords when they correlate to keyword mappings', () => {
const preservedAssets = preserveKeywords(mockLocalAssets, mockRemoteAssets, {
COMPANY_NAME: 'Travel0',
ALLOWED_LOGOUT_URLS: ['localhost:3000/logout', 'https://travel0.com/logout'],
ENV: 'Production',
});

expect(preservedAssets).to.deep.equal(
(() => {
const expected = cloneDeep(mockRemoteAssets);
//@ts-ignore
expected.tenant = mockLocalAssets.tenant;
expected.actions[0].display_name = '##ENV## Action 1';
return expected;
})()
);
});

it('should not preserve keywords when no keyword mappings', () => {
const preservedAssets = preserveKeywords(mockLocalAssets, mockRemoteAssets, {});
expect(preservedAssets).to.deep.equal(mockRemoteAssets);
});
});

0 comments on commit 75787a7

Please sign in to comment.