Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/38 fix keys should ask to retrieve other types #1064

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions docs/dist/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6150,7 +6150,8 @@ used to ensure the program tells surrounding software that an unrecoverable erro
<a name="Util.isTrue"></a>

### Util.isTrue(attrValue) ⇒ <code>boolean</code>
SFMC accepts multiple true values for Boolean attributes for which we are checking here
SFMC accepts multiple true values for Boolean attributes for which we are checking here.
The same problem occurs when evaluating boolean CLI flags

**Kind**: static method of [<code>Util</code>](#Util)
**Returns**: <code>boolean</code> - attribute value == true ? true : false
Expand All @@ -6162,7 +6163,8 @@ SFMC accepts multiple true values for Boolean attributes for which we are checki
<a name="Util.isFalse"></a>

### Util.isFalse(attrValue) ⇒ <code>boolean</code>
SFMC accepts multiple false values for Boolean attributes for which we are checking here
SFMC accepts multiple false values for Boolean attributes for which we are checking here.
The same problem occurs when evaluating boolean CLI flags

**Kind**: static method of [<code>Util</code>](#Util)
**Returns**: <code>boolean</code> - attribute value == false ? true : false
Expand Down Expand Up @@ -6535,6 +6537,7 @@ CLI helper class
* [Cli](#Cli)
* [.initMcdevConfig()](#Cli.initMcdevConfig) ⇒ <code>Promise.&lt;boolean&gt;</code>
* [.addExtraCredential(properties)](#Cli.addExtraCredential) ⇒ <code>Promise.&lt;(boolean\|string)&gt;</code>
* [.postFixKeysReretrieve(type, dependentTypes)](#Cli.postFixKeysReretrieve) ⇒ <code>Promise.&lt;boolean&gt;</code>
* [.logExistingCredentials(properties)](#Cli.logExistingCredentials) ⇒ <code>void</code>
* [.updateCredential(properties, credName)](#Cli.updateCredential) ⇒ <code>Promise.&lt;boolean&gt;</code>
* [.getCredentialObject(properties, target, [isCredentialOnly], [allowAll])](#Cli.getCredentialObject) ⇒ <code>Promise.&lt;TYPE.BuObject&gt;</code>
Expand Down Expand Up @@ -6565,6 +6568,17 @@ Extends template file for properties.json
| --- | --- | --- |
| properties | <code>TYPE.Mcdevrc</code> | config file's json |

<a name="Cli.postFixKeysReretrieve"></a>

### Cli.postFixKeysReretrieve(type, dependentTypes) ⇒ <code>Promise.&lt;boolean&gt;</code>
**Kind**: static method of [<code>Cli</code>](#Cli)
**Returns**: <code>Promise.&lt;boolean&gt;</code> - true if user wants to continue with retrieve

| Param | Type | Description |
| --- | --- | --- |
| type | <code>TYPE.SupportedMetadataTypes</code> | limit execution to given metadata type |
| dependentTypes | <code>Array.&lt;TYPE.SupportedMetadataTypes&gt;</code> | types that depent on type |

<a name="Cli.logExistingCredentials"></a>

### Cli.logExistingCredentials(properties) ⇒ <code>void</code>
Expand Down Expand Up @@ -8042,7 +8056,8 @@ used to ensure the program tells surrounding software that an unrecoverable erro
<a name="Util.isTrue"></a>

### Util.isTrue(attrValue) ⇒ <code>boolean</code>
SFMC accepts multiple true values for Boolean attributes for which we are checking here
SFMC accepts multiple true values for Boolean attributes for which we are checking here.
The same problem occurs when evaluating boolean CLI flags

**Kind**: static method of [<code>Util</code>](#Util)
**Returns**: <code>boolean</code> - attribute value == true ? true : false
Expand All @@ -8054,7 +8069,8 @@ SFMC accepts multiple true values for Boolean attributes for which we are checki
<a name="Util.isFalse"></a>

### Util.isFalse(attrValue) ⇒ <code>boolean</code>
SFMC accepts multiple false values for Boolean attributes for which we are checking here
SFMC accepts multiple false values for Boolean attributes for which we are checking here.
The same problem occurs when evaluating boolean CLI flags

**Kind**: static method of [<code>Util</code>](#Util)
**Returns**: <code>boolean</code> - attribute value == false ? true : false
Expand Down
26 changes: 21 additions & 5 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,7 @@ class Mcdev {
}

if (businessUnit === '*') {
Util.OPTIONS._multiBuExecution = true;
Util.logger.info(
`:: ${lang_present} the ${selectedType} on all BUs for all credentials`
);
Expand Down Expand Up @@ -916,6 +917,7 @@ class Mcdev {
}
}
if (bu === '*' && properties.credentials && properties.credentials[cred]) {
Util.OPTIONS._multiBuExecution = true;
Util.logger.info(`:: ${lang_present} ${selectedType} on all BUs for ${cred}`);
for (const bu in properties.credentials[cred].businessUnits) {
resultObj[cred + '/' + bu] = await this.#runOnBU(
Expand Down Expand Up @@ -1123,11 +1125,25 @@ class Mcdev {
actuallyFixedKeys.length === 1 ? '' : 's'
} of type ${type}`
);
Util.logger.warn(
` Please manually re-retrieve the following types as your local copies might now be outdated: ${Util.getGrayMsg(
dependentTypes.join(', ')
)}`
);
if (dependentTypes.length) {
Util.logger.warn(
`Please re-retrieve the following types as your local copies might now be outdated: ${Util.getGrayMsg(
dependentTypes.join(', ')
)}`
);
const reRetrieve = await Cli.postFixKeysReretrieve(type, dependentTypes);
if (reRetrieve) {
Util.logger.info(
`Retrieving latest versions of ${dependentTypes.join(', ')} from server`
);
const retriever = new Retriever(properties, buObject);
await retriever.retrieve(dependentTypes, null, null, false);
}
} else {
Util.logger.info(
`No dependent types found that need to be re-retrieved after fixing keys of type ${type}.`
);
}
} else {
Util.logger.warn(`No keys of type ${type} updated.`);
}
Expand Down
67 changes: 36 additions & 31 deletions lib/metadataTypes/MetadataType.js
Original file line number Diff line number Diff line change
Expand Up @@ -2054,41 +2054,46 @@ class MetadataType {
*/
static getKeysForFixing(metadataMap) {
const keysForDeploy = [];

for (const item of Object.values(metadataMap)) {
if (item[this.definition.nameField].length > this.definition.maxKeyLength) {
Util.logger.warn(
`Name of the item ${
item[this.definition.keyField]
} is too long for a key. Consider renaming your item. Key will be equal first ${
if (Object.keys(metadataMap).length) {
Util.logger.info(
`Searching for ${this.definition.type} keys among downloaded items that need fixing:`
);
for (const item of Object.values(metadataMap)) {
if (item[this.definition.nameField].length > this.definition.maxKeyLength) {
Util.logger.warn(
`Name of the item ${
item[this.definition.keyField]
} is too long for a key. Consider renaming your item. Key will be equal first ${
this.definition.maxKeyLength
} characters of the name`
);
item[this.definition.nameField] = item[this.definition.nameField].slice(
0,
this.definition.maxKeyLength
} characters of the name`
);
item[this.definition.nameField] = item[this.definition.nameField].slice(
0,
this.definition.maxKeyLength
);
}
);
}

if (
item[this.definition.nameField] != item[this.definition.keyField] &&
!this.definition.keyIsFixed
) {
keysForDeploy.push(item[this.definition.keyField]);
Util.logger.info(
` - added ${this.definition.type} to fixKey queue: ${
item[this.definition.keyField]
}`
);
} else {
Util.logger.info(
Util.getGrayMsg(
` ☇ skipping ${this.definition.type} ${
if (
item[this.definition.nameField] != item[this.definition.keyField] &&
!this.definition.keyIsFixed
) {
keysForDeploy.push(item[this.definition.keyField]);
Util.logger.info(
` - added ${this.definition.type} to fixKey queue: ${
item[this.definition.keyField]
}: key does not need to be updated`
)
);
}`
);
} else {
Util.logger.info(
Util.getGrayMsg(
` ☇ skipping ${this.definition.type} ${
item[this.definition.keyField]
}: key does not need to be updated`
)
);
}
}
Util.logger.info(`Found ${keysForDeploy.length} ${this.definition.type} keys to fix`);
}
return keysForDeploy;
}
Expand Down
40 changes: 40 additions & 0 deletions lib/util/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,46 @@ const Cli = {
return null;
}
},

/**
*
* @param {TYPE.SupportedMetadataTypes} type limit execution to given metadata type
* @param {TYPE.SupportedMetadataTypes[]} dependentTypes types that depent on type
* @returns {Promise.<boolean>} true if user wants to continue with retrieve
*/
async postFixKeysReretrieve(type, dependentTypes) {
if (Util.isTrue(Util.skipInteraction?.fixKeysReretrieve)) {
return true;
} else if (Util.isFalse(Util.skipInteraction?.fixKeysReretrieve)) {
return false;
} else {
const now = await inquirer.prompt([
{
type: 'confirm',
name: 'fixKeysReretrieve',
message: `Do you want to re-retrieve dependent types (${dependentTypes.join(
', '
)}) now?`,
default: true,
},
]);
if (Util.OPTIONS._multiBuExecution) {
const remember = await inquirer.prompt([
{
type: 'confirm',
name: 'rememberFixKeysReretrieve',
message: `Remember answer for other BUs?`,
default: true,
},
]);
if (remember.rememberFixKeysReretrieve) {
Util.skipInteraction ||= {};
Util.skipInteraction.fixKeysReretrieve = now.fixKeysReretrieve;
}
}
return now.fixKeysReretrieve;
}
},
/**
* helper that logs to cli which credentials are already existing in our config file
*
Expand Down
10 changes: 6 additions & 4 deletions lib/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,22 +135,24 @@ const Util = {
process.exitCode = 1;
},
/**
* SFMC accepts multiple true values for Boolean attributes for which we are checking here
* SFMC accepts multiple true values for Boolean attributes for which we are checking here.
* The same problem occurs when evaluating boolean CLI flags
*
* @param {*} attrValue value
* @returns {boolean} attribute value == true ? true : false
*/
isTrue(attrValue) {
return ['true', 'TRUE', 'True', '1', 1, 'Y', true].includes(attrValue);
return ['true', 'TRUE', 'True', '1', 1, 'Y', 'y', true].includes(attrValue);
},
/**
* SFMC accepts multiple false values for Boolean attributes for which we are checking here
* SFMC accepts multiple false values for Boolean attributes for which we are checking here.
* The same problem occurs when evaluating boolean CLI flags
*
* @param {*} attrValue value
* @returns {boolean} attribute value == false ? true : false
*/
isFalse(attrValue) {
return ['false', 'FALSE', 'False', '0', 0, 'N', false].includes(attrValue);
return ['false', 'FALSE', 'False', '0', 0, 'N', 'n', false].includes(attrValue);
},

/**
Expand Down
1 change: 0 additions & 1 deletion test/type.automation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ describe('type: automation', () => {
);
return;
});
it('Should change the key during update via --changeKeyValue');
});
describe('Templating ================', () => {
it('Should create a automation template via retrieveAsTemplate and build it', async () => {
Expand Down
1 change: 0 additions & 1 deletion test/type.dataExtension.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ describe('type: dataExtension', () => {
);
return;
});
it('Should change the key during update via --changeKeyValue');
it('Should rename fields');
});
describe('Templating ================', () => {
Expand Down
1 change: 0 additions & 1 deletion test/type.fileTransfer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ describe('type: fileTransfer', () => {
);
return;
});
it('Should change the key during update via --changeKeyValue ');
});
describe('Templating ================', () => {
it('Should create a fileTransfer template via retrieveAsTemplate and build it', async () => {
Expand Down
1 change: 0 additions & 1 deletion test/type.importFile.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ describe('type: importFile', () => {
);
return;
});
it('Should change the key during update via --changeKeyValue ');
});
describe('Templating ================', () => {
it('Should create a importFile template via retrieveAsTemplate and build it', async () => {
Expand Down
1 change: 0 additions & 1 deletion test/type.mobileKeyword.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ describe('type: mobileKeyword', () => {
);
return;
});
it('Should change the key during update via --changeKeyValue');
});
describe('Templating ================', () => {
it('Should create a mobileKeyword template via retrieveAsTemplate and build it', async () => {
Expand Down
47 changes: 44 additions & 3 deletions test/type.query.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ describe('type: query', () => {
});
it('Should NOT fixKeys and deploy', async () => {
// WHEN
handler.setOptions({ skipInteraction: { fixKeysReretrieve: false } });
const resultFixKeys = await handler.fixKeys('testInstance/testBU', 'query', [
'testExisting_query',
]);
Expand Down Expand Up @@ -354,8 +355,9 @@ describe('type: query', () => {
);
return;
});
it('Should fixKeys and deploy by key', async () => {
it('Should fixKeys and deploy by key WITHOUT re-retrieving dependent types', async () => {
// WHEN
handler.setOptions({ skipInteraction: { fixKeysReretrieve: false } });
const resultFixKeys = await handler.fixKeys('testInstance/testBU', 'query', [
'testExisting_query_fixKeys',
'testExisting_query',
Expand Down Expand Up @@ -389,9 +391,48 @@ describe('type: query', () => {
);
return;
});
it('Should fixKeys and deploy via --like', async () => {
it('Should fixKeys and deploy by key AND re-retrieve dependent types', async () => {
// WHEN
handler.setOptions({ like: { key: 'testExisting_query_f%' } });
handler.setOptions({ skipInteraction: { fixKeysReretrieve: true } });
const resultFixKeys = await handler.fixKeys('testInstance/testBU', 'query', [
'testExisting_query_fixKeys',
'testExisting_query',
]);
assert.equal(
resultFixKeys['testInstance/testBU'].length,
1,
'returned number of keys does not correspond to number of expected fixed keys'
);
assert.equal(
resultFixKeys['testInstance/testBU'][0],
'testExisting_query_fixedKeys',
'returned keys do not correspond to expected fixed keys'
);
// THEN
assert.equal(process.exitCode, false, 'fixKeys should not have thrown an error');
// confirm updated item
assert.deepEqual(
await testUtils.getActualJson('testExisting_query_fixedKeys', 'query'),
await testUtils.getExpectedJson('9999999', 'query', 'patch_fixKeys'),
'returned metadata was not equal expected for update query'
);
expect(
file(testUtils.getActualFile('testExisting_query_fixedKeys', 'query', 'sql'))
).to.equal(file(testUtils.getExpectedFile('9999999', 'query', 'patch_fixKeys', 'sql')));
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
31,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
});
it('Should fixKeys and deploy via --like WITHOUT re-retrieving dependent types', async () => {
// WHEN
handler.setOptions({
like: { key: 'testExisting_query_f%' },
skipInteraction: { fixKeysReretrieve: false },
});
const resultFixKeys = await handler.fixKeys('testInstance/testBU', 'query');
assert.equal(
resultFixKeys['testInstance/testBU'].length,
Expand Down
1 change: 0 additions & 1 deletion test/type.user.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ describe('type: user', () => {
);
return;
});
it('Should change the key during update with --changeKeyValue');
});
describe('Templating ================', () => {
// it('Should create a user template via retrieveAsTemplate and build it', async () => {});
Expand Down