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 add fixkeys command #1022

Merged
merged 40 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4ad994e
fixKeys command added
Jun 12, 2023
b4ebec4
38-add-fixKeys-command
Jun 18, 2023
df7301c
#38: retrieve, change key deploy and cache dependent DRAFT
phjulia Jun 28, 2023
f5579b7
#38: retrieve, change key deploy and cache dependent DRAFT
phjulia Jun 28, 2023
a91ca12
#38: check if type exists, check if key can be updated
phjulia Jun 28, 2023
70c5f0f
#38: added a test for query fixKeys
phjulia Jul 5, 2023
5e43907
#38: test for query
phjulia Jul 10, 2023
d0f8f4c
#38: merge develop
phjulia Jul 11, 2023
97d4355
#38: new query for tests
phjulia Jul 11, 2023
3e09830
#38: revert
phjulia Jul 11, 2023
11ccdb3
#38: test query
phjulia Jul 11, 2023
7cfc7b3
#38: revert state of test class to origin
phjulia Jul 11, 2023
aaeb6ee
#38: removed space in expected automation files
phjulia Jul 12, 2023
e1ad0f1
#38: reverted test changes
phjulia Jul 12, 2023
bbbe4b7
#38: test classes updated
phjulia Jul 12, 2023
d26dfff
#38: exit the function if there are no keys to update
phjulia Jul 12, 2023
9f546ac
#38: redundant variable removed
phjulia Jul 12, 2023
621774a
#38: missing await
phjulia Jul 12, 2023
5568a1b
#38: refactoring
JoernBerkefeld Jul 12, 2023
56de128
#38: fixing first part of test for fixKeys
JoernBerkefeld Jul 12, 2023
4e5b494
#38: tests, return keys of updated items
phjulia Jul 13, 2023
8d4783d
#38: function to get dependent, test method
phjulia Jul 14, 2023
06b7397
#38: expected number of calls
phjulia Jul 14, 2023
4a96dcb
Merge branch 'develop' into feature/38-add-fixkeys-command
phjulia Jul 14, 2023
b0db4b0
#38: warn users about outdated files
phjulia Jul 14, 2023
969dbda
#38: minor fixes
phjulia Jul 14, 2023
afd8ca6
#38: removed unnecessary file
phjulia Jul 14, 2023
156d0ec
#38: test exec context does not reset after execution of prev class
phjulia Jul 14, 2023
3e18cc2
Merge branch 'develop' into feature/38-add-fixkeys-command
phjulia Jul 16, 2023
92e389f
#38: set deploy dir
phjulia Jul 16, 2023
e2b10f5
#38: set retrieve
phjulia Jul 16, 2023
9b1f939
#38: jsdoc & log output improvements
JoernBerkefeld Jul 17, 2023
e05006e
#38: if mockSetup needs to be re-run for DEPLOY tests, do not set Opt…
JoernBerkefeld Jul 17, 2023
527508f
#38: ensure we dont run fixKeys for types that state their key is fixed
JoernBerkefeld Jul 17, 2023
fc2ebfd
#38: get dependent types that reference the fixedType completely or o…
JoernBerkefeld Jul 17, 2023
7c868d4
#38: use standard approach to setting Util.OPTIONS
JoernBerkefeld Jul 17, 2023
4f7866e
#38: improve log output
JoernBerkefeld Jul 17, 2023
a0c91fa
#38: add --like support to fixKeys
JoernBerkefeld Jul 17, 2023
ea56b1f
#38: refactoring
JoernBerkefeld Jul 18, 2023
2a96380
#38: always return array and always error if no keys were fixed
JoernBerkefeld Jul 18, 2023
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
26 changes: 26 additions & 0 deletions docs/dist/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ main class
* [.schedule(businessUnit, [selectedType], [keys])](#Mcdev.schedule) ⇒ <code>Promise.&lt;boolean&gt;</code>
* [.execute(businessUnit, [selectedType], [keys])](#Mcdev.execute) ⇒ <code>Promise.&lt;boolean&gt;</code>
* [.pause(businessUnit, [selectedType], [keys])](#Mcdev.pause) ⇒ <code>Promise.&lt;boolean&gt;</code>
* [.fixKeys(businessUnit, type, [keys])](#Mcdev.fixKeys) ⇒ <code>Array.&lt;string&gt;</code>

<a name="Mcdev.setSkipInteraction"></a>

Expand Down Expand Up @@ -816,6 +817,20 @@ pause an item
| [selectedType] | <code>TYPE.SupportedMetadataTypes</code> | limit to given metadata types |
| [keys] | <code>Array.&lt;string&gt;</code> | customerkey of the metadata |

<a name="Mcdev.fixKeys"></a>

### Mcdev.fixKeys(businessUnit, type, [keys]) ⇒ <code>Array.&lt;string&gt;</code>
Updates the key to match the name field

**Kind**: static method of [<code>Mcdev</code>](#Mcdev)
**Returns**: <code>Array.&lt;string&gt;</code> - list of fixedKeys

| Param | Type | Description |
| --- | --- | --- |
| businessUnit | <code>string</code> | name of BU |
| type | <code>TYPE.SupportedMetadataTypes</code> | limit execution to given metadata type |
| [keys] | <code>Array.&lt;string&gt;</code> | customerkey of the metadata |

<a name="Asset"></a>

## Asset ⇐ [<code>MetadataType</code>](#MetadataType)
Expand Down Expand Up @@ -3368,6 +3383,7 @@ Provides default functionality that can be overwritten by child metadata type cl
* [.deleteByKeyREST(url, key, [handleOutside])](#MetadataType.deleteByKeyREST) ⇒ <code>boolean</code>
* [.readBUMetadataForType(readDir, [listBadKeys], [buMetadata])](#MetadataType.readBUMetadataForType) ⇒ <code>object</code>
* [.getFilesToCommit(keyArr)](#MetadataType.getFilesToCommit) ⇒ <code>Promise.&lt;Array.&lt;string&gt;&gt;</code>
* [.getKeysForFixing(metadataMap)](#MetadataType.getKeysForFixing) ⇒ <code>Array.&lt;string&gt;</code>

<a name="MetadataType.client"></a>

Expand Down Expand Up @@ -4185,6 +4201,16 @@ additionally, the documentation for dataExtension and automation should be retur
| --- | --- | --- |
| keyArr | <code>Array.&lt;string&gt;</code> | customerkey of the metadata |

<a name="MetadataType.getKeysForFixing"></a>

### MetadataType.getKeysForFixing(metadataMap) ⇒ <code>Array.&lt;string&gt;</code>
**Kind**: static method of [<code>MetadataType</code>](#MetadataType)
**Returns**: <code>Array.&lt;string&gt;</code> - list of keys

| Param | Type | Description |
| --- | --- | --- |
| metadataMap | <code>TYPE.MetadataTypeMap</code> | metadata mapped by their keyField |

<a name="MobileCode"></a>

## MobileCode ⇐ [<code>MetadataType</code>](#MetadataType)
Expand Down
24 changes: 24 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,30 @@ yargs
Mcdev.pause(argv.BU, argv.TYPE, csvToArray(argv.KEY));
},
})
.command({
command: 'fixKeys <BU> <TYPE> [KEY]',
aliases: ['fx'],
desc: 'changes the key of the items to match the name',
builder: (yargs) => {
yargs
.positional('BU', {
type: 'string',
describe: 'the business unit where to fix keys',
})
.positional('TYPE', {
type: 'string',
describe: 'metadata type',
})
.positional('KEY', {
type: 'string',
describe: 'key(s) of the metadata component(s)',
});
},
handler: (argv) => {
Mcdev.setOptions(argv);
Mcdev.fixKeys(argv.BU, argv.TYPE, csvToArray(argv.KEY));
},
})
.command({
command: 'upgrade',
aliases: ['up'],
Expand Down
92 changes: 92 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,98 @@ class Mcdev {

return keyArr;
}
/**
* Updates the key to match the name field
*
* @param {string} businessUnit name of BU
* @param {TYPE.SupportedMetadataTypes} type limit execution to given metadata type
* @param {string[]} [keys] customerkey of the metadata
* @returns {string[]} list of fixedKeys
*/
static async fixKeys(businessUnit, type, keys) {
Util.startLogger();
Util.logger.info('mcdev:: fixKeys');
const properties = await config.getProperties();
if (!(await config.checkProperties(properties))) {
// return null here to avoid seeing 2 error messages for the same issue
return null;
}
if (!type || !Util._isValidType(type)) {
return;
}

if (MetadataTypeDefinitions[type].keyField === MetadataTypeDefinitions[type].idField) {
Util.logger.error(`Key cannot be updated for this type`);
return null;
}
let [cred, bu] = businessUnit ? businessUnit.split('/') : [null, null];
let numItemsToUpdate;
let deployed;

const buObject = await Cli.getCredentialObject(
properties,
cred === null ? null : cred + '/' + bu,
null,
true
);
if (buObject !== null) {
cache.initCache(buObject);
cred = buObject.credential;
bu = buObject.businessUnit;
}
Util.logger.info(`\n :: Updating keys for ${type} on ${cred}/${bu}\n`);
try {
try {
MetadataTypeInfo[type].client = auth.getSDK(buObject);
} catch (ex) {
Util.logger.error(ex.message);
return;
}
Util.logger.info(`First retrieve ${type}`);
const retriever = new Retriever(properties, buObject);
const retrieved = await retriever.retrieve([type], keys, null, false);

const typeArr = Object.values(retrieved)[0];
const keysForDeploy = MetadataTypeInfo[type].getKeysForFixing(typeArr[0], type);
numItemsToUpdate = keysForDeploy.length;
if (numItemsToUpdate < 1) {
Util.logger.info(`No items to update. Exiting`);
return true;
}
Util.OPTIONS.changeKeyField = MetadataTypeDefinitions[type].nameField;
properties.directories.deploy = properties.directories.retrieve;
deployed = await Deployer._deployBU(cred, bu, properties, [type], keysForDeploy, true);
const dependentTypes = await this.#getDependentMetadata(type);
// TODO retrieve and update other types that are dependent on this type.
Util.logger.warn(
`Keys for type '${type}' were updated. Retrieve types'${dependentTypes.join(
','
)}' again to have up-to-date data in your retrieve folder`
);
} catch (ex) {
Util.logger.errorStack(ex, 'mcdev.fixKeys failed');
}
Util.logger.info(`\n :: Done\n`);
return Object.keys(Object.values(deployed)[0]);
}
/**
*helper for {@link Mcdev.fixKeys}. Retrieve dependent metadata
*
* @private
*
* @param {string} type type of the metadata passed as a parameter to fixKeys function
* @returns {string[]} array of types that depend on the given type
*/
static async #getDependentMetadata(type) {
const dependencies = [];
Util.logger.info(`\n :: Retrieving dependent metadata \n`);
for (const dependentType of Object.keys(MetadataTypeDefinitions)) {
if (MetadataTypeDefinitions[dependentType].dependencies.includes(type)) {
dependencies.push(dependentType);
}
}
return dependencies;
}
}

module.exports = Mcdev;
40 changes: 40 additions & 0 deletions lib/metadataTypes/MetadataType.js
Original file line number Diff line number Diff line change
Expand Up @@ -2046,6 +2046,46 @@ class MetadataType {
const fileList = keyArr.map((key) => File.normalizePath([path, key + typeExtension]));
return fileList;
}

/**
*
* @param {TYPE.MetadataTypeMap} metadataMap metadata mapped by their keyField
* @returns {string[]} list of keys
*/
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 ${
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(`Updating key for query ${item[this.definition.keyField]}`);
} else {
Util.logger.info(
` ☇ skipping query ${
item[this.definition.keyField]
} - key does not need to be updated`
);
}
}
return keysForDeploy;
}
}

MetadataType.definition = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "testExisting_query_fixedKeys",
"key": "testExisting_query_fixKeys",
"description": "updated on deploy",
"targetKey": "testExisting_dataExtension",
"createdDate": "2022-04-26T15:21:16.453",
"modifiedDate": "2022-04-26T16:04:15.88",
"targetUpdateTypeName": "Overwrite",
"isFrozen": false,
"r__folder_Path": "Query"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SELECT
SubscriberKey as testField
FROM
_Subscribers
WHERE
country IN ('test')
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"queryDefinitionId": "549f0568-607c-4940-afef-437965094dat_fixKeys",
"name": "testExisting_query_fixedKeys",
"key": "testExisting_query_fixKeys",
"description": "bla bla",
"queryText": "SELECT\n SubscriberKey as testField\nFROM\n _Subscribers\nWHERE\n country IN ('test')\n",
"targetName": "testExisting_dataExtension",
"targetKey": "testExisting_dataExtension",
"targetId": "21711373-72c1-ec11-b83b-48df37d1deb7",
"targetDescription": "",
"createdDate": "2022-04-26T15:21:16.453",
"modifiedDate": "2022-04-26T16:02:44.01",
"targetUpdateTypeId": 0,
"targetUpdateTypeName": "Overwrite",
"categoryId": 999,
"isFrozen": false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"queryDefinitionId": "549f0568-607c-4940-afef-437965094dat_fixKeys",
"name": "testExisting_query_fixedKeys",
"key": "testExisting_query_fixedKeys",
"description": "updated on deploy",
"queryText": "SELECT\n SubscriberKey as testField\nFROM\n _Subscribers\nWHERE\n country IN ('test')\n",
"targetName": "testExisting_dataExtension",
"targetKey": "testExisting_dataExtension",
"targetId": "21711373-72c1-ec11-b83b-48df37d1deb7",
"targetDescription": "",
"createdDate": "2022-04-26T15:21:16.453",
"modifiedDate": "2022-04-26T16:04:15.88",
"targetUpdateTypeId": 0,
"targetUpdateTypeName": "Overwrite",
"validatedQueryText": "SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;\r\n\r\nINSERT INTO C518001158.[testDataExtension] ([testField])\r\nSELECT querydef.[testField]\r\nFROM (SELECT SubscriberKey as testField FROM C518001158._Subscribers ) AS querydef \r\nSELECT @rcInsert = @@ROWCOUNT;;\r\n",
"categoryId": 999,
"isFrozen": false
}
19 changes: 18 additions & 1 deletion test/resources/9999999/automation/v1/queries/get-response.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"count": 2,
"count": 3,
"page": 1,
"pageSize": 50,
"items": [
Expand Down Expand Up @@ -36,6 +36,23 @@
"targetUpdateTypeName": "Overwrite",
"categoryId": 999,
"isFrozen": false
},
{
"queryDefinitionId": "549f0568-607c-4940-afef-437965094dat_fixKeys",
"name": "testExisting_query_fixedKeys",
"key": "testExisting_query_fixKeys",
"description": "bla bla",
"queryText": "SELECT\n SubscriberKey as testField\nFROM\n _Subscribers\nWHERE\n country IN ('test')\n",
"targetName": "testExisting_dataExtension",
"targetKey": "testExisting_dataExtension",
"targetId": "21711373-72c1-ec11-b83b-48df37d1deb7",
"targetDescription": "",
"createdDate": "2022-04-26T15:21:16.453",
"modifiedDate": "2022-04-26T16:02:44.01",
"targetUpdateTypeId": 0,
"targetUpdateTypeName": "Overwrite",
"categoryId": 999,
"isFrozen": false
}
]
}
11 changes: 11 additions & 0 deletions test/resources/9999999/query/patch_fixKeys-expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "testExisting_query_fixedKeys",
"key": "testExisting_query_fixedKeys",
"description": "updated on deploy",
"targetKey": "testExisting_dataExtension",
"createdDate": "2022-04-26T15:21:16.453",
"modifiedDate": "2022-04-26T16:04:15.88",
"targetUpdateTypeName": "Overwrite",
"isFrozen": false,
"r__folder_Path": "Query"
}
6 changes: 6 additions & 0 deletions test/resources/9999999/query/patch_fixKeys-expected.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SELECT
SubscriberKey AS testField
FROM
_Subscribers
WHERE
country IN ('test')
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soap:Header>
<wsa:Action>RetrieveResponse</wsa:Action>
<wsa:MessageID>urn:uuid:7ef0345e-b559-4fc4-8986-47e54e1a8a58</wsa:MessageID>
<wsa:RelatesTo>urn:uuid:b2e814a6-517c-4882-9bbb-238bfce951ce</wsa:RelatesTo>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsse:Security>
<wsu:Timestamp wsu:Id="Timestamp-dfc4ae59-8642-4432-b505-554669b47186">
<wsu:Created>2023-04-11T16:33:48Z</wsu:Created>
<wsu:Expires>2023-04-11T16:38:48Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body>
<RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">
<OverallStatus>OK</OverallStatus>
<RequestID>e8eb2988-2f43-4243-a6b0-6ab6b841a6ab</RequestID>
<Results xsi:type="QueryDefinition">
<PartnerKey xsi:nil="true" />
<ObjectID>549f0568-607c-4940-afef-437965094dat_fixKeys</ObjectID>
</Results>
</RetrieveResponseMsg>
</soap:Body>
</soap:Envelope>
Loading
Loading