From 35438e9412a09d7073eee984ef4c17ead142bb47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 10 Aug 2023 13:15:17 +0200
Subject: [PATCH 01/70] #940: basic concept for fixing shared DEs incl new
--fixShared option
---
docs/dist/documentation.md | 16 +++++++++++
lib/cli.js | 8 +++++-
lib/index.js | 1 +
lib/metadataTypes/DataExtension.js | 43 +++++++++++++++++++++++++++++-
4 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 8a2189b07..e2b5ed302 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -219,6 +219,9 @@ Provides default functionality that can be overwritten by child metadata type cl
Automation.(metadataMap, originalMetadataMap, key, [oldKey]) ⇒ Promise.<{key:string, response:object}>
helper for postDeployTasks
+DataExtension.(upsertedMetadata, originalMetadata, createdUpdated) ⇒ void
+helper for postDeployTasks
+
getUserName(userList, item, fieldname) ⇒ string
setupSDK(sessionKey, authObject) ⇒ SDK
@@ -8539,6 +8542,19 @@ helper for [postDeployTasks](#Automation.postDeployTasks)
| key | string
| current customer key |
| [oldKey] | string
| old customer key before fixKey / changeKeyValue / changeKeyField |
+
+
+## DataExtension.(upsertedMetadata, originalMetadata, createdUpdated) ⇒ void
+helper for [postDeployTasks](#DataExtension.postDeployTasks)
+
+**Kind**: global function
+
+| Param | Type | Description |
+| --- | --- | --- |
+| upsertedMetadata | TYPE.DataExtensionMap
| metadata mapped by their keyField |
+| originalMetadata | TYPE.DataExtensionMap
| metadata to be updated (contains additioanl fields) |
+| createdUpdated | Object
| counter representing successful creates/updates |
+
## getUserName(userList, item, fieldname) ⇒ string
diff --git a/lib/cli.js b/lib/cli.js
index 8c198cf97..81c9b59c1 100644
--- a/lib/cli.js
+++ b/lib/cli.js
@@ -45,7 +45,7 @@ yargs
},
})
.command({
- command: 'deploy [BU] [TYPE] [KEY] [--fromRetrieve] [--refresh]',
+ command: 'deploy [BU] [TYPE] [KEY]',
aliases: ['d'],
desc: 'deploys local metadata to a business unit',
builder: (yargs) => {
@@ -97,6 +97,12 @@ yargs
group: 'Options for deploy:',
describe:
'optionally start existing schedule instead of running item once immediately (only works for automations)',
+ })
+ .option('fixShared', {
+ type: 'boolean',
+ group: 'Options for deploy:',
+ describe:
+ "optionally ensure that updates to shared DataExtensions become visible in child BU's data designer (SF Known issue W-11031095)",
});
},
handler: (argv) => {
diff --git a/lib/index.js b/lib/index.js
index b34ae4102..bcc150061 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -56,6 +56,7 @@ class Mcdev {
'commitHistory',
'execute',
'filter',
+ 'fixShared',
'fromRetrieve',
'json',
'like',
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 7210095a6..45508b44d 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -283,7 +283,7 @@ class DataExtension extends MetadataType {
* @param {{created: number, updated: number}} createdUpdated counter representing successful creates/updates
* @returns {void}
*/
- static postDeployTasks(upsertedMetadata, originalMetadata, createdUpdated) {
+ static async postDeployTasks(upsertedMetadata, originalMetadata, createdUpdated) {
for (const key in upsertedMetadata) {
const item = upsertedMetadata[key];
@@ -354,6 +354,47 @@ class DataExtension extends MetadataType {
DataExtensionField.postRetrieveTasks(field, true);
}
}
+ await this.#postDeployFixShared(upsertedMetadata, originalMetadata);
+ }
+
+ /**
+ * helper for {@link DataExtension.postDeployTasks}
+ *
+ * @param {TYPE.DataExtensionMap} upsertedMetadata metadata mapped by their keyField
+ * @param {TYPE.DataExtensionMap} originalMetadata metadata to be updated (contains additioanl fields)
+ * @param {{created: number, updated: number}} createdUpdated counter representing successful creates/updates
+ * @returns {void}
+ */
+ static async #postDeployFixShared(upsertedMetadata, originalMetadata, createdUpdated) {
+ if (this.buObject.eid !== this.buObject.mid || createdUpdated.updated === 0) {
+ // only if we were executing a deploy on parent bu could we be deploying shared data extensions
+ // only if updates were made could the issue in https://issues.salesforce.com/#q=W-11031095 affect data designer
+ return;
+ }
+ // find all shared data extensions
+ const sharedDataExtensions = [];
+ for (const key in upsertedMetadata) {
+ const item = upsertedMetadata[key];
+ const originalItem = originalMetadata[key];
+ if (
+ item.r__folder_ContentType === 'shared_dataextension' ||
+ originalItem.r__folder_ContentType === 'shared_dataextension'
+ ) {
+ sharedDataExtensions.push(item);
+ }
+ }
+ if (sharedDataExtensions.length > 0 && !Util.OPTIONS.fixShared) {
+ Util.logger.warn(
+ 'Shared Data Extensions were updated but fixShared option is not set. This can result in your changes not being visible on child BUs.'
+ );
+ // TODO replace with 2 inquirer questions to 1) ask if child BUs should be fixed if needed and 2) select which BUs to run this for
+ }
+ if (sharedDataExtensions.length > 0 && Util.OPTIONS.fixShared) {
+ // TODO initiate actual search & update logic
+ } else {
+ // no shared dataExtensions or fixShared option not enabled
+ return;
+ }
}
/**
From 82aaa6cbc631da7647d872bbfcb75a3dad1d22b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 10 Aug 2023 16:03:11 +0200
Subject: [PATCH 02/70] #940: refactoring
---
docs/dist/documentation.md | 26 ++++++
lib/metadataTypes/DataExtension.js | 137 ++++++++++++++++-------------
2 files changed, 102 insertions(+), 61 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index e2b5ed302..3c0415605 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -1301,6 +1301,7 @@ AttributeSet MetadataType
* [AttributeSet](#AttributeSet) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], [key])](#AttributeSet.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveForCache()](#AttributeSet.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.retrieveForSharedDEs([deKeys])](#AttributeSet.retrieveForSharedDEs) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.parseResponseBody(body, [singleRetrieve])](#AttributeSet.parseResponseBody) ⇒ TYPE.MetadataTypeMap
* [.postRetrieveTasks(metadata)](#AttributeSet.postRetrieveTasks) ⇒ TYPE.MetadataTypeItem
* [._getSystemValueDefinitions()](#AttributeSet._getSystemValueDefinitions) ⇒ Array.<object>
@@ -1327,6 +1328,18 @@ Retrieves Metadata of schema set definitions for caching.
**Kind**: static method of [AttributeSet
](#AttributeSet)
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise
+
+
+### AttributeSet.retrieveForSharedDEs([deKeys]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+Retrieves Metadata of schema set definitions for caching.
+
+**Kind**: static method of [AttributeSet
](#AttributeSet)
+**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise
+
+| Param | Type | Description |
+| --- | --- | --- |
+| [deKeys] | Array.<string>
| if provided, only shared DEs with these keys will be returned |
+
### AttributeSet.parseResponseBody(body, [singleRetrieve]) ⇒ TYPE.MetadataTypeMap
@@ -1784,6 +1797,7 @@ DataExtension MetadataType
* [.update(metadata)](#DataExtension.update) ⇒ Promise
* [.postDeployTasks(upsertedMetadata, originalMetadata, createdUpdated)](#DataExtension.postDeployTasks) ⇒ void
* [.retrieve(retrieveDir, [additionalFields], [_], [key])](#DataExtension.retrieve) ⇒ Promise.<{metadata: TYPE.DataExtensionMap, type: string}>
+ * [.retrieveSharedForCache([additionalFields])](#DataExtension.retrieveSharedForCache) ⇒ Promise.<TYPE.DataExtensionMap>
* [.retrieveChangelog([additionalFields])](#DataExtension.retrieveChangelog) ⇒ Promise.<{metadata: TYPE.DataExtensionMap, type: string}>
* [.postRetrieveTasks(metadata)](#DataExtension.postRetrieveTasks) ⇒ TYPE.DataExtensionItem
* [.preDeployTasks(metadata)](#DataExtension.preDeployTasks) ⇒ Promise.<TYPE.DataExtensionItem>
@@ -1876,6 +1890,18 @@ Retrieves dataExtension metadata. Afterwards starts retrieval of dataExtensionCo
| [_] | void
| unused parameter |
| [key] | string
| customer key of single item to retrieve |
+
+
+### DataExtension.retrieveSharedForCache([additionalFields]) ⇒ Promise.<TYPE.DataExtensionMap>
+helper for [retrieve](#DataExtension.retrieve) and for AttributeSet.retrieveForSharedDEs
+
+**Kind**: static method of [DataExtension
](#DataExtension)
+**Returns**: Promise.<TYPE.DataExtensionMap>
- keyField => metadata map
+
+| Param | Type | Description |
+| --- | --- | --- |
+| [additionalFields] | Array.<string>
| Returns specified fields even if their retrieve definition is not set to true |
+
### DataExtension.retrieveChangelog([additionalFields]) ⇒ Promise.<{metadata: TYPE.DataExtensionMap, type: string}>
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 45508b44d..3c8f5664e 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -434,67 +434,7 @@ class DataExtension extends MetadataType {
await this._attachFields(metadata, fieldOptions, additionalFields);
}
if (!retrieveDir && this.buObject.eid !== this.buObject.mid) {
- // for caching, we want to retrieve shared DEs as well from the instance parent BU
- Util.logger.info(
- ' - Caching dependent Metadata: dataExtension (shared via _ParentBU_)'
- );
- /** @type {TYPE.BuObject} */
- const buObjectParentBu = {
- eid: this.properties.credentials[this.buObject.credential].eid,
- mid: this.properties.credentials[this.buObject.credential].eid,
- businessUnit: Util.parentBuName,
- credential: this.buObject.credential,
- };
- try {
- this.client = auth.getSDK(buObjectParentBu);
- } catch (ex) {
- Util.logger.error(ex.message);
- return;
- }
- const metadataParentBu = await this._retrieveAll(additionalFields);
-
- // get shared folders to match our shared / synched Data Extensions
- const subTypeArr = this.definition.dependencies
- .filter((item) => item.startsWith('folder-'))
- .map((item) => item.slice(7));
- Util.logger.info(' - Caching dependent Metadata: folder (shared via _ParentBU_)');
- Util.logSubtypes(subTypeArr);
- Folder.client = this.client;
- Folder.buObject = buObjectParentBu;
- Folder.properties = this.properties;
- const result = await Folder.retrieveForCache(null, subTypeArr);
- cache.mergeMetadata('folder', result.metadata, this.buObject.eid);
-
- // get the types and clean out non-shared ones
- const folderTypesFromParent = require('../MetadataTypeDefinitions').folder
- .folderTypesFromParent;
- for (const metadataEntry in metadataParentBu) {
- try {
- // get the data extension type from the folder
- const folderContentType = cache.searchForField(
- 'folder',
- metadataParentBu[metadataEntry].CategoryID,
- 'ID',
- 'ContentType',
- this.buObject.eid
- );
- if (!folderTypesFromParent.includes(folderContentType)) {
- Util.logger.verbose(
- `removing ${metadataEntry} because r__folder_ContentType '${folderContentType}' identifies this DE as not being shared`
- );
- delete metadataParentBu[metadataEntry];
- }
- } catch (ex) {
- Util.logger.debug(
- `removing ${metadataEntry} because of error while retrieving r__folder_ContentType: ${ex.message}`
- );
- delete metadataParentBu[metadataEntry];
- }
- }
-
- // revert client to current default
- this.client = auth.getSDK(this.buObject);
- Folder.client = auth.getSDK(this.buObject);
+ const metadataParentBu = await this.retrieveSharedForCache(additionalFields);
// make sure to overwrite parent bu DEs with local ones
metadata = { ...metadataParentBu, ...metadata };
@@ -510,6 +450,81 @@ class DataExtension extends MetadataType {
return { metadata: metadata, type: 'dataExtension' };
}
+ /**
+ * helper for {@link DataExtension.retrieve} and for AttributeSet.retrieveForSharedDEs
+ *
+ * @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
+ * @returns {Promise.} keyField => metadata map
+ */
+ static async retrieveSharedForCache(additionalFields = []) {
+ // for caching, we want to retrieve shared DEs as well from the instance parent BU
+ Util.logger.info(' - Caching dependent Metadata: dataExtension (shared via _ParentBU_)');
+ const buObjectBak = this.buObject;
+ const clientBak = this.client;
+ /** @type {TYPE.BuObject} */
+ const buObjectParentBu = {
+ eid: this.properties.credentials[this.buObject.credential].eid,
+ mid: this.properties.credentials[this.buObject.credential].eid,
+ businessUnit: Util.parentBuName,
+ credential: this.buObject.credential,
+ };
+ try {
+ this.buObject = buObjectParentBu;
+ this.client = auth.getSDK(buObjectParentBu);
+ } catch (ex) {
+ Util.logger.error(ex.message);
+ return;
+ }
+ const metadataParentBu = await this._retrieveAll(additionalFields);
+
+ // get shared folders to match our shared / synched Data Extensions
+ const subTypeArr = this.definition.dependencies
+ .filter((item) => item.startsWith('folder-'))
+ .map((item) => item.slice(7));
+ Util.logger.info(' - Caching dependent Metadata: folder (shared via _ParentBU_)');
+ Util.logSubtypes(subTypeArr);
+ Folder.client = this.client;
+ Folder.buObject = this.buObject;
+ Folder.properties = this.properties;
+ const result = await Folder.retrieveForCache(null, subTypeArr);
+ cache.mergeMetadata('folder', result.metadata, this.buObject.eid);
+
+ // get the types and clean out non-shared ones
+ const folderTypesFromParent = require('../MetadataTypeDefinitions').folder
+ .folderTypesFromParent;
+ for (const metadataEntry in metadataParentBu) {
+ try {
+ // get the data extension type from the folder
+ const folderContentType = cache.searchForField(
+ 'folder',
+ metadataParentBu[metadataEntry].CategoryID,
+ 'ID',
+ 'ContentType',
+ this.buObject.eid
+ );
+ if (!folderTypesFromParent.includes(folderContentType)) {
+ Util.logger.verbose(
+ `removing ${metadataEntry} because r__folder_ContentType '${folderContentType}' identifies this DE as not being shared`
+ );
+ delete metadataParentBu[metadataEntry];
+ }
+ } catch (ex) {
+ Util.logger.debug(
+ `removing ${metadataEntry} because of error while retrieving r__folder_ContentType: ${ex.message}`
+ );
+ delete metadataParentBu[metadataEntry];
+ }
+ }
+
+ // revert client to current default
+ this.client = clientBak;
+ this.buObject = buObjectBak;
+ Folder.client = clientBak;
+ Folder.buObject = buObjectBak;
+
+ return metadataParentBu;
+ }
+
/**
* helper to retrieve all dataExtension fields and attach them to the dataExtension metadata
*
From 8eaeb04a60e1cf72805c98a4ed6f413c52d4d2ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 12:11:04 +0200
Subject: [PATCH 03/70] #940: fix data model for shared dataextensions
postDeploy
---
docs/dist/documentation.md | 110 ++++++++-
lib/cli.js | 1 -
lib/metadataTypes/AttributeSet.js | 32 +++
lib/metadataTypes/DataExtension.js | 307 ++++++++++++++++++++++--
lib/metadataTypes/DataExtensionField.js | 32 ++-
5 files changed, 446 insertions(+), 36 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 3c0415605..f15b793b0 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -222,6 +222,22 @@ Provides default functionality that can be overwritten by child metadata type cl
DataExtension.(upsertedMetadata, originalMetadata, createdUpdated) ⇒ void
helper for postDeployTasks
+DataExtension.(childBuName, buObjectParent, clientParent, sharedDataExtensions) ⇒ Promise.<Array.<string>>
+helper for DataExtension.#postDeployFixShared
+
+DataExtension.(deId, deKey, buObjectChildBu, clientChildBu, buObjectParent, clientParent) ⇒ Promise
+
+DataExtension.(randomSuffix, buObjectChildBu, clientChildBu, deKey, fieldObjectID) ⇒ Promise
+
+DataExtension.(buObjectChildBu, clientChildBu, deKey, deId) ⇒ Promise.<string>
+helper for DataExtension.#fixShared_item
+
+DataExtension.(randomSuffix, buObjectParent, clientParent, deKey) ⇒ Promise.<string>
+helper for DataExtension.#fixShared_item
+
+DataExtension.() ⇒ Array.<string>
+helper for DataExtension.#postDeployFixShared
+
getUserName(userList, item, fieldname) ⇒ string
setupSDK(sessionKey, authObject) ⇒ SDK
@@ -1301,7 +1317,7 @@ AttributeSet MetadataType
* [AttributeSet](#AttributeSet) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], [key])](#AttributeSet.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveForCache()](#AttributeSet.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.retrieveForSharedDEs([deKeys])](#AttributeSet.retrieveForSharedDEs) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.retrieveForSharedDEs(sharedDataExtensions)](#AttributeSet.retrieveForSharedDEs) ⇒ Promise.<Array.<string>>
* [.parseResponseBody(body, [singleRetrieve])](#AttributeSet.parseResponseBody) ⇒ TYPE.MetadataTypeMap
* [.postRetrieveTasks(metadata)](#AttributeSet.postRetrieveTasks) ⇒ TYPE.MetadataTypeItem
* [._getSystemValueDefinitions()](#AttributeSet._getSystemValueDefinitions) ⇒ Array.<object>
@@ -1330,15 +1346,15 @@ Retrieves Metadata of schema set definitions for caching.
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise
-### AttributeSet.retrieveForSharedDEs([deKeys]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+### AttributeSet.retrieveForSharedDEs(sharedDataExtensions) ⇒ Promise.<Array.<string>>
Retrieves Metadata of schema set definitions for caching.
**Kind**: static method of [AttributeSet
](#AttributeSet)
-**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise
+**Returns**: Promise.<Array.<string>>
- Promise of list of shared dataExtension IDs
| Param | Type | Description |
| --- | --- | --- |
-| [deKeys] | Array.<string>
| if provided, only shared DEs with these keys will be returned |
+| sharedDataExtensions | object
| list of IDs of shared data extensions |
@@ -2036,7 +2052,7 @@ DataExtensionField MetadataType
* [.postRetrieveTasks(metadata, forDataExtension)](#DataExtensionField.postRetrieveTasks) ⇒ TYPE.DataExtensionFieldItem
* [.prepareDeployColumnsOnUpdate(deployColumns, deKey)](#DataExtensionField.prepareDeployColumnsOnUpdate) ⇒ Promise.<Object.<string, TYPE.DataExtensionFieldItem>>
* [.deleteByKey(customerKey)](#DataExtensionField.deleteByKey) ⇒ Promise.<boolean>
- * [.deleteByKeySOAP(customerKey)](#DataExtensionField.deleteByKeySOAP) ⇒ boolean
+ * [.deleteByKeySOAP(customerKey, [fieldId])](#DataExtensionField.deleteByKeySOAP) ⇒ boolean
* [.postDeleteTasks(customerKey)](#DataExtensionField.postDeleteTasks) ⇒ void
@@ -2131,7 +2147,7 @@ Delete a metadata item from the specified business unit
-### DataExtensionField.deleteByKeySOAP(customerKey) ⇒ boolean
+### DataExtensionField.deleteByKeySOAP(customerKey, [fieldId]) ⇒ boolean
Delete a data extension from the specified business unit
**Kind**: static method of [DataExtensionField
](#DataExtensionField)
@@ -2140,6 +2156,7 @@ Delete a data extension from the specified business unit
| Param | Type | Description |
| --- | --- | --- |
| customerKey | string
| Identifier of metadata |
+| [fieldId] | string
| for programmatic deletes only one can pass in the ID directly |
@@ -8581,6 +8598,87 @@ helper for [postDeployTasks](#DataExtension.postDeployTasks)
| originalMetadata | TYPE.DataExtensionMap
| metadata to be updated (contains additioanl fields) |
| createdUpdated | Object
| counter representing successful creates/updates |
+
+
+## DataExtension.(childBuName, buObjectParent, clientParent, sharedDataExtensions) ⇒ Promise.<Array.<string>>
+helper for [DataExtension.#postDeployFixShared](DataExtension.#postDeployFixShared)
+
+**Kind**: global function
+**Returns**: Promise.<Array.<string>>
- updated shared DE keys on BU
+
+| Param | Type | Description |
+| --- | --- | --- |
+| childBuName | string
| name of child BU to fix |
+| buObjectParent | TYPE.BuObject
| bu object for parent BU |
+| clientParent | object
| SDK for parent BU |
+| sharedDataExtensions | object
| list of IDs of shared data extensions |
+
+
+
+## DataExtension.(deId, deKey, buObjectChildBu, clientChildBu, buObjectParent, clientParent) ⇒ Promise
+**Kind**: global function
+**Returns**: Promise
- -
+
+| Param | Type | Description |
+| --- | --- | --- |
+| deId | string
| data extension ObjectID |
+| deKey | string
| dataExtension key |
+| buObjectChildBu | TYPE.BuObject
| BU object for Child BU |
+| clientChildBu | object
| SDK for child BU |
+| buObjectParent | TYPE.BuObject
| BU object for Parent BU |
+| clientParent | object
| SDK for parent BU |
+
+
+
+## DataExtension.(randomSuffix, buObjectChildBu, clientChildBu, deKey, fieldObjectID) ⇒ Promise
+**Kind**: global function
+**Returns**: Promise
- -
+
+| Param | Type | Description |
+| --- | --- | --- |
+| randomSuffix | string
| - |
+| buObjectChildBu | TYPE.BuObject
| BU object for Child BU |
+| clientChildBu | object
| SDK for child BU |
+| deKey | string
| dataExtension key |
+| fieldObjectID | string
| field ObjectID |
+
+
+
+## DataExtension.(buObjectChildBu, clientChildBu, deKey, deId) ⇒ Promise.<string>
+helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
+
+**Kind**: global function
+**Returns**: Promise.<string>
- randomSuffix
+
+| Param | Type | Description |
+| --- | --- | --- |
+| buObjectChildBu | TYPE.BuObject
| BU object for Child BU |
+| clientChildBu | object
| SDK for child BU |
+| deKey | string
| dataExtension key |
+| deId | string
| dataExtension ObjectID |
+
+
+
+## DataExtension.(randomSuffix, buObjectParent, clientParent, deKey) ⇒ Promise.<string>
+helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
+
+**Kind**: global function
+**Returns**: Promise.<string>
- fieldObjectID
+
+| Param | Type | Description |
+| --- | --- | --- |
+| randomSuffix | string
| - |
+| buObjectParent | TYPE.BuObject
| BU object for Parent BU |
+| clientParent | object
| SDK for parent BU |
+| deKey | string
| dataExtension key |
+
+
+
+## DataExtension.() ⇒ Array.<string>
+helper for [DataExtension.#postDeployFixShared](DataExtension.#postDeployFixShared)
+
+**Kind**: global function
+**Returns**: Array.<string>
- list of selected BU names
## getUserName(userList, item, fieldname) ⇒ string
diff --git a/lib/cli.js b/lib/cli.js
index 81c9b59c1..8decd9ece 100644
--- a/lib/cli.js
+++ b/lib/cli.js
@@ -99,7 +99,6 @@ yargs
'optionally start existing schedule instead of running item once immediately (only works for automations)',
})
.option('fixShared', {
- type: 'boolean',
group: 'Options for deploy:',
describe:
"optionally ensure that updates to shared DataExtensions become visible in child BU's data designer (SF Known issue W-11031095)",
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index 1f9d82984..aac9cbfad 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -47,6 +47,38 @@ class AttributeSet extends MetadataType {
static retrieveForCache() {
return super.retrieveREST(null, '/hub/v1/contacts/schema/setDefinitions');
}
+ /**
+ * Retrieves Metadata of schema set definitions for caching.
+ *
+ * @param {object} sharedDataExtensions list of IDs of shared data extensions
+ * @returns {Promise.} Promise of list of shared dataExtension IDs
+ */
+ static async retrieveForSharedDEs(sharedDataExtensions) {
+ if (!Object.keys(sharedDataExtensions).length) {
+ return [];
+ }
+ const result = await super.retrieveREST(null, '/hub/v1/contacts/schema/setDefinitions');
+ const metadataMap = result?.metadata;
+ if (metadataMap && Object.keys(metadataMap).length) {
+ const sharedDEs = Object.keys(metadataMap)
+ .filter(
+ (key) =>
+ metadataMap[key].storageLogicalType === 'ExactTargetSchema' ||
+ metadataMap[key].storageLogicalType === 'DataExtension'
+ )
+ .filter((key) =>
+ Object.keys(sharedDataExtensions).includes(
+ metadataMap[key].storageReferenceID.value
+ )
+ )
+ .map((key) => metadataMap[key].storageReferenceID.value)
+ .filter(Boolean);
+ return sharedDEs;
+ } else {
+ // nothing to do - return empty array
+ return [];
+ }
+ }
/**
* Builds map of metadata entries mapped to their keyfields
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 3c8f5664e..fa51522d4 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -5,11 +5,13 @@ const TYPE = require('../../types/mcdev.d');
const MetadataType = require('./MetadataType');
const DataExtensionField = require('./DataExtensionField');
const Folder = require('./Folder');
+const AttributeSet = require('./AttributeSet');
const Util = require('../util/util');
const File = require('../util/file');
const auth = require('../util/auth');
const cache = require('../util/cache');
const pLimit = require('p-limit');
+const inquirer = require('inquirer');
/**
* DataExtension MetadataType
@@ -354,7 +356,7 @@ class DataExtension extends MetadataType {
DataExtensionField.postRetrieveTasks(field, true);
}
}
- await this.#postDeployFixShared(upsertedMetadata, originalMetadata);
+ await this.#postDeployFixShared(upsertedMetadata, originalMetadata, createdUpdated);
}
/**
@@ -369,34 +371,302 @@ class DataExtension extends MetadataType {
if (this.buObject.eid !== this.buObject.mid || createdUpdated.updated === 0) {
// only if we were executing a deploy on parent bu could we be deploying shared data extensions
// only if updates were made could the issue in https://issues.salesforce.com/#q=W-11031095 affect data designer
+ Util.logger.debug(`EID != MID or nothing updated`);
return;
}
+
// find all shared data extensions
- const sharedDataExtensions = [];
- for (const key in upsertedMetadata) {
- const item = upsertedMetadata[key];
- const originalItem = originalMetadata[key];
- if (
- item.r__folder_ContentType === 'shared_dataextension' ||
- originalItem.r__folder_ContentType === 'shared_dataextension'
- ) {
- sharedDataExtensions.push(item);
- }
- }
- if (sharedDataExtensions.length > 0 && !Util.OPTIONS.fixShared) {
+ const sharedDataExtensionsKeys = this.deployedSharedKeys;
+ this.deployedSharedKeys = null;
+
+ if (sharedDataExtensionsKeys.length > 0 && !Util.OPTIONS.fixShared) {
Util.logger.warn(
'Shared Data Extensions were updated but fixShared option is not set. This can result in your changes not being visible on child BUs.'
);
- // TODO replace with 2 inquirer questions to 1) ask if child BUs should be fixed if needed and 2) select which BUs to run this for
+ // TODO replace with 1 inquirer question to ask if child BUs should be fixed if needed
}
- if (sharedDataExtensions.length > 0 && Util.OPTIONS.fixShared) {
- // TODO initiate actual search & update logic
+ if (sharedDataExtensionsKeys.length > 0 && Util.OPTIONS.fixShared) {
+ // select which BUs to run this for
+ const selectedBuNames = await this.#fixSharedGetBUs();
+
+ // backup settings
+ const buObjectBak = this.buObject;
+ const clientBak = this.client;
+
+ // get dataExtension IDs
+ const sharedDataExtensions = {};
+ for (const key of sharedDataExtensionsKeys) {
+ try {
+ const id = cache.searchForField(
+ 'dataExtension',
+ key,
+ 'CustomerKey',
+ 'ObjectID',
+ this.buObject.eid
+ );
+ sharedDataExtensions[id] = key;
+ } catch {
+ continue;
+ }
+ }
+
+ // run the fix-data-model logic
+ Util.logger.info(
+ `Fixing Shared Data Extensions details in data models of child BUs` +
+ Util.getKeysString(sharedDataExtensionsKeys)
+ );
+ for (const buName of selectedBuNames) {
+ await this.#fixSharedOnBU(
+ buName,
+ buObjectBak,
+ clientBak,
+
+ sharedDataExtensions
+ );
+ }
+ Util.logger.info(`Finished fixing Shared Data Extensions details in data models`);
+
+ // restore settings
+ this.buObject = buObjectBak;
+ this.client = clientBak;
} else {
// no shared dataExtensions or fixShared option not enabled
return;
}
}
+ /**
+ * helper for {@link DataExtension.#postDeployFixShared}
+ *
+ * @param {string} childBuName name of child BU to fix
+ * @param {TYPE.BuObject} buObjectParent bu object for parent BU
+ * @param {object} clientParent SDK for parent BU
+ * @param {object} sharedDataExtensions list of IDs of shared data extensions
+ * @returns {Promise.} updated shared DE keys on BU
+ */
+ static async #fixSharedOnBU(childBuName, buObjectParent, clientParent, sharedDataExtensions) {
+ /** @type {TYPE.BuObject} */
+ const buObjectChildBu = {
+ eid: this.properties.credentials[buObjectParent.credential].eid,
+ mid: this.properties.credentials[buObjectParent.credential].businessUnits[childBuName],
+ businessUnit: childBuName,
+ credential: this.buObject.credential,
+ };
+ const clientChildBu = auth.getSDK(buObjectChildBu);
+
+ try {
+ // check if shared data Extension is used in an attributeSet on current BU
+ AttributeSet.properties = this.properties;
+ AttributeSet.buObject = buObjectChildBu;
+ AttributeSet.client = clientChildBu;
+ const sharedDeIdsUsedOnBU = await AttributeSet.retrieveForSharedDEs(
+ sharedDataExtensions
+ );
+ if (sharedDeIdsUsedOnBU.length) {
+ Util.logger.info(
+ ` - Fixing dataExtensions on BU ${childBuName} ` +
+ Util.getKeysString(
+ sharedDeIdsUsedOnBU.map((deId) => sharedDataExtensions[deId])
+ )
+ );
+
+ for (const deId of sharedDeIdsUsedOnBU) {
+ // dont use Promise.all to ensure order of execution; otherwise, switched BU contexts in one step will affect the next
+ await this.#fixShared_item(
+ deId,
+ sharedDataExtensions[deId],
+ buObjectChildBu,
+ clientChildBu,
+ buObjectParent,
+ clientParent
+ );
+ }
+ } else {
+ Util.logger.info(
+ Util.getGrayMsg(
+ ` - No matching attributeSet found for given Shared Data Extensions keys found on ${childBuName}`
+ )
+ );
+ }
+ return sharedDeIdsUsedOnBU;
+ } catch (ex) {
+ Util.logger.error(ex.message);
+ return;
+ }
+ }
+
+ /**
+ *
+ * @param {string} deId data extension ObjectID
+ * @param {string} deKey dataExtension key
+ * @param {TYPE.BuObject} buObjectChildBu BU object for Child BU
+ * @param {object} clientChildBu SDK for child BU
+ * @param {TYPE.BuObject} buObjectParent BU object for Parent BU
+ * @param {object} clientParent SDK for parent BU
+ * @returns {Promise} -
+ */
+ static async #fixShared_item(
+ deId,
+ deKey,
+ buObjectChildBu,
+ clientChildBu,
+ buObjectParent,
+ clientParent
+ ) {
+ // add field via child BU
+ const randomSuffix = await DataExtension.#fixShared_item_addField(
+ buObjectChildBu,
+ clientChildBu,
+ deKey,
+ deId
+ );
+
+ // get field ID from parent BU (it is not returned on child BU)
+ const fieldObjectID = await DataExtension.#fixShared_item_getFieldId(
+ randomSuffix,
+ buObjectParent,
+ clientParent,
+ deKey
+ );
+
+ // delete field via child BU
+ await DataExtension.#fixShared_item_deleteField(
+ randomSuffix,
+ buObjectChildBu,
+ clientChildBu,
+ deKey,
+ fieldObjectID
+ );
+
+ Util.logger.info(` - Fixed dataExtension ${deKey} on BU ${buObjectChildBu.businessUnit}`);
+ return true;
+ }
+
+ /**
+ *
+ * @param {string} randomSuffix -
+ * @param {TYPE.BuObject} buObjectChildBu BU object for Child BU
+ * @param {object} clientChildBu SDK for child BU
+ * @param {string} deKey dataExtension key
+ * @param {string} fieldObjectID field ObjectID
+ * @returns {Promise} -
+ */
+ static async #fixShared_item_deleteField(
+ randomSuffix,
+ buObjectChildBu,
+ clientChildBu,
+ deKey,
+ fieldObjectID
+ ) {
+ DataExtensionField.buObject = buObjectChildBu;
+ DataExtensionField.client = clientChildBu;
+ await DataExtensionField.deleteByKeySOAP(
+ deKey + '.TriggerUpdate' + randomSuffix,
+ fieldObjectID
+ );
+ }
+
+ /**
+ * helper for {@link DataExtension.#fixShared_item}
+ *
+ * @param {TYPE.BuObject} buObjectChildBu BU object for Child BU
+ * @param {object} clientChildBu SDK for child BU
+ * @param {string} deKey dataExtension key
+ * @param {string} deId dataExtension ObjectID
+ * @returns {Promise.} randomSuffix
+ */
+ static async #fixShared_item_addField(buObjectChildBu, clientChildBu, deKey, deId) {
+ this.buObject = buObjectChildBu;
+ this.client = clientChildBu;
+ const randomSuffix = Math.floor(Math.random() * 9999999999);
+ // add a new field to the shared DE to trigger an update to the data model
+ const soapType = this.definition.soapType || this.definition.type;
+ await this.client.soap.update(
+ Util.capitalizeFirstLetter(soapType),
+ {
+ CustomerKey: deKey,
+ ObjectID: deId,
+ Fields: {
+ Field: [
+ {
+ Name: 'TriggerUpdate' + randomSuffix,
+ IsRequired: false,
+ IsPrimaryKey: false,
+ FieldType: 'Boolean',
+ ObjectID: null,
+ },
+ ],
+ },
+ },
+ null
+ );
+ return randomSuffix;
+ }
+
+ /**
+ * helper for {@link DataExtension.#fixShared_item}
+ *
+ * @param {string} randomSuffix -
+ * @param {TYPE.BuObject} buObjectParent BU object for Parent BU
+ * @param {object} clientParent SDK for parent BU
+ * @param {string} deKey dataExtension key
+ * @returns {Promise.} fieldObjectID
+ */
+ static async #fixShared_item_getFieldId(randomSuffix, buObjectParent, clientParent, deKey) {
+ DataExtensionField.buObject = buObjectParent;
+ DataExtensionField.client = clientParent;
+ const fieldKey = `[${deKey}].[TriggerUpdate${randomSuffix}]`;
+ const fieldResponse = await DataExtensionField.retrieveForCache(
+ {
+ filter: {
+ leftOperand: 'CustomerKey',
+ operator: 'equals',
+ rightOperand: fieldKey,
+ },
+ },
+ ['Name', 'ObjectID']
+ );
+ const fieldObjectID = fieldResponse.metadata[fieldKey]?.ObjectID;
+ return fieldObjectID;
+ }
+
+ /**
+ * helper for {@link DataExtension.#postDeployFixShared}
+ *
+ * @returns {string[]} list of selected BU names
+ */
+ static async #fixSharedGetBUs() {
+ const buListObj = this.properties.credentials[this.buObject.credential].businessUnits;
+ const fixBuPreselected = [];
+ if (typeof Util.OPTIONS.fixShared === 'string') {
+ fixBuPreselected.push(
+ ...Util.OPTIONS.fixShared
+ .split(',')
+ .filter(Boolean)
+ .map((bu) => bu.trim())
+ );
+ }
+
+ const buList = Object.keys(buListObj)
+ .map((name) => ({ name, value: name, checked: fixBuPreselected.includes(name) }))
+ .filter((bu) => bu.value !== Util.parentBuName);
+ const questions = {
+ type: 'checkbox',
+ name: 'businessUnits',
+ message: 'Please select BUs that have access to the updated Shared Data Extensions:',
+ pageSize: 10,
+ choices: buList,
+ };
+ let responses = null;
+
+ try {
+ responses = await inquirer.prompt(questions);
+ } catch (ex) {
+ Util.logger.info(ex);
+ }
+ return responses.businessUnits;
+ }
+
/**
* Retrieves dataExtension metadata. Afterwards starts retrieval of dataExtensionColumn metadata retrieval
*
@@ -684,11 +954,16 @@ class DataExtension extends MetadataType {
throw new Error(`Cannot Upsert Strongly Typed Data Extensions`);
}
if (
+ !Util.OPTIONS._fixSharedOnBu &&
this.buObject.eid !== this.buObject.mid &&
metadata.r__folder_Path?.startsWith('Shared Items')
) {
throw new Error(`Cannot Create/Update a Shared Data Extension from the Child BU`);
}
+ if (metadata.r__folder_ContentType === 'shared_dataextension') {
+ this.deployedSharedKeys ||= [];
+ this.deployedSharedKeys.push(metadata.CustomerKey);
+ }
if (metadata.r__folder_Path?.startsWith('Synchronized Data Extensions')) {
throw new Error(
`Cannot Create/Update a Synchronized Data Extension. Please use Contact Builder to maintain these`
diff --git a/lib/metadataTypes/DataExtensionField.js b/lib/metadataTypes/DataExtensionField.js
index 7af1ab604..9fc4c2071 100644
--- a/lib/metadataTypes/DataExtensionField.js
+++ b/lib/metadataTypes/DataExtensionField.js
@@ -265,24 +265,28 @@ class DataExtensionField extends MetadataType {
* Delete a data extension from the specified business unit
*
* @param {string} customerKey Identifier of metadata
+ * @param {string} [fieldId] for programmatic deletes only one can pass in the ID directly
* @returns {boolean} deletion success flag
*/
- static async deleteByKeySOAP(customerKey) {
+ static async deleteByKeySOAP(customerKey, fieldId) {
const [deKey, fieldKey] = customerKey.split('.');
customerKey = `[${deKey}].[${fieldKey}]`;
+ let fieldObjectID = fieldId;
// get the object id
- const response = await this.retrieveForCache(
- {
- filter: {
- leftOperand: 'CustomerKey',
- operator: 'equals',
- rightOperand: customerKey,
+ if (!fieldObjectID) {
+ const response = await this.retrieveForCache(
+ {
+ filter: {
+ leftOperand: 'CustomerKey',
+ operator: 'equals',
+ rightOperand: customerKey,
+ },
},
- },
- ['Name', 'ObjectID']
- );
- const fieldObjectID = response.metadata[customerKey].ObjectID;
+ ['Name', 'ObjectID']
+ );
+ fieldObjectID = response.metadata[customerKey]?.ObjectID;
+ }
if (!fieldObjectID) {
Util.logger.error(`Could not find ${customerKey} on your BU`);
return false;
@@ -304,8 +308,10 @@ class DataExtensionField extends MetadataType {
null
);
- Util.logger.info(`- deleted ${this.definition.type}: ${customerKey}`);
- this.postDeleteTasks(customerKey);
+ if (!fieldId) {
+ Util.logger.info(` - deleted ${this.definition.type}: ${customerKey}`);
+ this.postDeleteTasks(customerKey);
+ }
return true;
} catch (ex) {
const errorMsg = ex.results?.length
From 11120cbd93084a4223f54e8a760834b1aee6c65f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 12:23:09 +0200
Subject: [PATCH 04/70] #940: remove redundant fields
---
lib/metadataTypes/AttributeSet.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index aac9cbfad..e3ca68caf 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -115,7 +115,7 @@ class AttributeSet extends MetadataType {
switch (metadata.storageLogicalType) {
case 'ExactTargetSchema': // synced / shared DEs
case 'DataExtension': {
- // local DEs
+ // shared / local DEs
try {
metadata.r__dataExtension_CustomerKey = cache.searchForField(
'dataExtension',
@@ -258,6 +258,12 @@ class AttributeSet extends MetadataType {
// Member ID
delete metadata.customObjectOwnerMID;
+ // remove duplicate ID fields (main field is definitionID)
+ delete metadata.setDefinitionID;
+ if (metadata.dataRetentionProperties?.setDefinitionID) {
+ delete metadata.dataRetentionProperties?.setDefinitionID;
+ }
+
// connectingID.identifierType seems to be always set to 'FullyQualifiedName' - to be sure we check it here and remove it if it's the case
if (metadata.connectingID?.identifierType === 'FullyQualifiedName') {
// remove useless field
From 32b0310765aa85737d5ea4e59d70f3b297fbca83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 12:39:14 +0200
Subject: [PATCH 05/70] #940: allow skipping question for more BUs + ensure
provided BUs are valid
---
lib/metadataTypes/DataExtension.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index fa51522d4..6f0edfec7 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -639,13 +639,18 @@ class DataExtension extends MetadataType {
const buListObj = this.properties.credentials[this.buObject.credential].businessUnits;
const fixBuPreselected = [];
if (typeof Util.OPTIONS.fixShared === 'string') {
+ const availableBuNames = Object.keys(buListObj);
fixBuPreselected.push(
...Util.OPTIONS.fixShared
.split(',')
.filter(Boolean)
.map((bu) => bu.trim())
+ .filter((bu) => availableBuNames.includes(bu))
);
}
+ if (Util.skipInteraction && fixBuPreselected.length) {
+ return fixBuPreselected;
+ }
const buList = Object.keys(buListObj)
.map((name) => ({ name, value: name, checked: fixBuPreselected.includes(name) }))
From a9ac14bb97186cdb4d0a3bc7cf6b64b6b4aef445 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 14:01:07 +0200
Subject: [PATCH 06/70] #940: fix attributeSet test
---
test/resources/9999999/attributeSet/retrieve-expected.json | 4 +---
test/type.dataExtension.test.js | 2 ++
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/test/resources/9999999/attributeSet/retrieve-expected.json b/test/resources/9999999/attributeSet/retrieve-expected.json
index cf01d6710..a81a4fe12 100644
--- a/test/resources/9999999/attributeSet/retrieve-expected.json
+++ b/test/resources/9999999/attributeSet/retrieve-expected.json
@@ -11,8 +11,7 @@
"dataRetentionProperties": {
"isDeleteAtEndOfRetentionPeriod": false,
"isResetRetentionPeriodOnImport": false,
- "isRowBasedRetention": false,
- "setDefinitionID": "3152de3f-31e2-e611-80cc-1402ec7222b4"
+ "isRowBasedRetention": false
},
"definitionKey": "MobileSubscriptions",
"isCustomObjectBacked": true,
@@ -29,7 +28,6 @@
"parentID": "00000000-0000-0000-0000-000000000000",
"r__folder_Path": "Data Extensions",
"relationshipCount": 0,
- "setDefinitionID": "3152de3f-31e2-e611-80cc-1402ec7222b4",
"setDefinitionKey": "MobileSubscriptions",
"storageLogicalType": "DataExtension",
"storageName": "_MobileSubscription",
diff --git a/test/type.dataExtension.test.js b/test/type.dataExtension.test.js
index e9a8a6d93..f16b073fd 100644
--- a/test/type.dataExtension.test.js
+++ b/test/type.dataExtension.test.js
@@ -87,6 +87,8 @@ describe('type: dataExtension', () => {
);
return;
});
+ it('Should create & update a shared dataExtension');
+ it('Should create & update a shared dataExtension with --fixShared');
it('Should rename fields');
});
describe('Templating ================', () => {
From 55b54ed38ddd6665741f12227ddfcf8b10cf208f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 15:04:42 +0200
Subject: [PATCH 07/70] #940: add test for delete dataExtension, delete
dataExtensionField, getFilesToCommit
---
docs/dist/documentation.md | 4 +-
lib/metadataTypes/DataExtension.js | 1 +
.../9999999/dataExtension/delete-response.xml | 42 +++++++++
...ing_dataExtension].[LastName]-response.xml | 44 ++++++++++
test/type.dataExtension.test.js | 88 +++++++++++--------
5 files changed, 141 insertions(+), 38 deletions(-)
create mode 100644 test/resources/9999999/dataExtension/delete-response.xml
create mode 100644 test/resources/9999999/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtension].[LastName]-response.xml
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index f15b793b0..a27dc2ce2 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -220,7 +220,8 @@ Provides default functionality that can be overwritten by child metadata type cl
helper for postDeployTasks
DataExtension.(upsertedMetadata, originalMetadata, createdUpdated) ⇒ void
-helper for postDeployTasks
+helper for postDeployTasks
+fixes an issue where shared data extensions are not visible in data designer on child BU; SF known issue: https://issues.salesforce.com/#q=W-11031095
DataExtension.(childBuName, buObjectParent, clientParent, sharedDataExtensions) ⇒ Promise.<Array.<string>>
helper for DataExtension.#postDeployFixShared
@@ -8589,6 +8590,7 @@ helper for [postDeployTasks](#Automation.postDeployTasks)
## DataExtension.(upsertedMetadata, originalMetadata, createdUpdated) ⇒ void
helper for [postDeployTasks](#DataExtension.postDeployTasks)
+fixes an issue where shared data extensions are not visible in data designer on child BU; SF known issue: https://issues.salesforce.com/#q=W-11031095
**Kind**: global function
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 6f0edfec7..8eb73b4af 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -361,6 +361,7 @@ class DataExtension extends MetadataType {
/**
* helper for {@link DataExtension.postDeployTasks}
+ * fixes an issue where shared data extensions are not visible in data designer on child BU; SF known issue: https://issues.salesforce.com/#q=W-11031095
*
* @param {TYPE.DataExtensionMap} upsertedMetadata metadata mapped by their keyField
* @param {TYPE.DataExtensionMap} originalMetadata metadata to be updated (contains additioanl fields)
diff --git a/test/resources/9999999/dataExtension/delete-response.xml b/test/resources/9999999/dataExtension/delete-response.xml
new file mode 100644
index 000000000..3c5d3b961
--- /dev/null
+++ b/test/resources/9999999/dataExtension/delete-response.xml
@@ -0,0 +1,42 @@
+
+
+
+ DeleteResponse
+ urn:uuid:cbcad7ed-d768-4dbd-b2b9-230cc05dca1b
+ urn:uuid:545315fb-1e5b-4b6b-a17a-da1fcac3524f
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2023-08-11T12:34:31Z
+ 2023-08-11T12:39:31Z
+
+
+
+
+
+
+ OK
+ Data Extension deleted. / Data Extension Fields deleted
+ 0
+
+
+ 21711373-72c1-ec11-b83b-48df37d1deb7
+ testExisting_dataExtension
+
+
+
+ 5c0faaa8-81db-4530-8b47-c56432f68543
+ OK
+
+
+
diff --git a/test/resources/9999999/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtension].[LastName]-response.xml b/test/resources/9999999/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtension].[LastName]-response.xml
new file mode 100644
index 000000000..d040f9e3b
--- /dev/null
+++ b/test/resources/9999999/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtension].[LastName]-response.xml
@@ -0,0 +1,44 @@
+
+
+
+ RetrieveResponse
+ urn:uuid:6d2f81c8-80ab-44d5-8664-206753e7ac8d
+ urn:uuid:a7354389-079e-4844-93b5-af6b7bf1d535
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-21T19:21:52Z
+ 2022-04-21T19:26:52Z
+
+
+
+
+
+ OK
+ cfe51e71-6a2b-4cb4-aecd-3777076d63bc
+
+
+ bea0e308-5d45-4181-a673-da9972a7c674
+ [testExisting_dataExtension].[LastName]
+ LastName
+ 0
+
+ 50
+ false
+ 1
+ false
+ Text
+
+
+
+ testExisting_dataExtension
+
+
+
+
+
diff --git a/test/type.dataExtension.test.js b/test/type.dataExtension.test.js
index f16b073fd..02031e6eb 100644
--- a/test/type.dataExtension.test.js
+++ b/test/type.dataExtension.test.js
@@ -197,46 +197,60 @@ describe('type: dataExtension', () => {
});
describe('Delete ================', () => {
// TODO: add this test
- it('Should delete the item'); // , async () => {
- // // WHEN
- // const result = await handler.deleteByKey('testInstance/testBU', 'mobileKeyword', [
- // 'testExisting_keyword',
- // ]);
- // // THEN
- // assert.equal(process.exitCode, false, 'delete should not have thrown an error');
+ it('Should delete the dataExtension', async () => {
+ // WHEN
+ const result = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'dataExtension',
+ 'testExisting_dataExtension'
+ );
+ // THEN
+ assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- // assert.equal(result, true, 'should have deleted the item');
- // return;
- // });
+ assert.equal(result, true, 'should have deleted the item');
+ return;
+ });
+ it('Should delete the dataExtensionField', async () => {
+ // WHEN
+ const result = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'dataExtensionField',
+ 'testExisting_dataExtension.LastName'
+ );
+ // THEN
+ assert.equal(process.exitCode, false, 'delete should not have thrown an error');
+
+ assert.equal(result, true, 'should have deleted the item');
+ return;
+ });
});
describe('CI/CD ================', () => {
- // TODO: add this test
- it('Should return a list of files based on their type and key'); // , async () => {
- // // WHEN
- // const fileList = await handler.getFilesToCommit(
- // 'testInstance/testBU',
- // 'mobileKeyword',
- // ['testExisting_keyword']
- // );
- // // THEN
- // assert.equal(
- // process.exitCode,
- // false,
- // 'getFilesToCommit should not have thrown an error'
- // );
- // assert.equal(fileList.length, 2, 'expected only 2 file paths');
+ it('Should return a list of files based on their type and key', async () => {
+ // WHEN
+ const fileList = await handler.getFilesToCommit(
+ 'testInstance/testBU',
+ 'dataExtension',
+ ['testExisting_dataExtension']
+ );
+ // THEN
+ assert.equal(
+ process.exitCode,
+ false,
+ 'getFilesToCommit should not have thrown an error'
+ );
+ assert.equal(fileList.length, 2, 'expected only 2 file paths (json, md)');
- // assert.equal(
- // fileList[0].split('\\').join('/'),
- // 'retrieve/testInstance/testBU/mobileKeyword/testExisting_keyword.mobileKeyword-meta.json',
- // 'wrong JSON path'
- // );
- // assert.equal(
- // fileList[1].split('\\').join('/'),
- // 'retrieve/testInstance/testBU/mobileKeyword/testExisting_keyword.mobileKeyword-meta.amp',
- // 'wrong AMP path'
- // );
- // return;
- // });
+ assert.equal(
+ fileList[0].split('\\').join('/'),
+ 'retrieve/testInstance/testBU/dataExtension/testExisting_dataExtension.dataExtension-meta.json',
+ 'wrong JSON path'
+ );
+ assert.equal(
+ fileList[1].split('\\').join('/'),
+ 'retrieve/testInstance/testBU/dataExtension/testExisting_dataExtension.dataExtension-doc.md',
+ 'wrong MD path'
+ );
+ return;
+ });
});
});
From 52463a3f061946eea287a179d4e074e393702397 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 15:33:40 +0200
Subject: [PATCH 08/70] #940: add test for retrieving shared data extensions
---
.../dataExtension/retrieve-expected.json | 55 +++
.../dataExtension/retrieve-expected.md | 18 +
.../dataExtension/retrieve-response.xml | 28 +-
.../dataExtensionField/retrieve-response.xml | 98 +++++
.../retrieve-response.xml | 303 ++++++++++++++
...extensionORContentType=hidden-response.xml | 387 ++++++++++++++++++
.../1111111/dataFolder/retrieve-response.xml | 107 +++--
test/type.dataExtension.test.js | 46 ++-
8 files changed, 1013 insertions(+), 29 deletions(-)
create mode 100644 test/resources/1111111/dataExtension/retrieve-expected.json
create mode 100644 test/resources/1111111/dataExtension/retrieve-expected.md
create mode 100644 test/resources/1111111/dataExtensionField/retrieve-response.xml
create mode 100644 test/resources/1111111/dataExtensionTemplate/retrieve-response.xml
create mode 100644 test/resources/1111111/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml
diff --git a/test/resources/1111111/dataExtension/retrieve-expected.json b/test/resources/1111111/dataExtension/retrieve-expected.json
new file mode 100644
index 000000000..f64ad16df
--- /dev/null
+++ b/test/resources/1111111/dataExtension/retrieve-expected.json
@@ -0,0 +1,55 @@
+{
+ "CustomerKey": "testExisting_dataExtensionShared",
+ "DataRetentionPeriodLength": 6,
+ "DataRetentionPeriodUnitOfMeasure": 5,
+ "DeleteAtEndOfRetentionPeriod": false,
+ "Description": "bla bla",
+ "Fields": [
+ {
+ "DefaultValue": "",
+ "FieldType": "Text",
+ "IsPrimaryKey": false,
+ "IsRequired": false,
+ "MaxLength": 50,
+ "Name": "FirstName"
+ },
+ {
+ "DefaultValue": "",
+ "FieldType": "Text",
+ "IsPrimaryKey": false,
+ "IsRequired": false,
+ "MaxLength": 50,
+ "Name": "LastName"
+ },
+ {
+ "DefaultValue": "",
+ "FieldType": "EmailAddress",
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "MaxLength": 254,
+ "Name": "EmailAddress"
+ },
+ {
+ "DefaultValue": "",
+ "FieldType": "Text",
+ "IsPrimaryKey": true,
+ "IsRequired": true,
+ "MaxLength": 50,
+ "Name": "ContactKey"
+ }
+ ],
+ "IsSendable": true,
+ "IsTestable": true,
+ "Name": "testExisting_dataExtensionShared",
+ "ResetRetentionPeriodOnImport": false,
+ "RetainUntil": "",
+ "RowBasedRetention": true,
+ "SendableDataExtensionField": {
+ "Name": "ContactKey"
+ },
+ "SendableSubscriberField": {
+ "Name": "Subscriber Key"
+ },
+ "r__folder_ContentType": "shared_dataextension",
+ "r__folder_Path": "Shared Items/Shared Data Extensions"
+}
diff --git a/test/resources/1111111/dataExtension/retrieve-expected.md b/test/resources/1111111/dataExtension/retrieve-expected.md
new file mode 100644
index 000000000..7e9a1d2fa
--- /dev/null
+++ b/test/resources/1111111/dataExtension/retrieve-expected.md
@@ -0,0 +1,18 @@
+## testExisting_dataExtensionShared
+
+**Description:** bla bla
+
+**Folder:** Shared Items/Shared Data Extensions/
+
+**Fields in table:** 4
+
+**Sendable:** Yes (`ContactKey` to `Subscriber Key`)
+
+**Testable:** Yes
+
+| Name | FieldType | MaxLength | IsPrimaryKey | IsNullable | DefaultValue |
+| --- | --- | --- | --- | --- | --- |
+| FirstName | Text | 50 | - | + | |
+| LastName | Text | 50 | - | + | |
+| EmailAddress | EmailAddress | 254 | - | - | |
+| ContactKey | Text | 50 | + | - | |
diff --git a/test/resources/1111111/dataExtension/retrieve-response.xml b/test/resources/1111111/dataExtension/retrieve-response.xml
index 68ea2dd11..cad82d0b3 100644
--- a/test/resources/1111111/dataExtension/retrieve-response.xml
+++ b/test/resources/1111111/dataExtension/retrieve-response.xml
@@ -21,6 +21,32 @@
OK
d175de6e-c8e4-4f5d-9c1d-ad64426ff4b7
+
+
+ 2022-04-21T06:56:27.927
+ 2022-04-21T06:56:27.927
+ 21711373-72c1-ec11-b83b-shared
+ testExisting_dataExtensionShared
+ testExisting_dataExtensionShared
+ bla bla
+ true
+ true
+
+
+
+ ContactKey
+
+
+ _SubscriberKey
+
+ 6
+ 5
+ true
+ false
+ false
+
+ 89356
+
-
\ No newline at end of file
+
diff --git a/test/resources/1111111/dataExtensionField/retrieve-response.xml b/test/resources/1111111/dataExtensionField/retrieve-response.xml
new file mode 100644
index 000000000..c3810d2ca
--- /dev/null
+++ b/test/resources/1111111/dataExtensionField/retrieve-response.xml
@@ -0,0 +1,98 @@
+
+
+
+ RetrieveResponse
+ urn:uuid:6d2f81c8-80ab-44d5-8664-206753e7ac8d
+ urn:uuid:a7354389-079e-4844-93b5-af6b7bf1d535
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-21T19:21:52Z
+ 2022-04-21T19:26:52Z
+
+
+
+
+
+ OK
+ cfe51e71-6a2b-4cb4-aecd-3777076d63bc
+
+
+ shared-8018397d-880d-4f88-940e-3b4eca098a0c
+ [testExisting_dataExtensionShared].[ContactKey]
+ ContactKey
+ 0
+
+ 50
+ true
+ 3
+ true
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-bea0e308-5d45-4181-a673-da9972a7c674
+ [testExisting_dataExtensionShared].[LastName]
+ LastName
+ 0
+
+ 50
+ false
+ 1
+ false
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-2557b461-a699-4744-950d-e80a19afc2dc
+ [testExisting_dataExtensionShared].[EmailAddress]
+ EmailAddress
+ 0
+
+ 254
+ true
+ 2
+ false
+ EmailAddress
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-42760528-a8c5-44dd-8c1d-ff34e5daee54
+ [testExisting_dataExtensionShared].[FirstName]
+ FirstName
+ 0
+
+ 50
+ false
+ 0
+ false
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+
diff --git a/test/resources/1111111/dataExtensionTemplate/retrieve-response.xml b/test/resources/1111111/dataExtensionTemplate/retrieve-response.xml
new file mode 100644
index 000000000..31b41f0b5
--- /dev/null
+++ b/test/resources/1111111/dataExtensionTemplate/retrieve-response.xml
@@ -0,0 +1,303 @@
+
+
+
+ RetrieveResponse
+ urn:uuid:110bbc72-d639-4e67-ab93-68e081bcf3a0
+ urn:uuid:753eed05-f925-4113-8a98-e81ca69c96fd
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-21T19:21:49Z
+ 2022-04-21T19:26:49Z
+
+
+
+
+
+ OK
+ 82fd5f74-ad8c-49ad-958f-867d4a4b53b0
+
+
+
+ IsSendable
+ False
+
+
+ IsTestable
+ False
+
+
+ SendableCustomObjectField
+
+
+
+ SendableSubscriberField
+
+
+
+ DataRetentionPeriodLength
+
+
+
+ DataRetentionPeriodUnitOfMeasure
+
+
+
+ RowBasedRetention
+ False
+
+
+ ResetRetentionPeriodOnImport
+ False
+
+
+ DeleteAtEndOfRetentionPeriod
+ False
+
+
+ RetainUntil
+
+
+ cfd6fc95-d594-ea11-a2e6-1402ec938a35
+ 086D14D3-5057-462B-AF33-01CA8D1FE87A
+ DomainExclusion
+ Domain Exclusion Data Extension Template
+
+
+
+
+ IsSendable
+ True
+
+
+ IsTestable
+ False
+
+
+ SendableCustomObjectField
+ SubscriberKey
+
+
+ SendableSubscriberField
+ _SubscriberKey
+
+
+ DataRetentionPeriodLength
+
+
+
+ DataRetentionPeriodUnitOfMeasure
+
+
+
+ RowBasedRetention
+ False
+
+
+ ResetRetentionPeriodOnImport
+ False
+
+
+ DeleteAtEndOfRetentionPeriod
+ False
+
+
+ RetainUntil
+
+
+ 1fd7fc95-d594-ea11-a2e6-1402ec938a35
+ B6E8AE4C-3D93-49B1-B299-E0AE734213DD
+ TriggeredSendDataExtension
+ Triggered Send Source Data Extension Template
+
+
+
+
+ IsSendable
+ True
+
+
+ IsTestable
+ False
+
+
+ SendableCustomObjectField
+ Email Address
+
+
+ SendableSubscriberField
+ _EmailAddress
+
+
+ DataRetentionPeriodLength
+
+
+
+ DataRetentionPeriodUnitOfMeasure
+
+
+
+ RowBasedRetention
+ False
+
+
+ ResetRetentionPeriodOnImport
+ False
+
+
+ DeleteAtEndOfRetentionPeriod
+ False
+
+
+ RetainUntil
+
+
+ bb1df59b-d594-ea11-a2e6-1402ec938a35
+ 23471ECA-8710-4512-9296-040CA86FBD9E
+ CONTEXTUAL_SUPPRESSION_LISTS
+ Used to create new auto-suppression lists
+
+
+
+
+ IsSendable
+ True
+
+
+ IsTestable
+ False
+
+
+ SendableCustomObjectField
+ EmailAddress
+
+
+ SendableSubscriberField
+ _SubscriberKey
+
+
+ DataRetentionPeriodLength
+
+
+
+ DataRetentionPeriodUnitOfMeasure
+
+
+
+ RowBasedRetention
+ False
+
+
+ ResetRetentionPeriodOnImport
+ False
+
+
+ DeleteAtEndOfRetentionPeriod
+ False
+
+
+ RetainUntil
+
+
+ e61df59b-d594-ea11-a2e6-1402ec938a35
+ 00A4369E-0B57-4EF2-BFFA-E3F23B4D1098
+ SocialPages Default Template Extension
+ Required for contacts. Used by Smart Capture for Social Pages.
+
+
+
+
+ IsSendable
+ True
+
+
+ IsTestable
+ False
+
+
+ SendableCustomObjectField
+ SubscriberKey
+
+
+ SendableSubscriberField
+ _SubscriberKey
+
+
+ DataRetentionPeriodLength
+ 6
+
+
+ DataRetentionPeriodUnitOfMeasure
+ 5
+
+
+ RowBasedRetention
+ False
+
+
+ ResetRetentionPeriodOnImport
+ False
+
+
+ DeleteAtEndOfRetentionPeriod
+ False
+
+
+ RetainUntil
+
+
+ 37d8c7f2-ad19-4084-8d18-4dda1dc36772
+ DAE95D91-762C-4124-B082-0433165ADD30
+ AudienceBuilderResult
+ Used for creating audience builder result destinations.
+
+
+
+
+ IsSendable
+ True
+
+
+ IsTestable
+ False
+
+
+ SendableCustomObjectField
+ ContactKey
+
+
+ SendableSubscriberField
+ _SubscriberKey
+
+
+ DataRetentionPeriodLength
+
+
+
+ DataRetentionPeriodUnitOfMeasure
+ 0
+
+
+ RowBasedRetention
+ False
+
+
+ ResetRetentionPeriodOnImport
+ False
+
+
+ DeleteAtEndOfRetentionPeriod
+ False
+
+
+ RetainUntil
+
+
+ 941cf36b-f927-4674-8468-c9a3bed7cae4
+ BE1B7591-BFA6-473F-A6CE-0E458204865B
+ Event DE Template
+ Event Data Extension Template
+
+
+
+
\ No newline at end of file
diff --git a/test/resources/1111111/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml b/test/resources/1111111/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml
new file mode 100644
index 000000000..41bb03f59
--- /dev/null
+++ b/test/resources/1111111/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml
@@ -0,0 +1,387 @@
+
+
+
+ RetrieveResponse
+ urn:uuid:4d209b2f-d7ce-4e6e-916c-c8642d368866
+ urn:uuid:a850f043-1422-4d16-8443-702dd2f9f13a
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2023-08-11T13:15:46Z
+ 2023-08-11T13:20:46Z
+
+
+
+
+
+ OK
+ ba1b0c59-78c4-4608-8423-35dda2248d4d
+
+
+ 1111111
+
+
+ 2016-07-22T11:52:18.73
+ 2016-07-22T11:52:19.603
+ 89344
+
+ shared_data_default
+
+
+ 0
+
+
+ Shared Items
+
+ shared_data
+ true
+ false
+ false
+
+
+
+ 1111111
+
+
+ 2016-07-22T11:52:19.6
+ 2016-07-22T11:52:19.6
+ 89355
+
+ dataextension_default
+
+
+ 0
+
+
+ Data Extensions
+
+ dataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-07-22T11:52:19.603
+ 2016-07-22T11:52:19.603
+ 89356
+
+ shared_dataextension_default
+
+
+ 89344
+
+ shared_data_default
+
+ Shared Data Extensions
+
+ shared_dataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-07-29T12:13:27.28
+ 2016-07-29T12:13:27.28
+ 90889
+
+ HiddenCategory_default
+
+
+ 0
+
+
+ HiddenCategory
+ Hidden folder to store Hidden items
+ Hidden
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-08-23T09:22:27.54
+ 2016-08-23T09:22:27.54
+ 93698
+
+ salesforcedataextension_default
+
+
+ 0
+
+
+ Salesforce Data Extensions
+
+ salesforcedataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-08-23T09:22:27.55
+ 2016-08-23T09:22:27.55
+ 93699
+
+ shared_salesforcedataextension_defau
+
+
+ 89344
+
+ shared_data_default
+
+ Shared Salesforce Data Extensions
+
+ shared_salesforcedataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2020-01-27T10:50:46.573
+ 2020-01-27T10:50:46.573
+ 309082
+
+
+
+
+ 89355
+
+ dataextension_default
+
+ QueryStudioResults
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2020-04-17T08:14:19.763
+ 2020-04-17T08:14:19.763
+ 587750
+
+
+
+
+ 89356
+
+ shared_dataextension_default
+
+ catalyst target 1
+
+ shared_dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2020-07-09T02:30:12.38
+ 2021-12-16T03:43:30.753
+ 605618
+
+ dataextension_default
+
+
+ 89355
+
+ dataextension_default
+
+ Audiences
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2020-12-25T06:11:40.107
+ 2021-12-23T10:51:24.393
+ 633441
+
+
+
+
+ 89355
+
+ dataextension_default
+
+ System DEs
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2021-01-30T11:54:36.11
+ 2021-01-30T11:54:36.11
+ 638814
+
+ 0b72bf27-0678-484d-ac0b-a8762b9bec33
+
+
+ 89356
+
+ shared_dataextension_default
+
+ Customer 360 Segments
+ All Customer 360 segments will be grouped here. Each sub-folder relates to an activation profile name.
+ shared_dataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2021-01-30T11:56:38.77
+ 2021-01-30T11:56:38.77
+ 638815
+
+ cedd206d-178e-41cb-8965-ce255975b046
+
+
+ 638814
+
+ 0b72bf27-0678-484d-ac0b-a8762b9bec33
+
+ FirstAudience360 Segment
+
+ shared_dataextension
+ true
+ false
+ false
+
+
+
+ 1111111
+
+
+ 2021-02-07T10:44:01.413
+ 2021-12-16T03:43:33.38
+ 639967
+
+
+
+
+ 89355
+
+ dataextension_default
+
+ TestAudiences
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2021-08-04T15:17:18.533
+ 2021-08-04T15:17:18.567
+ 675203
+
+ A19F7E38-7369-497E-826F-D551F17FB0B4
+
+
+ 0
+
+
+ Synchronized Data Extensions
+
+ synchronizeddataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2021-10-03T05:01:37.23
+ 2021-10-03T05:01:37.37
+ 688352
+
+ B80AE306-55BC-4C2E-A79F-8CCA486F0BA0
+
+
+ 0
+
+
+ Synchronized Data Extensions
+
+ synchronizeddataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2022-10-26T09:48:38.293
+ 2022-10-26T09:48:38.31
+ 757145
+
+ 0ACB800B-AA8B-4F0F-9642-4907592C919C
+
+
+ 0
+
+
+ Synchronized Data Extensions
+
+ synchronizeddataextension
+ true
+ false
+ true
+
+
+
+
diff --git a/test/resources/1111111/dataFolder/retrieve-response.xml b/test/resources/1111111/dataFolder/retrieve-response.xml
index 30b16237c..73e3ec0c1 100644
--- a/test/resources/1111111/dataFolder/retrieve-response.xml
+++ b/test/resources/1111111/dataFolder/retrieve-response.xml
@@ -1,43 +1,98 @@
-
+
RetrieveResponse
- urn:uuid:f36f3303-3b5a-4641-8109-b26447634d91
- urn:uuid:33983968-28c4-4379-bb5f-f80ae32eb988
+ urn:uuid:6d2f81c8-80ab-44d5-8664-206753e7ac8d
+ urn:uuid:a7354389-079e-4844-93b5-af6b7bf1d535
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
-
- 2022-04-19T20:03:41Z
- 2022-04-19T20:08:41Z
+
+ 2022-04-21T19:21:52Z
+ 2022-04-21T19:26:52Z
OK
- 02cd5ccb-8f84-4651-826f-71169eeecf05
-
-
- 1111111
-
+ cfe51e71-6a2b-4cb4-aecd-3777076d63bc
+
- 2016-07-22T11:52:19.6
- 2016-07-22T11:52:19.6
- 1
-
- dataextension_default
-
+ 8018397d-880d-4f88-940e-3b4eca098a0c
+ [testExisting_dataExtension].[ContactKey]
+ ContactKey
+ 0
+
+ 50
+ true
+ 3
+ true
+ Text
+
- 0
-
- Data Extensions
-
- dataextension
- true
- false
- true
+ testExisting_dataExtension
+
+
+
+
+ bea0e308-5d45-4181-a673-da9972a7c674
+ [testExisting_dataExtension].[LastName]
+ LastName
+ 0
+
+ 50
+ false
+ 1
+ false
+ Text
+
+
+
+ testExisting_dataExtension
+
+
+
+
+ 2557b461-a699-4744-950d-e80a19afc2dc
+ [testExisting_dataExtension].[EmailAddress]
+ EmailAddress
+ 0
+
+ 254
+ true
+ 2
+ false
+ EmailAddress
+
+
+
+ testExisting_dataExtension
+
+
+
+
+ 42760528-a8c5-44dd-8c1d-ff34e5daee54
+ [testExisting_dataExtension].[FirstName]
+ FirstName
+ 0
+
+ 50
+ false
+ 0
+ false
+ Text
+
+
+
+ testExisting_dataExtension
+
-
\ No newline at end of file
+
diff --git a/test/type.dataExtension.test.js b/test/type.dataExtension.test.js
index 02031e6eb..096c6f54d 100644
--- a/test/type.dataExtension.test.js
+++ b/test/type.dataExtension.test.js
@@ -50,6 +50,48 @@ describe('type: dataExtension', () => {
);
return;
});
+ it('Should retrieve a shared dataExtension', async () => {
+ // WHEN
+ await handler.retrieve('testInstance/_ParentBU_', ['dataExtension']);
+ // THEN
+ assert.equal(process.exitCode, false, 'retrieve should not have thrown an error');
+ // get results from cache
+ const result = cache.getCache();
+ assert.equal(
+ result.dataExtension ? Object.keys(result.dataExtension).length : 0,
+ 1,
+ 'only one dataExtension expected'
+ );
+ assert.deepEqual(
+ await testUtils.getActualJson(
+ 'testExisting_dataExtensionShared',
+ 'dataExtension',
+ '_ParentBU_'
+ ),
+ await testUtils.getExpectedJson('1111111', 'dataExtension', 'retrieve'),
+
+ 'returned metadata was not equal expected'
+ );
+ // check if MD file was created and equals expectations
+ expect(
+ file(
+ testUtils.getActualDoc(
+ 'testExisting_dataExtensionShared',
+ 'dataExtension',
+ '_ParentBU_'
+ )
+ )
+ ).to.equal(
+ file(testUtils.getExpectedFile('1111111', 'dataExtension', 'retrieve', 'md'))
+ );
+
+ assert.equal(
+ testUtils.getAPIHistoryLength(),
+ 4,
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+ );
+ return;
+ });
});
describe('Deploy ================', () => {
beforeEach(() => {
@@ -65,8 +107,8 @@ describe('type: dataExtension', () => {
const result = cache.getCache();
assert.equal(
result.dataExtension ? Object.keys(result.dataExtension).length : 0,
- 2,
- 'two dataExtensions expected'
+ 3,
+ 'three dataExtensions expected'
);
// insert
assert.deepEqual(
From 3749ac15c46915df9c90512a56ad74de9a90529d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 16:40:22 +0200
Subject: [PATCH 09/70] #940: add deploy test for shared dataExtensions with
--fixShared
---
lib/index.js | 1 +
lib/metadataTypes/DataExtension.js | 4 +-
...ataExtensionShared.dataExtension-meta.json | 59 +++
...ataExtensionShared.dataExtension-meta.json | 23 +
.../rowset/get-response.json | 13 +
.../dataExtension/create-expected.json | 23 +
.../1111111/dataExtension/create-response.xml | 59 +++
.../dataExtension/update-expected.json | 55 +++
.../1111111/dataExtension/update-response.xml | 57 +++
...[TriggerUpdate_randomNumber_]-response.xml | 45 ++
...tExisting_dataExtensionShared-response.xml | 98 ++++
...tExisting_dataExtensionShared-response.xml | 98 ++++
.../1111111/dataFolder/retrieve-response.xml | 443 ++++++++++++++---
.../schema/attributeGroups/get-response.json | 43 ++
.../schema/setDefinitions/get-response.json | 447 ++++++++++++++++++
test/type.attributeGroup.test.js | 8 +-
test/type.attributeSet.test.js | 8 +-
test/type.dataExtension.test.js | 110 ++++-
18 files changed, 1505 insertions(+), 89 deletions(-)
create mode 100644 test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json
create mode 100644 test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testNew_dataExtensionShared.dataExtension-meta.json
create mode 100644 test/resources/1111111/data/v1/customobjectdata/key/testExisting_dataExtensionShared/rowset/get-response.json
create mode 100644 test/resources/1111111/dataExtension/create-expected.json
create mode 100644 test/resources/1111111/dataExtension/create-response.xml
create mode 100644 test/resources/1111111/dataExtension/update-expected.json
create mode 100644 test/resources/1111111/dataExtension/update-response.xml
create mode 100644 test/resources/1111111/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtensionShared].[TriggerUpdate_randomNumber_]-response.xml
create mode 100644 test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml
create mode 100644 test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testNew_dataExtensionSharedORDataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml
diff --git a/lib/index.js b/lib/index.js
index bcc150061..535fa4f08 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -63,6 +63,7 @@ class Mcdev {
'noLogColors',
'noLogFile',
'refresh',
+ '_runningTest',
'schedule',
'skipInteraction',
];
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 8eb73b4af..80b7174c0 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -579,7 +579,9 @@ class DataExtension extends MetadataType {
static async #fixShared_item_addField(buObjectChildBu, clientChildBu, deKey, deId) {
this.buObject = buObjectChildBu;
this.client = clientChildBu;
- const randomSuffix = Math.floor(Math.random() * 9999999999);
+ const randomSuffix = Util.OPTIONS._runningTest
+ ? '_randomNumber_'
+ : Math.floor(Math.random() * 9999999999);
// add a new field to the shared DE to trigger an update to the data model
const soapType = this.definition.soapType || this.definition.type;
await this.client.soap.update(
diff --git a/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json b/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json
new file mode 100644
index 000000000..23a55d5a1
--- /dev/null
+++ b/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json
@@ -0,0 +1,59 @@
+{
+ "CustomerKey": "testExisting_dataExtensionShared",
+ "Name": "testExisting_dataExtensionShared",
+ "Description": "Container for my test emails",
+ "IsSendable": true,
+ "IsTestable": true,
+ "SendableDataExtensionField": { "Name": "ContactKey" },
+ "SendableSubscriberField": { "Name": "Subscriber Key" },
+ "DataRetentionPeriodLength": 6,
+ "DataRetentionPeriodUnitOfMeasure": 5,
+ "RowBasedRetention": true,
+ "ResetRetentionPeriodOnImport": false,
+ "DeleteAtEndOfRetentionPeriod": false,
+ "RetainUntil": "",
+ "Fields": [
+ {
+ "Name": "FirstName",
+ "DefaultValue": "",
+ "MaxLength": 50,
+ "IsRequired": false,
+ "IsPrimaryKey": false,
+ "FieldType": "Text"
+ },
+ {
+ "Name": "LastName",
+ "DefaultValue": "",
+ "MaxLength": 55,
+ "IsRequired": false,
+ "IsPrimaryKey": false,
+ "FieldType": "Text"
+ },
+ {
+ "Name": "EmailAddress",
+ "DefaultValue": "",
+ "MaxLength": 254,
+ "IsRequired": true,
+ "IsPrimaryKey": false,
+ "FieldType": "EmailAddress"
+ },
+ {
+ "Name": "testField",
+ "DefaultValue": "",
+ "MaxLength": 254,
+ "IsRequired": false,
+ "IsPrimaryKey": false,
+ "FieldType": "Text"
+ },
+ {
+ "Name": "ContactKey",
+ "DefaultValue": "",
+ "MaxLength": 50,
+ "IsRequired": true,
+ "IsPrimaryKey": true,
+ "FieldType": "Text"
+ }
+ ],
+ "r__folder_ContentType": "shared_dataextension",
+ "r__folder_Path": "Shared Items/Shared Data Extensions"
+}
diff --git a/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testNew_dataExtensionShared.dataExtension-meta.json b/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testNew_dataExtensionShared.dataExtension-meta.json
new file mode 100644
index 000000000..daf504e7c
--- /dev/null
+++ b/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testNew_dataExtensionShared.dataExtension-meta.json
@@ -0,0 +1,23 @@
+{
+ "CustomerKey": "testNew_dataExtensionShared",
+ "Name": "testNew_dataExtensionShared",
+ "Description": "",
+ "IsSendable": false,
+ "IsTestable": false,
+ "RowBasedRetention": false,
+ "ResetRetentionPeriodOnImport": false,
+ "DeleteAtEndOfRetentionPeriod": false,
+ "RetainUntil": "",
+ "Fields": [
+ {
+ "Name": "testField",
+ "DefaultValue": "",
+ "MaxLength": 254,
+ "IsRequired": true,
+ "IsPrimaryKey": false,
+ "FieldType": "Text"
+ }
+ ],
+ "r__folder_ContentType": "shared_dataextension",
+ "r__folder_Path": "Shared Items/Shared Data Extensions"
+}
diff --git a/test/resources/1111111/data/v1/customobjectdata/key/testExisting_dataExtensionShared/rowset/get-response.json b/test/resources/1111111/data/v1/customobjectdata/key/testExisting_dataExtensionShared/rowset/get-response.json
new file mode 100644
index 000000000..1156309d9
--- /dev/null
+++ b/test/resources/1111111/data/v1/customobjectdata/key/testExisting_dataExtensionShared/rowset/get-response.json
@@ -0,0 +1,13 @@
+{
+ "links": {
+ "self": "/v1/customobjectdata/token/ea0a44dc-b679-4d7d-8b77-e5d3f106e854/rowset?$page=1"
+ },
+ "requestToken": "ea0a44dc-b679-4d7d-8b77-e5d3f106e854",
+ "tokenExpireDateUtc": "2023-01-26T13:54:59.883",
+ "customObjectId": "30400c03-0ec4-ec11-b83c-48df37d1de8b",
+ "customObjectKey": "testExisting_dataExtensionShared",
+ "pageSize": 1,
+ "page": 1,
+ "count": 0,
+ "top": 0
+}
diff --git a/test/resources/1111111/dataExtension/create-expected.json b/test/resources/1111111/dataExtension/create-expected.json
new file mode 100644
index 000000000..222e46023
--- /dev/null
+++ b/test/resources/1111111/dataExtension/create-expected.json
@@ -0,0 +1,23 @@
+{
+ "CustomerKey": "testNew_dataExtensionShared",
+ "DeleteAtEndOfRetentionPeriod": false,
+ "Description": "",
+ "Fields": [
+ {
+ "DefaultValue": "",
+ "FieldType": "Text",
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "MaxLength": 254,
+ "Name": "testField"
+ }
+ ],
+ "IsSendable": false,
+ "IsTestable": false,
+ "Name": "testNew_dataExtensionShared",
+ "ResetRetentionPeriodOnImport": false,
+ "RetainUntil": "",
+ "RowBasedRetention": false,
+ "r__folder_ContentType": "shared_dataextension",
+ "r__folder_Path": "Shared Items/Shared Data Extensions"
+}
diff --git a/test/resources/1111111/dataExtension/create-response.xml b/test/resources/1111111/dataExtension/create-response.xml
new file mode 100644
index 000000000..207f5ca3c
--- /dev/null
+++ b/test/resources/1111111/dataExtension/create-response.xml
@@ -0,0 +1,59 @@
+
+
+
+ CreateResponse
+ urn:uuid:3a5f1edf-dacb-4d19-a0d3-4e0dcc9f507d
+ urn:uuid:fb395987-bf45-42d6-af73-f51816c7b73f
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-24T20:35:10Z
+ 2022-04-24T20:40:10Z
+
+
+
+
+
+
+ OK
+ Data Extension created.
+ 0
+ 0
+ shared-0ec4-ec11-b83c-48df37d1de8a
+
+
+ shared-0ec4-ec11-b83c-48df37d1de8a
+ testNew_dataExtensionShared
+ testNew_dataExtensionShared
+
+ false
+ false
+ false
+ false
+ false
+
+
+
+
+
+ testField
+
+ 254
+ true
+ false
+ Text
+
+
+ 89356
+
+
+ c41aa55a-90e3-4021-9f82-103796aae6da
+ OK
+
+
+
diff --git a/test/resources/1111111/dataExtension/update-expected.json b/test/resources/1111111/dataExtension/update-expected.json
new file mode 100644
index 000000000..e889c1f87
--- /dev/null
+++ b/test/resources/1111111/dataExtension/update-expected.json
@@ -0,0 +1,55 @@
+{
+ "CustomerKey": "testExisting_dataExtensionShared",
+ "DeleteAtEndOfRetentionPeriod": false,
+ "Description": "Container for my test emails",
+ "Fields": [
+ {
+ "DefaultValue": "",
+ "FieldType": "Text",
+ "IsPrimaryKey": false,
+ "IsRequired": false,
+ "MaxLength": 50,
+ "Name": "FirstName"
+ },
+ {
+ "DefaultValue": "",
+ "FieldType": "Text",
+ "IsPrimaryKey": false,
+ "IsRequired": false,
+ "MaxLength": 55,
+ "Name": "LastName"
+ },
+ {
+ "DefaultValue": "",
+ "FieldType": "EmailAddress",
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "MaxLength": 254,
+ "Name": "EmailAddress"
+ },
+ {
+ "DefaultValue": "",
+ "FieldType": "Text",
+ "IsPrimaryKey": true,
+ "IsRequired": true,
+ "MaxLength": 50,
+ "Name": "ContactKey"
+ },
+ {
+ "DefaultValue": "",
+ "FieldType": "Text",
+ "IsPrimaryKey": false,
+ "IsRequired": false,
+ "MaxLength": 254,
+ "Name": "testField"
+ }
+ ],
+ "IsSendable": false,
+ "IsTestable": false,
+ "Name": "testExisting_dataExtensionShared",
+ "ResetRetentionPeriodOnImport": false,
+ "RetainUntil": "",
+ "RowBasedRetention": true,
+ "r__folder_ContentType": "shared_dataextension",
+ "r__folder_Path": "Shared Items/Shared Data Extensions"
+}
diff --git a/test/resources/1111111/dataExtension/update-response.xml b/test/resources/1111111/dataExtension/update-response.xml
new file mode 100644
index 000000000..f2122b7e1
--- /dev/null
+++ b/test/resources/1111111/dataExtension/update-response.xml
@@ -0,0 +1,57 @@
+
+
+
+ UpdateResponse
+ urn:uuid:994e213d-1125-450d-b187-32e3870147d1
+ urn:uuid:f1fc86ef-c0c8-4c17-a901-a15fc2631f76
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-26T20:49:03Z
+ 2022-04-26T20:54:03Z
+
+
+
+
+
+
+ OK
+ Data Extension updated.
+ 0
+
+
+ 21711373-72c1-ec11-b83b-shared
+ testExisting_dataExtensionShared
+ testExisting_dataExtensionShared
+ Container for my test emails
+ false
+ false
+ false
+ false
+ false
+
+
+
+
+
+ testField
+
+ 254
+ true
+ false
+ Text
+
+
+ 89356
+
+
+ dbfedcb6-a809-4101-b314-a7b920c9fb1e
+ OK
+
+
+
diff --git a/test/resources/1111111/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtensionShared].[TriggerUpdate_randomNumber_]-response.xml b/test/resources/1111111/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtensionShared].[TriggerUpdate_randomNumber_]-response.xml
new file mode 100644
index 000000000..ddb2cff52
--- /dev/null
+++ b/test/resources/1111111/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtensionShared].[TriggerUpdate_randomNumber_]-response.xml
@@ -0,0 +1,45 @@
+
+
+
+ RetrieveResponse
+ urn:uuid:6d2f81c8-80ab-44d5-8664-206753e7ac8d
+ urn:uuid:a7354389-079e-4844-93b5-af6b7bf1d535
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-21T19:21:52Z
+ 2022-04-21T19:26:52Z
+
+
+
+
+
+ OK
+ cfe51e71-6a2b-4cb4-aecd-3777076d63bc
+
+
+ TriggerUpdate-8018397d-880d-4f88-940e-3b4eca098a0c
+ [testExisting_dataExtensionShared].[TriggerUpdate_randomNumber_]
+ TriggerUpdate_randomNumber_
+ 0
+
+ 50
+ true
+ 3
+ true
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+
+
diff --git a/test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml b/test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml
new file mode 100644
index 000000000..c3810d2ca
--- /dev/null
+++ b/test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml
@@ -0,0 +1,98 @@
+
+
+
+ RetrieveResponse
+ urn:uuid:6d2f81c8-80ab-44d5-8664-206753e7ac8d
+ urn:uuid:a7354389-079e-4844-93b5-af6b7bf1d535
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-21T19:21:52Z
+ 2022-04-21T19:26:52Z
+
+
+
+
+
+ OK
+ cfe51e71-6a2b-4cb4-aecd-3777076d63bc
+
+
+ shared-8018397d-880d-4f88-940e-3b4eca098a0c
+ [testExisting_dataExtensionShared].[ContactKey]
+ ContactKey
+ 0
+
+ 50
+ true
+ 3
+ true
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-bea0e308-5d45-4181-a673-da9972a7c674
+ [testExisting_dataExtensionShared].[LastName]
+ LastName
+ 0
+
+ 50
+ false
+ 1
+ false
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-2557b461-a699-4744-950d-e80a19afc2dc
+ [testExisting_dataExtensionShared].[EmailAddress]
+ EmailAddress
+ 0
+
+ 254
+ true
+ 2
+ false
+ EmailAddress
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-42760528-a8c5-44dd-8c1d-ff34e5daee54
+ [testExisting_dataExtensionShared].[FirstName]
+ FirstName
+ 0
+
+ 50
+ false
+ 0
+ false
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+
diff --git a/test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testNew_dataExtensionSharedORDataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml b/test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testNew_dataExtensionSharedORDataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml
new file mode 100644
index 000000000..c3810d2ca
--- /dev/null
+++ b/test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testNew_dataExtensionSharedORDataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml
@@ -0,0 +1,98 @@
+
+
+
+ RetrieveResponse
+ urn:uuid:6d2f81c8-80ab-44d5-8664-206753e7ac8d
+ urn:uuid:a7354389-079e-4844-93b5-af6b7bf1d535
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-21T19:21:52Z
+ 2022-04-21T19:26:52Z
+
+
+
+
+
+ OK
+ cfe51e71-6a2b-4cb4-aecd-3777076d63bc
+
+
+ shared-8018397d-880d-4f88-940e-3b4eca098a0c
+ [testExisting_dataExtensionShared].[ContactKey]
+ ContactKey
+ 0
+
+ 50
+ true
+ 3
+ true
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-bea0e308-5d45-4181-a673-da9972a7c674
+ [testExisting_dataExtensionShared].[LastName]
+ LastName
+ 0
+
+ 50
+ false
+ 1
+ false
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-2557b461-a699-4744-950d-e80a19afc2dc
+ [testExisting_dataExtensionShared].[EmailAddress]
+ EmailAddress
+ 0
+
+ 254
+ true
+ 2
+ false
+ EmailAddress
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+ shared-42760528-a8c5-44dd-8c1d-ff34e5daee54
+ [testExisting_dataExtensionShared].[FirstName]
+ FirstName
+ 0
+
+ 50
+ false
+ 0
+ false
+ Text
+
+
+
+ testExisting_dataExtensionShared
+
+
+
+
+
diff --git a/test/resources/1111111/dataFolder/retrieve-response.xml b/test/resources/1111111/dataFolder/retrieve-response.xml
index 73e3ec0c1..41bb03f59 100644
--- a/test/resources/1111111/dataFolder/retrieve-response.xml
+++ b/test/resources/1111111/dataFolder/retrieve-response.xml
@@ -7,91 +7,380 @@
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
RetrieveResponse
- urn:uuid:6d2f81c8-80ab-44d5-8664-206753e7ac8d
- urn:uuid:a7354389-079e-4844-93b5-af6b7bf1d535
+ urn:uuid:4d209b2f-d7ce-4e6e-916c-c8642d368866
+ urn:uuid:a850f043-1422-4d16-8443-702dd2f9f13a
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
-
- 2022-04-21T19:21:52Z
- 2022-04-21T19:26:52Z
+
+ 2023-08-11T13:15:46Z
+ 2023-08-11T13:20:46Z
OK
- cfe51e71-6a2b-4cb4-aecd-3777076d63bc
-
-
- 8018397d-880d-4f88-940e-3b4eca098a0c
- [testExisting_dataExtension].[ContactKey]
- ContactKey
- 0
-
- 50
- true
- 3
- true
- Text
-
-
-
- testExisting_dataExtension
-
-
-
-
- bea0e308-5d45-4181-a673-da9972a7c674
- [testExisting_dataExtension].[LastName]
- LastName
- 0
-
- 50
- false
- 1
- false
- Text
-
-
-
- testExisting_dataExtension
-
-
-
-
- 2557b461-a699-4744-950d-e80a19afc2dc
- [testExisting_dataExtension].[EmailAddress]
- EmailAddress
- 0
-
- 254
- true
- 2
- false
- EmailAddress
-
-
-
- testExisting_dataExtension
-
-
-
-
- 42760528-a8c5-44dd-8c1d-ff34e5daee54
- [testExisting_dataExtension].[FirstName]
- FirstName
- 0
-
- 50
- false
- 0
- false
- Text
-
-
-
- testExisting_dataExtension
-
+ ba1b0c59-78c4-4608-8423-35dda2248d4d
+
+
+ 1111111
+
+
+ 2016-07-22T11:52:18.73
+ 2016-07-22T11:52:19.603
+ 89344
+
+ shared_data_default
+
+
+ 0
+
+
+ Shared Items
+
+ shared_data
+ true
+ false
+ false
+
+
+
+ 1111111
+
+
+ 2016-07-22T11:52:19.6
+ 2016-07-22T11:52:19.6
+ 89355
+
+ dataextension_default
+
+
+ 0
+
+
+ Data Extensions
+
+ dataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-07-22T11:52:19.603
+ 2016-07-22T11:52:19.603
+ 89356
+
+ shared_dataextension_default
+
+
+ 89344
+
+ shared_data_default
+
+ Shared Data Extensions
+
+ shared_dataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-07-29T12:13:27.28
+ 2016-07-29T12:13:27.28
+ 90889
+
+ HiddenCategory_default
+
+
+ 0
+
+
+ HiddenCategory
+ Hidden folder to store Hidden items
+ Hidden
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-08-23T09:22:27.54
+ 2016-08-23T09:22:27.54
+ 93698
+
+ salesforcedataextension_default
+
+
+ 0
+
+
+ Salesforce Data Extensions
+
+ salesforcedataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-08-23T09:22:27.55
+ 2016-08-23T09:22:27.55
+ 93699
+
+ shared_salesforcedataextension_defau
+
+
+ 89344
+
+ shared_data_default
+
+ Shared Salesforce Data Extensions
+
+ shared_salesforcedataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2020-01-27T10:50:46.573
+ 2020-01-27T10:50:46.573
+ 309082
+
+
+
+
+ 89355
+
+ dataextension_default
+
+ QueryStudioResults
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2020-04-17T08:14:19.763
+ 2020-04-17T08:14:19.763
+ 587750
+
+
+
+
+ 89356
+
+ shared_dataextension_default
+
+ catalyst target 1
+
+ shared_dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2020-07-09T02:30:12.38
+ 2021-12-16T03:43:30.753
+ 605618
+
+ dataextension_default
+
+
+ 89355
+
+ dataextension_default
+
+ Audiences
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2020-12-25T06:11:40.107
+ 2021-12-23T10:51:24.393
+ 633441
+
+
+
+
+ 89355
+
+ dataextension_default
+
+ System DEs
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2021-01-30T11:54:36.11
+ 2021-01-30T11:54:36.11
+ 638814
+
+ 0b72bf27-0678-484d-ac0b-a8762b9bec33
+
+
+ 89356
+
+ shared_dataextension_default
+
+ Customer 360 Segments
+ All Customer 360 segments will be grouped here. Each sub-folder relates to an activation profile name.
+ shared_dataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2021-01-30T11:56:38.77
+ 2021-01-30T11:56:38.77
+ 638815
+
+ cedd206d-178e-41cb-8965-ce255975b046
+
+
+ 638814
+
+ 0b72bf27-0678-484d-ac0b-a8762b9bec33
+
+ FirstAudience360 Segment
+
+ shared_dataextension
+ true
+ false
+ false
+
+
+
+ 1111111
+
+
+ 2021-02-07T10:44:01.413
+ 2021-12-16T03:43:33.38
+ 639967
+
+
+
+
+ 89355
+
+ dataextension_default
+
+ TestAudiences
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2021-08-04T15:17:18.533
+ 2021-08-04T15:17:18.567
+ 675203
+
+ A19F7E38-7369-497E-826F-D551F17FB0B4
+
+
+ 0
+
+
+ Synchronized Data Extensions
+
+ synchronizeddataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2021-10-03T05:01:37.23
+ 2021-10-03T05:01:37.37
+ 688352
+
+ B80AE306-55BC-4C2E-A79F-8CCA486F0BA0
+
+
+ 0
+
+
+ Synchronized Data Extensions
+
+ synchronizeddataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2022-10-26T09:48:38.293
+ 2022-10-26T09:48:38.31
+ 757145
+
+ 0ACB800B-AA8B-4F0F-9642-4907592C919C
+
+
+ 0
+
+
+ Synchronized Data Extensions
+
+ synchronizeddataextension
+ true
+ false
+ true
diff --git a/test/resources/9999999/hub/v1/contacts/schema/attributeGroups/get-response.json b/test/resources/9999999/hub/v1/contacts/schema/attributeGroups/get-response.json
index 078668f80..e0dbcb015 100644
--- a/test/resources/9999999/hub/v1/contacts/schema/attributeGroups/get-response.json
+++ b/test/resources/9999999/hub/v1/contacts/schema/attributeGroups/get-response.json
@@ -571,6 +571,49 @@
"identifierType": "FullyQualifiedName"
},
"namespace": ""
+ },
+ {
+ "mID": 7330928,
+ "objectState": "Created",
+ "attributeSetIdentifiers": [
+ {
+ "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "definitionKey": "testExisting_dataExtensionShared",
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "namespace": ""
+ }
+ ],
+ "isOwner": true,
+ "isPrimary": false,
+ "isSystemDefined": false,
+ "isHidden": false,
+ "canAddProperties": true,
+ "canAddRelationships": true,
+ "containsSchemaAttributes": false,
+ "canRemove": true,
+ "canChangeProperties": true,
+ "displayOrder": 8,
+ "requiredRelationships": [],
+ "canModify": true,
+ "attributeGroupIconKey": "et-icon-databas",
+ "fullyQualifiedName": "testExisting_attributeGroup",
+ "attributeGroupType": "Standard",
+ "localizedDescription": {},
+ "attributeCount": 6,
+ "definitionID": "79846c6e-5238-ee11-b85a-48df37d1de8a",
+ "definitionName": {
+ "value": "testExisting_attributeGroup"
+ },
+ "definitionKey": "testExisting_attributeGroup",
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "namespace": ""
}
],
"responseContext": {
diff --git a/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json b/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
index 8e5dc97ff..150cb21ff 100644
--- a/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
+++ b/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
@@ -19793,6 +19793,453 @@
"setDefinitionID": "f452de3f-31e2-e611-80cc-1402ec7222b4",
"setDefinitionKey": "PredictiveIntelProfiles",
"name": "Predictive Intelligence Profiles"
+ },
+ {
+ "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "testExisting_dataExtensionShared",
+ "definitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "relationships": [
+ {
+ "canModify": true,
+ "canRemove": true,
+ "isHidden": false,
+ "isSystemDefined": false,
+ "isGroupToSetRelationship": true,
+ "leftItem": {
+ "cardinality": "One",
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "identifier": "79846c6e-5238-ee11-b85a-48df37d1de8a",
+ "relationshipType": "AttributeGroup"
+ },
+ "leftRelationshipIDs": [
+ {
+ "type": "int16",
+ "value": "3"
+ }
+ ],
+ "leftRelationshipReferenceType": "CustomerData",
+ "relationshipAttributes": [
+ {
+ "leftAttributeID": "37778523-13f7-e911-a2d8-1402ec938a35",
+ "leftConnectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "rightAttributeID": "558b787a-5238-ee11-b85a-48df37d1de8a",
+ "rightConnectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ }
+ ],
+ "relationshipID": "598b787a-5238-ee11-b85a-48df37d1de8a",
+ "rightItem": {
+ "cardinality": "One",
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "identifier": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "relationshipType": "AttributeSet"
+ }
+ }
+ ],
+ "valueDefinitions": [
+ {
+ "baseType": "Numeric",
+ "dataSourceName": {},
+ "dataType": "LongNumber",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "548b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "CustomObjectKey",
+ "definitionName": {
+ "value": "Custom Object Key"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "fullyQualifiedName": "testExisting_dataExtensionShared.Custom Object Key",
+ "isHidden": true,
+ "isIdentityValue": true,
+ "isNullable": false,
+ "isPrimaryKey": false,
+ "isReadOnly": true,
+ "isSystemDefined": true,
+ "isUpdateable": true,
+ "parentDefinition": {
+ "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "testExisting_dataExtensionShared",
+ "definitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "_CustomObjectKey",
+ "valueDefinitionID": "548b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "CustomObjectKey",
+ "name": "Custom Object Key",
+ "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "setDefinitionKey": "testExisting_dataExtensionShared",
+ "setDefinitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "parentIdentifier": "528b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ {
+ "baseType": "Text",
+ "dataSourceName": {},
+ "dataType": "Text",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "588b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "FirstName",
+ "definitionName": {
+ "value": "FirstName"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "displayOrder": 0,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.FirstName",
+ "isHidden": false,
+ "isIdentityValue": false,
+ "isNullable": true,
+ "isPrimaryKey": false,
+ "isReadOnly": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 50,
+ "obfuscationProperties": {
+ "maskType": "None",
+ "maskTypeID": 0,
+ "storageTypeID": 1,
+ "storageType": "Plain",
+ "valueDefinitionID": "588b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ "ordinal": 0,
+ "parentDefinition": {
+ "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "testExisting_dataExtensionShared",
+ "definitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "FirstName",
+ "storageFieldReferenceID": {
+ "type": "guid",
+ "value": "391bfc9e-ea85-4610-a24b-d8400a36cdfc"
+ },
+ "valueDefinitionID": "588b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "FirstName",
+ "name": "FirstName",
+ "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "setDefinitionKey": "testExisting_dataExtensionShared",
+ "setDefinitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "parentIdentifier": "528b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ {
+ "baseType": "Text",
+ "dataSourceName": {},
+ "dataType": "Text",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "578b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "LastName",
+ "definitionName": {
+ "value": "LastName"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "displayOrder": 1,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.LastName",
+ "isHidden": false,
+ "isIdentityValue": false,
+ "isNullable": true,
+ "isPrimaryKey": false,
+ "isReadOnly": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 55,
+ "obfuscationProperties": {
+ "maskType": "None",
+ "maskTypeID": 0,
+ "storageTypeID": 1,
+ "storageType": "Plain",
+ "valueDefinitionID": "578b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ "ordinal": 1,
+ "parentDefinition": {
+ "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "testExisting_dataExtensionShared",
+ "definitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "LastName",
+ "storageFieldReferenceID": {
+ "type": "guid",
+ "value": "3f80ba1f-f957-400f-88cb-a9303491026d"
+ },
+ "valueDefinitionID": "578b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "LastName",
+ "name": "LastName",
+ "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "setDefinitionKey": "testExisting_dataExtensionShared",
+ "setDefinitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "parentIdentifier": "528b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ {
+ "baseType": "Text",
+ "dataSourceName": {},
+ "dataType": "EmailAddress",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "568b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "EmailAddress",
+ "definitionName": {
+ "value": "EmailAddress"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "displayOrder": 2,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.EmailAddress",
+ "isHidden": false,
+ "isIdentityValue": false,
+ "isNullable": false,
+ "isPrimaryKey": false,
+ "isReadOnly": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 254,
+ "obfuscationProperties": {
+ "maskType": "None",
+ "maskTypeID": 0,
+ "storageTypeID": 1,
+ "storageType": "Plain",
+ "valueDefinitionID": "568b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ "ordinal": 2,
+ "parentDefinition": {
+ "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "testExisting_dataExtensionShared",
+ "definitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "EmailAddress",
+ "storageFieldReferenceID": {
+ "type": "guid",
+ "value": "41b9575b-da06-41ed-8551-f76868451a51"
+ },
+ "valueDefinitionID": "568b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "EmailAddress",
+ "name": "EmailAddress",
+ "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "setDefinitionKey": "testExisting_dataExtensionShared",
+ "setDefinitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "parentIdentifier": "528b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ {
+ "baseType": "Text",
+ "dataSourceName": {},
+ "dataType": "Text",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "538b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "testField",
+ "definitionName": {
+ "value": "testField"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "displayOrder": 3,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.testField",
+ "isHidden": false,
+ "isIdentityValue": false,
+ "isNullable": true,
+ "isPrimaryKey": false,
+ "isReadOnly": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 254,
+ "obfuscationProperties": {
+ "maskType": "None",
+ "maskTypeID": 0,
+ "storageTypeID": 1,
+ "storageType": "Plain",
+ "valueDefinitionID": "538b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ "ordinal": 3,
+ "parentDefinition": {
+ "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "testExisting_dataExtensionShared",
+ "definitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "testField",
+ "storageFieldReferenceID": {
+ "type": "guid",
+ "value": "ec7a606d-f38e-4c91-a5f2-02bf231a0954"
+ },
+ "valueDefinitionID": "538b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "testField",
+ "name": "testField",
+ "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "setDefinitionKey": "testExisting_dataExtensionShared",
+ "setDefinitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "parentIdentifier": "528b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ {
+ "baseType": "Text",
+ "dataSourceName": {},
+ "dataType": "Text",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "558b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "ContactKey",
+ "definitionName": {
+ "value": "ContactKey"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "displayOrder": 4,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.ContactKey",
+ "isHidden": false,
+ "isIdentityValue": false,
+ "isNullable": false,
+ "isPrimaryKey": true,
+ "isReadOnly": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 50,
+ "obfuscationProperties": {
+ "maskType": "None",
+ "maskTypeID": 0,
+ "storageTypeID": 1,
+ "storageType": "Plain",
+ "valueDefinitionID": "558b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ "ordinal": 4,
+ "parentDefinition": {
+ "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "testExisting_dataExtensionShared",
+ "definitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "ContactKey",
+ "storageFieldReferenceID": {
+ "type": "guid",
+ "value": "49d0db37-dff0-49d9-9d82-eb29b345f238"
+ },
+ "valueDefinitionID": "558b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "ContactKey",
+ "name": "ContactKey",
+ "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "setDefinitionKey": "testExisting_dataExtensionShared",
+ "setDefinitionName": {
+ "value": "testExisting_dataExtensionShared"
+ },
+ "parentIdentifier": "528b787a-5238-ee11-b85a-48df37d1de8a"
+ }
+ ],
+ "attributeCount": 0,
+ "canAddValues": true,
+ "canChangeValues": true,
+ "canModify": true,
+ "canRemove": true,
+ "categoryID": 89356,
+ "createdBy": 700301950,
+ "createDate": "2023-08-11T08:22:00",
+ "customObjectOwnerMID": 7281698,
+ "dataRetentionProperties": {
+ "isRowBasedRetention": true,
+ "isResetRetentionPeriodOnImport": false,
+ "isDeleteAtEndOfRetentionPeriod": false,
+ "periodLength": 6,
+ "periodUnitOfMeasure": 5,
+ "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a"
+ },
+ "localizedDescription": {
+ "value": "Container for my test emails"
+ },
+ "fullyQualifiedName": "testExisting_dataExtensionShared",
+ "isCustomObjectBacked": true,
+ "isEvent": false,
+ "isHidden": false,
+ "isReadOnly": false,
+ "isRoot": false,
+ "isSendable": true,
+ "isShared": true,
+ "isSystemDefined": false,
+ "isTestaable": true,
+ "parentID": "00000000-0000-0000-0000-000000000000",
+ "relationshipCount": 1,
+ "sendAttributeStorageName": "ContactKey",
+ "sendContactKeyStorageName": "_SubscriberKey",
+ "storageLogicalType": "DataExtension",
+ "storageName": "testExisting_dataExtensionShared",
+ "storageObjectIDs": ["5b8b787a-5238-ee11-b85a-48df37d1de8a"],
+ "storageReferenceID": {
+ "type": "guid",
+ "value": "21711373-72c1-ec11-b83b-shared"
+ },
+ "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
+ "setDefinitionKey": "testExisting_dataExtensionShared",
+ "name": "testExisting_dataExtensionShared"
}
],
"responseContext": {
diff --git a/test/type.attributeGroup.test.js b/test/type.attributeGroup.test.js
index 49ff53a13..61bdaaeaa 100644
--- a/test/type.attributeGroup.test.js
+++ b/test/type.attributeGroup.test.js
@@ -26,16 +26,16 @@ describe('type: attributeGroup', () => {
retrieve['testInstance/testBU'].attributeGroup
? Object.keys(retrieve['testInstance/testBU'].attributeGroup).length
: 0,
- 7,
- 'only 7 attributeGroups expected in retrieve response'
+ 8,
+ 'only 8 attributeGroups expected in retrieve response'
);
// get results from cache
const result = cache.getCache();
assert.equal(
result.attributeGroup ? Object.keys(result.attributeGroup).length : 0,
- 7,
- 'only 7 attributeGroups expected in cache'
+ 8,
+ 'only 8 attributeGroups expected in cache'
);
assert.deepEqual(
await testUtils.getActualJson('ETMobileConnect', 'attributeGroup'),
diff --git a/test/type.attributeSet.test.js b/test/type.attributeSet.test.js
index d05ea88a0..a894b7f09 100644
--- a/test/type.attributeSet.test.js
+++ b/test/type.attributeSet.test.js
@@ -26,15 +26,15 @@ describe('type: attributeSet', () => {
retrieve['testInstance/testBU'].attributeSet
? Object.keys(retrieve['testInstance/testBU'].attributeSet).length
: 0,
- 27,
- 'only 27 attributeSets expected in retrieve response'
+ 28,
+ 'only 28 attributeSets expected in retrieve response'
);
// get results from cache
const result = cache.getCache();
assert.equal(
result.attributeSet ? Object.keys(result.attributeSet).length : 0,
- 27,
- 'only 27 attributeSets expected in cache'
+ 28,
+ 'only 28 attributeSets expected in cache'
);
assert.deepEqual(
diff --git a/test/type.dataExtension.test.js b/test/type.dataExtension.test.js
index 096c6f54d..addbf820c 100644
--- a/test/type.dataExtension.test.js
+++ b/test/type.dataExtension.test.js
@@ -99,10 +99,18 @@ describe('type: dataExtension', () => {
});
it('Should create & update a dataExtension', async () => {
// WHEN
- await handler.deploy('testInstance/testBU', ['dataExtension']);
+ const deployResult = await handler.deploy('testInstance/testBU', ['dataExtension']);
// THEN
assert.equal(process.exitCode, false, 'deploy should not have thrown an error');
+ assert.equal(
+ deployResult['testInstance/testBU']?.dataExtension
+ ? Object.keys(deployResult['testInstance/testBU']?.dataExtension).length
+ : 0,
+ 2,
+ 'two dataExtensions to be deployed'
+ );
+
// get results from cache
const result = cache.getCache();
assert.equal(
@@ -129,8 +137,104 @@ describe('type: dataExtension', () => {
);
return;
});
- it('Should create & update a shared dataExtension');
- it('Should create & update a shared dataExtension with --fixShared');
+ it('Should create & update a shared dataExtension', async () => {
+ // WHEN
+ const deployResult = await handler.deploy('testInstance/_ParentBU_', ['dataExtension']);
+ // THEN
+ assert.equal(process.exitCode, false, 'deploy should not have thrown an error');
+
+ assert.equal(
+ deployResult['testInstance/_ParentBU_']?.dataExtension
+ ? Object.keys(deployResult['testInstance/_ParentBU_']?.dataExtension).length
+ : 0,
+ 2,
+ 'two dataExtensions to be deployed'
+ );
+
+ // get results from cache
+ const result = cache.getCache();
+ assert.equal(
+ result.dataExtension ? Object.keys(result.dataExtension).length : 0,
+ 2,
+ 'two dataExtensions expected'
+ );
+ // insert
+ assert.deepEqual(
+ await testUtils.getActualJson(
+ 'testNew_dataExtensionShared',
+ 'dataExtension',
+ '_ParentBU_'
+ ),
+ await testUtils.getExpectedJson('1111111', 'dataExtension', 'create'),
+ 'returned metadata was not equal expected for create'
+ );
+ // update
+ assert.deepEqual(
+ await testUtils.getActualJson(
+ 'testExisting_dataExtensionShared',
+ 'dataExtension',
+ '_ParentBU_'
+ ),
+ await testUtils.getExpectedJson('1111111', 'dataExtension', 'update'),
+ 'returned metadata was not equal expected for update'
+ );
+ assert.equal(
+ testUtils.getAPIHistoryLength(),
+ 8,
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+ );
+ return;
+ });
+ it('Should create & update a shared dataExtension with --fixShared & --skipInteraction', async () => {
+ // WHEN
+ handler.setOptions({ fixShared: 'testBU', skipInteraction: true, _runningTest: true });
+
+ const deployResult = await handler.deploy('testInstance/_ParentBU_', ['dataExtension']);
+ // THEN
+ assert.equal(process.exitCode, false, 'deploy should not have thrown an error');
+
+ assert.equal(
+ deployResult['testInstance/_ParentBU_']?.dataExtension
+ ? Object.keys(deployResult['testInstance/_ParentBU_']?.dataExtension).length
+ : 0,
+ 2,
+ 'two dataExtensions to be deployed'
+ );
+
+ // get results from cache
+ const result = cache.getCache();
+ assert.equal(
+ result.dataExtension ? Object.keys(result.dataExtension).length : 0,
+ 2,
+ 'two dataExtensions expected'
+ );
+ // insert
+ assert.deepEqual(
+ await testUtils.getActualJson(
+ 'testNew_dataExtensionShared',
+ 'dataExtension',
+ '_ParentBU_'
+ ),
+ await testUtils.getExpectedJson('1111111', 'dataExtension', 'create'),
+ 'returned metadata was not equal expected for create'
+ );
+ // update
+ assert.deepEqual(
+ await testUtils.getActualJson(
+ 'testExisting_dataExtensionShared',
+ 'dataExtension',
+ '_ParentBU_'
+ ),
+ await testUtils.getExpectedJson('1111111', 'dataExtension', 'update'),
+ 'returned metadata was not equal expected for update'
+ );
+ assert.equal(
+ testUtils.getAPIHistoryLength(),
+ 12,
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+ );
+ return;
+ });
it('Should rename fields');
});
describe('Templating ================', () => {
From a4bb88b2ef46f13bfaaff3b5b538ed70468353fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 16:43:19 +0200
Subject: [PATCH 10/70] #940: improve CICD test for script
---
test/type.script.test.js | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/test/type.script.test.js b/test/type.script.test.js
index 84202cfec..e5582bb05 100644
--- a/test/type.script.test.js
+++ b/test/type.script.test.js
@@ -358,7 +358,12 @@ describe('type: script', () => {
assert.equal(
fileList[1].split('\\').join('/'),
'retrieve/testInstance/testBU/script/testExisting_script.script-meta.ssjs',
- 'wrong JSON path'
+ 'wrong SSJS path'
+ );
+ assert.equal(
+ fileList[2].split('\\').join('/'),
+ 'retrieve/testInstance/testBU/script/testExisting_script.script-meta.html',
+ 'wrong HTML path'
);
return;
});
From 938cf5d2922d502bf73d9c5957d26b5c0ad0abe4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 11 Aug 2023 16:44:47 +0200
Subject: [PATCH 11/70] #940: improve logs
---
lib/metadataTypes/DataExtension.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 80b7174c0..e4320d5aa 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -382,7 +382,7 @@ class DataExtension extends MetadataType {
if (sharedDataExtensionsKeys.length > 0 && !Util.OPTIONS.fixShared) {
Util.logger.warn(
- 'Shared Data Extensions were updated but fixShared option is not set. This can result in your changes not being visible on child BUs.'
+ 'Shared Data Extensions were updated but --fixShared option is not set. This can result in your changes not being visible on child BUs.'
);
// TODO replace with 1 inquirer question to ask if child BUs should be fixed if needed
}
@@ -485,7 +485,7 @@ class DataExtension extends MetadataType {
} else {
Util.logger.info(
Util.getGrayMsg(
- ` - No matching attributeSet found for given Shared Data Extensions keys found on ${childBuName}`
+ ` - No matching attributeSet found for given Shared Data Extensions keys found on BU ${childBuName}`
)
);
}
From 1b605fa20ae9f3e49bac771c7727497d0a3d75ef Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Aug 2023 20:20:26 +0000
Subject: [PATCH 12/70] Bump eslint from 8.46.0 to 8.47.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.46.0 to 8.47.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.46.0...v8.47.0)
---
updated-dependencies:
- dependency-name: eslint
dependency-type: direct:development
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
package-lock.json | 74 +++++++++++++++++++++++------------------------
package.json | 2 +-
2 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 2f84a7329..380e2af9c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,7 +38,7 @@
"axios-mock-adapter": "1.21.5",
"chai": "4.3.7",
"chai-files": "1.4.0",
- "eslint": "8.46.0",
+ "eslint": "8.47.0",
"eslint-config-prettier": "9.0.0",
"eslint-config-ssjs": "1.1.11",
"eslint-plugin-jsdoc": "46.4.6",
@@ -554,9 +554,9 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz",
- "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+ "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
@@ -599,9 +599,9 @@
"dev": true
},
"node_modules/@eslint/js": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz",
- "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==",
+ "version": "8.47.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz",
+ "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -3147,15 +3147,15 @@
}
},
"node_modules/eslint": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz",
- "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==",
+ "version": "8.47.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz",
+ "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.1",
- "@eslint/js": "^8.46.0",
+ "@eslint/eslintrc": "^2.1.2",
+ "@eslint/js": "^8.47.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -3166,7 +3166,7 @@
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.2",
+ "eslint-visitor-keys": "^3.4.3",
"espree": "^9.6.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
@@ -3390,9 +3390,9 @@
}
},
"node_modules/eslint-visitor-keys": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz",
- "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==",
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4292,9 +4292,9 @@
}
},
"node_modules/globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "version": "13.21.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
+ "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@@ -10338,9 +10338,9 @@
"dev": true
},
"@eslint/eslintrc": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz",
- "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+ "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
@@ -10375,9 +10375,9 @@
}
},
"@eslint/js": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz",
- "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==",
+ "version": "8.47.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz",
+ "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==",
"dev": true
},
"@humanwhocodes/config-array": {
@@ -12314,15 +12314,15 @@
"dev": true
},
"eslint": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz",
- "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==",
+ "version": "8.47.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz",
+ "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.1",
- "@eslint/js": "^8.46.0",
+ "@eslint/eslintrc": "^2.1.2",
+ "@eslint/js": "^8.47.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -12333,7 +12333,7 @@
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.2",
+ "eslint-visitor-keys": "^3.4.3",
"espree": "^9.6.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
@@ -12493,9 +12493,9 @@
}
},
"eslint-visitor-keys": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz",
- "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==",
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true
},
"espree": {
@@ -13116,9 +13116,9 @@
}
},
"globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "version": "13.21.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
+ "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
"dev": true,
"requires": {
"type-fest": "^0.20.2"
diff --git a/package.json b/package.json
index c88c78bc6..35eb9fcc0 100644
--- a/package.json
+++ b/package.json
@@ -84,7 +84,7 @@
"axios-mock-adapter": "1.21.5",
"chai": "4.3.7",
"chai-files": "1.4.0",
- "eslint": "8.46.0",
+ "eslint": "8.47.0",
"eslint-config-prettier": "9.0.0",
"eslint-config-ssjs": "1.1.11",
"eslint-plugin-jsdoc": "46.4.6",
From dea24395d5bc87f23f66f9cdb78cfc7f49d2fcd4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 16 Aug 2023 16:34:07 +0200
Subject: [PATCH 13/70] #940: evaluate fix-success; refactoring
---
docs/dist/documentation.md | 72 +++++----
lib/metadataTypes/DataExtension.js | 249 +++++++++++++++++------------
2 files changed, 184 insertions(+), 137 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index a27dc2ce2..c80e5c097 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -220,24 +220,28 @@ Provides default functionality that can be overwritten by child metadata type cl
helper for postDeployTasks
DataExtension.(upsertedMetadata, originalMetadata, createdUpdated) ⇒ void
-helper for postDeployTasks
+
takes care of updating attribute groups on child BUs after an update to Shared DataExtensions
+helper for postDeployTasks
fixes an issue where shared data extensions are not visible in data designer on child BU; SF known issue: https://issues.salesforce.com/#q=W-11031095
-DataExtension.(childBuName, buObjectParent, clientParent, sharedDataExtensions) ⇒ Promise.<Array.<string>>
-helper for DataExtension.#postDeployFixShared
+DataExtension.() ⇒ Array.<string>
+helper for DataExtension.#fixShared
+
+DataExtension.(childBuName, buObjectParent, clientParent, sharedDataExtensionMap) ⇒ Promise.<Array.<string>>
+helper for DataExtension.#fixShared
+
+DataExtension.(deId, deKey, buObjectChildBu, clientChildBu, buObjectParent, clientParent) ⇒ Promise.<boolean>
+method that actually takes care of triggering the update for a particular BU-sharedDe combo
+helper for DataExtension.#fixShared_onBU
-DataExtension.(deId, deKey, buObjectChildBu, clientChildBu, buObjectParent, clientParent) ⇒ Promise
-
-DataExtension.(randomSuffix, buObjectChildBu, clientChildBu, deKey, fieldObjectID) ⇒ Promise
-
DataExtension.(buObjectChildBu, clientChildBu, deKey, deId) ⇒ Promise.<string>
helper for DataExtension.#fixShared_item
DataExtension.(randomSuffix, buObjectParent, clientParent, deKey) ⇒ Promise.<string>
helper for DataExtension.#fixShared_item
-DataExtension.() ⇒ Array.<string>
-helper for DataExtension.#postDeployFixShared
+DataExtension.(randomSuffix, buObjectChildBu, clientChildBu, deKey, fieldObjectID) ⇒ Promise
+helper for DataExtension.#fixShared_item
getUserName(userList, item, fieldname) ⇒ string
@@ -8589,6 +8593,7 @@ helper for [postDeployTasks](#Automation.postDeployTasks)
## DataExtension.(upsertedMetadata, originalMetadata, createdUpdated) ⇒ void
+takes care of updating attribute groups on child BUs after an update to Shared DataExtensions
helper for [postDeployTasks](#DataExtension.postDeployTasks)
fixes an issue where shared data extensions are not visible in data designer on child BU; SF known issue: https://issues.salesforce.com/#q=W-11031095
@@ -8602,8 +8607,15 @@ fixes an issue where shared data extensions are not visible in data designer on
-## DataExtension.(childBuName, buObjectParent, clientParent, sharedDataExtensions) ⇒ Promise.<Array.<string>>
-helper for [DataExtension.#postDeployFixShared](DataExtension.#postDeployFixShared)
+## DataExtension.() ⇒ Array.<string>
+helper for [DataExtension.#fixShared](DataExtension.#fixShared)
+
+**Kind**: global function
+**Returns**: Array.<string>
- list of selected BU names
+
+
+## DataExtension.(childBuName, buObjectParent, clientParent, sharedDataExtensionMap) ⇒ Promise.<Array.<string>>
+helper for [DataExtension.#fixShared](DataExtension.#fixShared)
**Kind**: global function
**Returns**: Promise.<Array.<string>>
- updated shared DE keys on BU
@@ -8613,13 +8625,16 @@ helper for [DataExtension.#postDeployFixShared](DataExtension.#postDeployFixShar
| childBuName | string
| name of child BU to fix |
| buObjectParent | TYPE.BuObject
| bu object for parent BU |
| clientParent | object
| SDK for parent BU |
-| sharedDataExtensions | object
| list of IDs of shared data extensions |
+| sharedDataExtensionMap | Object.<string, string>
| ID-Key relationship of shared data extensions |
-## DataExtension.(deId, deKey, buObjectChildBu, clientChildBu, buObjectParent, clientParent) ⇒ Promise
+## DataExtension.(deId, deKey, buObjectChildBu, clientChildBu, buObjectParent, clientParent) ⇒ Promise.<boolean>
+method that actually takes care of triggering the update for a particular BU-sharedDe combo
+helper for [DataExtension.#fixShared_onBU](DataExtension.#fixShared_onBU)
+
**Kind**: global function
-**Returns**: Promise
- -
+**Returns**: Promise.<boolean>
- flag that signals if the fix was successful
| Param | Type | Description |
| --- | --- | --- |
@@ -8632,20 +8647,6 @@ helper for [DataExtension.#postDeployFixShared](DataExtension.#postDeployFixShar
-## DataExtension.(randomSuffix, buObjectChildBu, clientChildBu, deKey, fieldObjectID) ⇒ Promise
-**Kind**: global function
-**Returns**: Promise
- -
-
-| Param | Type | Description |
-| --- | --- | --- |
-| randomSuffix | string
| - |
-| buObjectChildBu | TYPE.BuObject
| BU object for Child BU |
-| clientChildBu | object
| SDK for child BU |
-| deKey | string
| dataExtension key |
-| fieldObjectID | string
| field ObjectID |
-
-
-
## DataExtension.(buObjectChildBu, clientChildBu, deKey, deId) ⇒ Promise.<string>
helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
@@ -8676,11 +8677,20 @@ helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
-## DataExtension.() ⇒ Array.<string>
-helper for [DataExtension.#postDeployFixShared](DataExtension.#postDeployFixShared)
+## DataExtension.(randomSuffix, buObjectChildBu, clientChildBu, deKey, fieldObjectID) ⇒ Promise
+helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
**Kind**: global function
-**Returns**: Array.<string>
- list of selected BU names
+**Returns**: Promise
- -
+
+| Param | Type | Description |
+| --- | --- | --- |
+| randomSuffix | string
| - |
+| buObjectChildBu | TYPE.BuObject
| BU object for Child BU |
+| clientChildBu | object
| SDK for child BU |
+| deKey | string
| dataExtension key |
+| fieldObjectID | string
| field ObjectID |
+
## getUserName(userList, item, fieldname) ⇒ string
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index e4320d5aa..a29244e35 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -356,10 +356,11 @@ class DataExtension extends MetadataType {
DataExtensionField.postRetrieveTasks(field, true);
}
}
- await this.#postDeployFixShared(upsertedMetadata, originalMetadata, createdUpdated);
+ await this.#fixShared(upsertedMetadata, originalMetadata, createdUpdated);
}
/**
+ * takes care of updating attribute groups on child BUs after an update to Shared DataExtensions
* helper for {@link DataExtension.postDeployTasks}
* fixes an issue where shared data extensions are not visible in data designer on child BU; SF known issue: https://issues.salesforce.com/#q=W-11031095
*
@@ -368,7 +369,7 @@ class DataExtension extends MetadataType {
* @param {{created: number, updated: number}} createdUpdated counter representing successful creates/updates
* @returns {void}
*/
- static async #postDeployFixShared(upsertedMetadata, originalMetadata, createdUpdated) {
+ static async #fixShared(upsertedMetadata, originalMetadata, createdUpdated) {
if (this.buObject.eid !== this.buObject.mid || createdUpdated.updated === 0) {
// only if we were executing a deploy on parent bu could we be deploying shared data extensions
// only if updates were made could the issue in https://issues.salesforce.com/#q=W-11031095 affect data designer
@@ -382,20 +383,22 @@ class DataExtension extends MetadataType {
if (sharedDataExtensionsKeys.length > 0 && !Util.OPTIONS.fixShared) {
Util.logger.warn(
- 'Shared Data Extensions were updated but --fixShared option is not set. This can result in your changes not being visible on child BUs.'
+ 'Shared Data Extensions were updated but --fixShared option is not set. This can result in your changes not being visible in attribute groups on child BUs.'
+ );
+ Util.logger.info(
+ 'We recommend to re-run your deployment with the --fixShared option unless you are sure your Shared Data Extension is not used in attribute groups on any child BU.'
);
- // TODO replace with 1 inquirer question to ask if child BUs should be fixed if needed
}
if (sharedDataExtensionsKeys.length > 0 && Util.OPTIONS.fixShared) {
// select which BUs to run this for
- const selectedBuNames = await this.#fixSharedGetBUs();
+ const selectedBuNames = await this.#fixShared_getBUs();
// backup settings
const buObjectBak = this.buObject;
const clientBak = this.client;
- // get dataExtension IDs
- const sharedDataExtensions = {};
+ // get dataExtension ID-Key relationship
+ const sharedDataExtensionMap = {};
for (const key of sharedDataExtensionsKeys) {
try {
const id = cache.searchForField(
@@ -405,7 +408,7 @@ class DataExtension extends MetadataType {
'ObjectID',
this.buObject.eid
);
- sharedDataExtensions[id] = key;
+ sharedDataExtensionMap[id] = key;
} catch {
continue;
}
@@ -416,13 +419,14 @@ class DataExtension extends MetadataType {
`Fixing Shared Data Extensions details in data models of child BUs` +
Util.getKeysString(sharedDataExtensionsKeys)
);
+
for (const buName of selectedBuNames) {
- await this.#fixSharedOnBU(
+ await this.#fixShared_onBU(
buName,
buObjectBak,
clientBak,
- sharedDataExtensions
+ sharedDataExtensionMap
);
}
Util.logger.info(`Finished fixing Shared Data Extensions details in data models`);
@@ -437,15 +441,62 @@ class DataExtension extends MetadataType {
}
/**
- * helper for {@link DataExtension.#postDeployFixShared}
+ * helper for {@link DataExtension.#fixShared}
+ *
+ * @returns {string[]} list of selected BU names
+ */
+ static async #fixShared_getBUs() {
+ const buListObj = this.properties.credentials[this.buObject.credential].businessUnits;
+ const fixBuPreselected = [];
+ if (typeof Util.OPTIONS.fixShared === 'string') {
+ const availableBuNames = Object.keys(buListObj);
+ fixBuPreselected.push(
+ ...Util.OPTIONS.fixShared
+ .split(',')
+ .filter(Boolean)
+ .map((bu) => bu.trim())
+ .filter((bu) => availableBuNames.includes(bu))
+ );
+ }
+ if (Util.skipInteraction && fixBuPreselected.length) {
+ return fixBuPreselected;
+ }
+
+ const buList = Object.keys(buListObj)
+ .map((name) => ({ name, value: name, checked: fixBuPreselected.includes(name) }))
+ .filter((bu) => bu.value !== Util.parentBuName);
+ const questions = {
+ type: 'checkbox',
+ name: 'businessUnits',
+ message: 'Please select BUs that have access to the updated Shared Data Extensions:',
+ pageSize: 10,
+ choices: buList,
+ };
+ let responses = null;
+
+ try {
+ responses = await inquirer.prompt(questions);
+ } catch (ex) {
+ Util.logger.info(ex);
+ }
+ return responses.businessUnits;
+ }
+
+ /**
+ * helper for {@link DataExtension.#fixShared}
*
* @param {string} childBuName name of child BU to fix
* @param {TYPE.BuObject} buObjectParent bu object for parent BU
* @param {object} clientParent SDK for parent BU
- * @param {object} sharedDataExtensions list of IDs of shared data extensions
+ * @param {Object.} sharedDataExtensionMap ID-Key relationship of shared data extensions
* @returns {Promise.} updated shared DE keys on BU
*/
- static async #fixSharedOnBU(childBuName, buObjectParent, clientParent, sharedDataExtensions) {
+ static async #fixShared_onBU(
+ childBuName,
+ buObjectParent,
+ clientParent,
+ sharedDataExtensionMap
+ ) {
/** @type {TYPE.BuObject} */
const buObjectChildBu = {
eid: this.properties.credentials[buObjectParent.credential].eid,
@@ -461,42 +512,59 @@ class DataExtension extends MetadataType {
AttributeSet.buObject = buObjectChildBu;
AttributeSet.client = clientChildBu;
const sharedDeIdsUsedOnBU = await AttributeSet.retrieveForSharedDEs(
- sharedDataExtensions
+ sharedDataExtensionMap
);
if (sharedDeIdsUsedOnBU.length) {
+ let sharedDataExtensionsKeys = sharedDeIdsUsedOnBU.map(
+ (deId) => sharedDataExtensionMap[deId]
+ );
Util.logger.info(
` - Fixing dataExtensions on BU ${childBuName} ` +
- Util.getKeysString(
- sharedDeIdsUsedOnBU.map((deId) => sharedDataExtensions[deId])
- )
+ Util.getKeysString(sharedDataExtensionsKeys)
);
for (const deId of sharedDeIdsUsedOnBU) {
// dont use Promise.all to ensure order of execution; otherwise, switched BU contexts in one step will affect the next
- await this.#fixShared_item(
+ const fixed = await this.#fixShared_item(
deId,
- sharedDataExtensions[deId],
+ sharedDataExtensionMap[deId],
buObjectChildBu,
clientChildBu,
buObjectParent,
clientParent
);
+ if (!fixed) {
+ // remove from list of shared DEs that were fixed
+ sharedDataExtensionsKeys = sharedDataExtensionsKeys.filter(
+ (key) => key !== sharedDataExtensionMap[deId]
+ );
+ }
}
+ if (sharedDataExtensionsKeys.length) {
+ Util.logger.debug(
+ ` - Fixed ${sharedDataExtensionsKeys.length}/${
+ sharedDeIdsUsedOnBU.length
+ }: ${sharedDataExtensionsKeys.join(', ')}`
+ );
+ }
+ return sharedDataExtensionsKeys;
} else {
Util.logger.info(
Util.getGrayMsg(
` - No matching attributeSet found for given Shared Data Extensions keys found on BU ${childBuName}`
)
);
+ return [];
}
- return sharedDeIdsUsedOnBU;
} catch (ex) {
Util.logger.error(ex.message);
- return;
+ return [];
}
}
/**
+ * method that actually takes care of triggering the update for a particular BU-sharedDe combo
+ * helper for {@link DataExtension.#fixShared_onBU}
*
* @param {string} deId data extension ObjectID
* @param {string} deKey dataExtension key
@@ -504,7 +572,7 @@ class DataExtension extends MetadataType {
* @param {object} clientChildBu SDK for child BU
* @param {TYPE.BuObject} buObjectParent BU object for Parent BU
* @param {object} clientParent SDK for parent BU
- * @returns {Promise} -
+ * @returns {Promise.} flag that signals if the fix was successful
*/
static async #fixShared_item(
deId,
@@ -514,57 +582,43 @@ class DataExtension extends MetadataType {
buObjectParent,
clientParent
) {
- // add field via child BU
- const randomSuffix = await DataExtension.#fixShared_item_addField(
- buObjectChildBu,
- clientChildBu,
- deKey,
- deId
- );
+ try {
+ // add field via child BU
+ const randomSuffix = await DataExtension.#fixShared_item_addField(
+ buObjectChildBu,
+ clientChildBu,
+ deKey,
+ deId
+ );
- // get field ID from parent BU (it is not returned on child BU)
- const fieldObjectID = await DataExtension.#fixShared_item_getFieldId(
- randomSuffix,
- buObjectParent,
- clientParent,
- deKey
- );
+ // get field ID from parent BU (it is not returned on child BU)
+ const fieldObjectID = await DataExtension.#fixShared_item_getFieldId(
+ randomSuffix,
+ buObjectParent,
+ clientParent,
+ deKey
+ );
- // delete field via child BU
- await DataExtension.#fixShared_item_deleteField(
- randomSuffix,
- buObjectChildBu,
- clientChildBu,
- deKey,
- fieldObjectID
- );
+ // delete field via child BU
+ await DataExtension.#fixShared_item_deleteField(
+ randomSuffix,
+ buObjectChildBu,
+ clientChildBu,
+ deKey,
+ fieldObjectID
+ );
- Util.logger.info(` - Fixed dataExtension ${deKey} on BU ${buObjectChildBu.businessUnit}`);
- return true;
- }
+ Util.logger.info(
+ ` - Fixed dataExtension ${deKey} on BU ${buObjectChildBu.businessUnit}`
+ );
- /**
- *
- * @param {string} randomSuffix -
- * @param {TYPE.BuObject} buObjectChildBu BU object for Child BU
- * @param {object} clientChildBu SDK for child BU
- * @param {string} deKey dataExtension key
- * @param {string} fieldObjectID field ObjectID
- * @returns {Promise} -
- */
- static async #fixShared_item_deleteField(
- randomSuffix,
- buObjectChildBu,
- clientChildBu,
- deKey,
- fieldObjectID
- ) {
- DataExtensionField.buObject = buObjectChildBu;
- DataExtensionField.client = clientChildBu;
- await DataExtensionField.deleteByKeySOAP(
- deKey + '.TriggerUpdate' + randomSuffix,
- fieldObjectID
- );
+ return true;
+ } catch (ex) {
+ Util.logger.error(
+ `- error fixing dataExtension ${deKey} on BU ${buObjectChildBu.businessUnit}: ${ex.message}`
+ );
+ return false;
+ }
}
/**
@@ -634,45 +688,28 @@ class DataExtension extends MetadataType {
}
/**
- * helper for {@link DataExtension.#postDeployFixShared}
+ * helper for {@link DataExtension.#fixShared_item}
*
- * @returns {string[]} list of selected BU names
+ * @param {string} randomSuffix -
+ * @param {TYPE.BuObject} buObjectChildBu BU object for Child BU
+ * @param {object} clientChildBu SDK for child BU
+ * @param {string} deKey dataExtension key
+ * @param {string} fieldObjectID field ObjectID
+ * @returns {Promise} -
*/
- static async #fixSharedGetBUs() {
- const buListObj = this.properties.credentials[this.buObject.credential].businessUnits;
- const fixBuPreselected = [];
- if (typeof Util.OPTIONS.fixShared === 'string') {
- const availableBuNames = Object.keys(buListObj);
- fixBuPreselected.push(
- ...Util.OPTIONS.fixShared
- .split(',')
- .filter(Boolean)
- .map((bu) => bu.trim())
- .filter((bu) => availableBuNames.includes(bu))
- );
- }
- if (Util.skipInteraction && fixBuPreselected.length) {
- return fixBuPreselected;
- }
-
- const buList = Object.keys(buListObj)
- .map((name) => ({ name, value: name, checked: fixBuPreselected.includes(name) }))
- .filter((bu) => bu.value !== Util.parentBuName);
- const questions = {
- type: 'checkbox',
- name: 'businessUnits',
- message: 'Please select BUs that have access to the updated Shared Data Extensions:',
- pageSize: 10,
- choices: buList,
- };
- let responses = null;
-
- try {
- responses = await inquirer.prompt(questions);
- } catch (ex) {
- Util.logger.info(ex);
- }
- return responses.businessUnits;
+ static async #fixShared_item_deleteField(
+ randomSuffix,
+ buObjectChildBu,
+ clientChildBu,
+ deKey,
+ fieldObjectID
+ ) {
+ DataExtensionField.buObject = buObjectChildBu;
+ DataExtensionField.client = clientChildBu;
+ await DataExtensionField.deleteByKeySOAP(
+ deKey + '.TriggerUpdate' + randomSuffix,
+ fieldObjectID
+ );
}
/**
From 13d6879b727d7c0bf782844473e9f85f6aec648a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 16 Aug 2023 16:52:35 +0200
Subject: [PATCH 14/70] #940: allow pre-selecting ALL BUs via --fixShared=*
---
docs/dist/documentation.md | 13 +++++++++---
lib/metadataTypes/DataExtension.js | 33 ++++++++++++++++++++----------
2 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index c80e5c097..fe0313a62 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -235,13 +235,16 @@ fixes an issue where shared data extensions are not visible in data designer on
helper for DataExtension.#fixShared_onBU
DataExtension.(buObjectChildBu, clientChildBu, deKey, deId) ⇒ Promise.<string>
-helper for DataExtension.#fixShared_item
+add a new field to the shared DE to trigger an update to the data model
+helper for DataExtension.#fixShared_item
DataExtension.(randomSuffix, buObjectParent, clientParent, deKey) ⇒ Promise.<string>
-helper for DataExtension.#fixShared_item
+get ID of the field added by DataExtension.#fixShared_item_addField on the shared DE via parent BU
+helper for DataExtension.#fixShared_item
DataExtension.(randomSuffix, buObjectChildBu, clientChildBu, deKey, fieldObjectID) ⇒ Promise
-helper for DataExtension.#fixShared_item
+delete the field added by DataExtension.#fixShared_item_addField
+helper for DataExtension.#fixShared_item
getUserName(userList, item, fieldname) ⇒ string
@@ -1914,6 +1917,7 @@ Retrieves dataExtension metadata. Afterwards starts retrieval of dataExtensionCo
### DataExtension.retrieveSharedForCache([additionalFields]) ⇒ Promise.<TYPE.DataExtensionMap>
+get shared dataExtensions from parent BU and merge them into the cache
helper for [retrieve](#DataExtension.retrieve) and for AttributeSet.retrieveForSharedDEs
**Kind**: static method of [DataExtension
](#DataExtension)
@@ -8648,6 +8652,7 @@ helper for [DataExtension.#fixShared_onBU](DataExtension.#fixShared_onBU)
## DataExtension.(buObjectChildBu, clientChildBu, deKey, deId) ⇒ Promise.<string>
+add a new field to the shared DE to trigger an update to the data model
helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
**Kind**: global function
@@ -8663,6 +8668,7 @@ helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
## DataExtension.(randomSuffix, buObjectParent, clientParent, deKey) ⇒ Promise.<string>
+get ID of the field added by [DataExtension.#fixShared_item_addField](DataExtension.#fixShared_item_addField) on the shared DE via parent BU
helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
**Kind**: global function
@@ -8678,6 +8684,7 @@ helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
## DataExtension.(randomSuffix, buObjectChildBu, clientChildBu, deKey, fieldObjectID) ⇒ Promise
+delete the field added by [DataExtension.#fixShared_item_addField](DataExtension.#fixShared_item_addField)
helper for [DataExtension.#fixShared_item](DataExtension.#fixShared_item)
**Kind**: global function
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index a29244e35..4dd6e3ab5 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -448,23 +448,34 @@ class DataExtension extends MetadataType {
static async #fixShared_getBUs() {
const buListObj = this.properties.credentials[this.buObject.credential].businessUnits;
const fixBuPreselected = [];
+ const availableBuNames = Object.keys(buListObj).filter(
+ (buName) => buName !== Util.parentBuName
+ );
if (typeof Util.OPTIONS.fixShared === 'string') {
- const availableBuNames = Object.keys(buListObj);
- fixBuPreselected.push(
- ...Util.OPTIONS.fixShared
- .split(',')
- .filter(Boolean)
- .map((bu) => bu.trim())
- .filter((bu) => availableBuNames.includes(bu))
- );
+ if (Util.OPTIONS.fixShared === '*') {
+ // pre-select all BUs
+ fixBuPreselected.push(...availableBuNames);
+ } else {
+ // pre-select BUs from comma-separated list
+ fixBuPreselected.push(
+ ...Util.OPTIONS.fixShared
+ .split(',')
+ .filter(Boolean)
+ .map((bu) => bu.trim())
+ .filter((bu) => availableBuNames.includes(bu))
+ );
+ }
}
if (Util.skipInteraction && fixBuPreselected.length) {
+ // assume programmatic use case or user that wants to skip the wizard. Use pre-selected BUs
return fixBuPreselected;
}
- const buList = Object.keys(buListObj)
- .map((name) => ({ name, value: name, checked: fixBuPreselected.includes(name) }))
- .filter((bu) => bu.value !== Util.parentBuName);
+ const buList = availableBuNames.map((name) => ({
+ name,
+ value: name,
+ checked: fixBuPreselected.includes(name),
+ }));
const questions = {
type: 'checkbox',
name: 'businessUnits',
From 87e6267cdac16f2fed330cf41508067c6b8e9d6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 16 Aug 2023 16:54:21 +0200
Subject: [PATCH 15/70] #940: refactoring & jsdoc
---
lib/metadataTypes/DataExtension.js | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 4dd6e3ab5..3600dfab8 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -47,7 +47,7 @@ class DataExtension extends MetadataType {
};
}
Util.logger.info(` - Caching dependent Metadata: dataExtensionField`);
- await this._attachFields(metadataMap, fieldOptions);
+ await this.#attachFields(metadataMap, fieldOptions);
/** @type {object[]} */
const metadataToCreate = [];
@@ -633,6 +633,7 @@ class DataExtension extends MetadataType {
}
/**
+ * add a new field to the shared DE to trigger an update to the data model
* helper for {@link DataExtension.#fixShared_item}
*
* @param {TYPE.BuObject} buObjectChildBu BU object for Child BU
@@ -672,6 +673,7 @@ class DataExtension extends MetadataType {
}
/**
+ * get ID of the field added by {@link DataExtension.#fixShared_item_addField} on the shared DE via parent BU
* helper for {@link DataExtension.#fixShared_item}
*
* @param {string} randomSuffix -
@@ -699,6 +701,7 @@ class DataExtension extends MetadataType {
}
/**
+ * delete the field added by {@link DataExtension.#fixShared_item_addField}
* helper for {@link DataExtension.#fixShared_item}
*
* @param {string} randomSuffix -
@@ -757,7 +760,7 @@ class DataExtension extends MetadataType {
// in case of cache dont get fields
if (metadata && retrieveDir) {
// get fields from API
- await this._attachFields(metadata, fieldOptions, additionalFields);
+ await this.#attachFields(metadata, fieldOptions, additionalFields);
}
if (!retrieveDir && this.buObject.eid !== this.buObject.mid) {
const metadataParentBu = await this.retrieveSharedForCache(additionalFields);
@@ -777,6 +780,7 @@ class DataExtension extends MetadataType {
}
/**
+ * get shared dataExtensions from parent BU and merge them into the cache
* helper for {@link DataExtension.retrieve} and for AttributeSet.retrieveForSharedDEs
*
* @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
@@ -860,7 +864,7 @@ class DataExtension extends MetadataType {
* @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
* @returns {Promise.} -
*/
- static async _attachFields(metadata, fieldOptions, additionalFields) {
+ static async #attachFields(metadata, fieldOptions, additionalFields) {
const fieldsObj = await this._retrieveFields(fieldOptions, additionalFields);
const fieldKeys = Object.keys(fieldsObj);
// add fields to corresponding DE
From d2f72abe2633b01d698a02219bb121a8e1dd3776 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 16 Aug 2023 21:30:45 +0200
Subject: [PATCH 16/70] #940: refactoring
---
docs/dist/documentation.md | 6 +++---
lib/metadataTypes/AttributeSet.js | 10 ++++------
lib/metadataTypes/DataExtension.js | 2 +-
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index fe0313a62..666ecb716 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -1325,7 +1325,7 @@ AttributeSet MetadataType
* [AttributeSet](#AttributeSet) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], [key])](#AttributeSet.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveForCache()](#AttributeSet.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.retrieveForSharedDEs(sharedDataExtensions)](#AttributeSet.retrieveForSharedDEs) ⇒ Promise.<Array.<string>>
+ * [.retrieveForSharedDEs(sharedDataExtensionIds)](#AttributeSet.retrieveForSharedDEs) ⇒ Promise.<Array.<string>>
* [.parseResponseBody(body, [singleRetrieve])](#AttributeSet.parseResponseBody) ⇒ TYPE.MetadataTypeMap
* [.postRetrieveTasks(metadata)](#AttributeSet.postRetrieveTasks) ⇒ TYPE.MetadataTypeItem
* [._getSystemValueDefinitions()](#AttributeSet._getSystemValueDefinitions) ⇒ Array.<object>
@@ -1354,7 +1354,7 @@ Retrieves Metadata of schema set definitions for caching.
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise
-### AttributeSet.retrieveForSharedDEs(sharedDataExtensions) ⇒ Promise.<Array.<string>>
+### AttributeSet.retrieveForSharedDEs(sharedDataExtensionIds) ⇒ Promise.<Array.<string>>
Retrieves Metadata of schema set definitions for caching.
**Kind**: static method of [AttributeSet
](#AttributeSet)
@@ -1362,7 +1362,7 @@ Retrieves Metadata of schema set definitions for caching.
| Param | Type | Description |
| --- | --- | --- |
-| sharedDataExtensions | object
| list of IDs of shared data extensions |
+| sharedDataExtensionIds | Array.<string>
| ID array for shared data extensions |
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index e3ca68caf..a558587df 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -50,11 +50,11 @@ class AttributeSet extends MetadataType {
/**
* Retrieves Metadata of schema set definitions for caching.
*
- * @param {object} sharedDataExtensions list of IDs of shared data extensions
+ * @param {string[]} sharedDataExtensionIds ID array for shared data extensions
* @returns {Promise.} Promise of list of shared dataExtension IDs
*/
- static async retrieveForSharedDEs(sharedDataExtensions) {
- if (!Object.keys(sharedDataExtensions).length) {
+ static async retrieveForSharedDEs(sharedDataExtensionIds) {
+ if (!sharedDataExtensionIds.length) {
return [];
}
const result = await super.retrieveREST(null, '/hub/v1/contacts/schema/setDefinitions');
@@ -67,9 +67,7 @@ class AttributeSet extends MetadataType {
metadataMap[key].storageLogicalType === 'DataExtension'
)
.filter((key) =>
- Object.keys(sharedDataExtensions).includes(
- metadataMap[key].storageReferenceID.value
- )
+ sharedDataExtensionIds.includes(metadataMap[key].storageReferenceID.value)
)
.map((key) => metadataMap[key].storageReferenceID.value)
.filter(Boolean);
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 3600dfab8..2875cffab 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -523,7 +523,7 @@ class DataExtension extends MetadataType {
AttributeSet.buObject = buObjectChildBu;
AttributeSet.client = clientChildBu;
const sharedDeIdsUsedOnBU = await AttributeSet.retrieveForSharedDEs(
- sharedDataExtensionMap
+ Object.keys(sharedDataExtensionMap)
);
if (sharedDeIdsUsedOnBU.length) {
let sharedDataExtensionsKeys = sharedDeIdsUsedOnBU.map(
From 08068a8d7cc8dcf37367badfff9dd406191185aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 10:50:32 +0200
Subject: [PATCH 17/70] #940: improve skip fixShared logic and logs
---
lib/metadataTypes/DataExtension.js | 41 +++++++++++++++---------------
1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 2875cffab..4dd880959 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -370,26 +370,29 @@ class DataExtension extends MetadataType {
* @returns {void}
*/
static async #fixShared(upsertedMetadata, originalMetadata, createdUpdated) {
- if (this.buObject.eid !== this.buObject.mid || createdUpdated.updated === 0) {
+ if (this.buObject.eid !== this.buObject.mid) {
// only if we were executing a deploy on parent bu could we be deploying shared data extensions
+ Util.logger.debug(`Skipping fixShared logic because we are not executing on Parent BU`);
+ return;
+ }
+ if (createdUpdated.updated === 0) {
// only if updates were made could the issue in https://issues.salesforce.com/#q=W-11031095 affect data designer
- Util.logger.debug(`EID != MID or nothing updated`);
+ Util.logger.debug(`Skipping fixShared logic because nothing was updated`);
return;
}
// find all shared data extensions
+ if (!this.deployedSharedKeys.length) {
+ Util.logger.debug(
+ `Skipping fixShared logic because no Shared Data Extensions were updated`
+ );
+ return;
+ }
+
const sharedDataExtensionsKeys = this.deployedSharedKeys;
this.deployedSharedKeys = null;
- if (sharedDataExtensionsKeys.length > 0 && !Util.OPTIONS.fixShared) {
- Util.logger.warn(
- 'Shared Data Extensions were updated but --fixShared option is not set. This can result in your changes not being visible in attribute groups on child BUs.'
- );
- Util.logger.info(
- 'We recommend to re-run your deployment with the --fixShared option unless you are sure your Shared Data Extension is not used in attribute groups on any child BU.'
- );
- }
- if (sharedDataExtensionsKeys.length > 0 && Util.OPTIONS.fixShared) {
+ if (Util.OPTIONS.fixShared) {
// select which BUs to run this for
const selectedBuNames = await this.#fixShared_getBUs();
@@ -421,13 +424,7 @@ class DataExtension extends MetadataType {
);
for (const buName of selectedBuNames) {
- await this.#fixShared_onBU(
- buName,
- buObjectBak,
- clientBak,
-
- sharedDataExtensionMap
- );
+ await this.#fixShared_onBU(buName, buObjectBak, clientBak, sharedDataExtensionMap);
}
Util.logger.info(`Finished fixing Shared Data Extensions details in data models`);
@@ -435,8 +432,12 @@ class DataExtension extends MetadataType {
this.buObject = buObjectBak;
this.client = clientBak;
} else {
- // no shared dataExtensions or fixShared option not enabled
- return;
+ Util.logger.warn(
+ 'Shared Data Extensions were updated but --fixShared option is not set. This can result in your changes not being visible in attribute groups on child BUs.'
+ );
+ Util.logger.info(
+ 'We recommend to re-run your deployment with the --fixShared option unless you are sure your Shared Data Extension is not used in attribute groups on any child BU.'
+ );
}
}
From 1076b7020e93430a40c759bf26e240f83e8e599e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 10:54:29 +0200
Subject: [PATCH 18/70] #940: only run fixShared logic if fields of a shared
data extension were added/changed
---
lib/metadataTypes/DataExtension.js | 11 ++++++++++-
lib/metadataTypes/DataExtensionField.js | 5 +++++
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 4dd880959..acf737fe2 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -389,8 +389,17 @@ class DataExtension extends MetadataType {
return;
}
- const sharedDataExtensionsKeys = this.deployedSharedKeys;
+ const sharedDataExtensionsKeys = this.deployedSharedKeys.filter((key) =>
+ DataExtensionField.fixShared_fieldChange.includes(key)
+ );
this.deployedSharedKeys = null;
+ if (!sharedDataExtensionsKeys.length) {
+ // only if updates were made could the issue in https://issues.salesforce.com/#q=W-11031095 affect data designer
+ Util.logger.debug(
+ `Skipping fixShared logic because no fields were changed on updated Shared Data Extensions`
+ );
+ return;
+ }
if (Util.OPTIONS.fixShared) {
// select which BUs to run this for
diff --git a/lib/metadataTypes/DataExtensionField.js b/lib/metadataTypes/DataExtensionField.js
index 9fc4c2071..c993c15f9 100644
--- a/lib/metadataTypes/DataExtensionField.js
+++ b/lib/metadataTypes/DataExtensionField.js
@@ -248,6 +248,11 @@ class DataExtensionField extends MetadataType {
}` + deployColumns.map((item) => item.Name).join(', ')
)
);
+ // create list of DE keys that had changes to their fields to be able to use it as a filter in the --fixShared logic
+ this.fixShared_fieldChange ||= [];
+ if (deployColumns.length) {
+ this.fixShared_fieldChange.push(deKey);
+ }
return existingFieldByName;
}
From 7947ce30ea74ec799c6b00d447d2e79d84ec90fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 15:06:32 +0200
Subject: [PATCH 19/70] #940: check if attributeSet fields actually need fixing
---
docs/dist/documentation.md | 11 +--
lib/metadataTypes/AttributeSet.js | 108 +++++++++++++++++++++---
lib/metadataTypes/DataExtension.js | 24 +++---
lib/metadataTypes/DataExtensionField.js | 17 +++-
4 files changed, 131 insertions(+), 29 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 666ecb716..f01ef5cf2 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -1325,7 +1325,7 @@ AttributeSet MetadataType
* [AttributeSet](#AttributeSet) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], [key])](#AttributeSet.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveForCache()](#AttributeSet.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.retrieveForSharedDEs(sharedDataExtensionIds)](#AttributeSet.retrieveForSharedDEs) ⇒ Promise.<Array.<string>>
+ * [.fixShared_retrieve(sharedDataExtensionMap, fixShared_fieldChange)](#AttributeSet.fixShared_retrieve) ⇒ Promise.<Array.<string>>
* [.parseResponseBody(body, [singleRetrieve])](#AttributeSet.parseResponseBody) ⇒ TYPE.MetadataTypeMap
* [.postRetrieveTasks(metadata)](#AttributeSet.postRetrieveTasks) ⇒ TYPE.MetadataTypeItem
* [._getSystemValueDefinitions()](#AttributeSet._getSystemValueDefinitions) ⇒ Array.<object>
@@ -1352,9 +1352,9 @@ Retrieves Metadata of schema set definitions for caching.
**Kind**: static method of [AttributeSet
](#AttributeSet)
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise
-
+
-### AttributeSet.retrieveForSharedDEs(sharedDataExtensionIds) ⇒ Promise.<Array.<string>>
+### AttributeSet.fixShared\_retrieve(sharedDataExtensionMap, fixShared_fieldChange) ⇒ Promise.<Array.<string>>
Retrieves Metadata of schema set definitions for caching.
**Kind**: static method of [AttributeSet
](#AttributeSet)
@@ -1362,7 +1362,8 @@ Retrieves Metadata of schema set definitions for caching.
| Param | Type | Description |
| --- | --- | --- |
-| sharedDataExtensionIds | Array.<string>
| ID array for shared data extensions |
+| sharedDataExtensionMap | Object.<string, string>
| ID-Key relationship of shared data extensions |
+| fixShared_fieldChange | object
| DataExtensionField.fixShared_fieldChange |
@@ -1918,7 +1919,7 @@ Retrieves dataExtension metadata. Afterwards starts retrieval of dataExtensionCo
### DataExtension.retrieveSharedForCache([additionalFields]) ⇒ Promise.<TYPE.DataExtensionMap>
get shared dataExtensions from parent BU and merge them into the cache
-helper for [retrieve](#DataExtension.retrieve) and for AttributeSet.retrieveForSharedDEs
+helper for [retrieve](#DataExtension.retrieve) and for AttributeSet.fixShared_retrieve
**Kind**: static method of [DataExtension
](#DataExtension)
**Returns**: Promise.<TYPE.DataExtensionMap>
- keyField => metadata map
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index a558587df..a076d514d 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -50,28 +50,114 @@ class AttributeSet extends MetadataType {
/**
* Retrieves Metadata of schema set definitions for caching.
*
- * @param {string[]} sharedDataExtensionIds ID array for shared data extensions
+ * @param {Object.} sharedDataExtensionMap ID-Key relationship of shared data extensions
+ * @param {object} fixShared_fieldChange DataExtensionField.fixShared_fieldChange
* @returns {Promise.} Promise of list of shared dataExtension IDs
*/
- static async retrieveForSharedDEs(sharedDataExtensionIds) {
- if (!sharedDataExtensionIds.length) {
+ static async fixShared_retrieve(sharedDataExtensionMap, fixShared_fieldChange) {
+ if (!Object.keys(sharedDataExtensionMap).length) {
return [];
}
const result = await super.retrieveREST(null, '/hub/v1/contacts/schema/setDefinitions');
const metadataMap = result?.metadata;
if (metadataMap && Object.keys(metadataMap).length) {
- const sharedDEs = Object.keys(metadataMap)
+ const sharedDeIds = Object.keys(metadataMap)
.filter(
- (key) =>
- metadataMap[key].storageLogicalType === 'ExactTargetSchema' ||
- metadataMap[key].storageLogicalType === 'DataExtension'
- )
- .filter((key) =>
- sharedDataExtensionIds.includes(metadataMap[key].storageReferenceID.value)
+ (asKey) =>
+ metadataMap[asKey].storageLogicalType === 'ExactTargetSchema' ||
+ metadataMap[asKey].storageLogicalType === 'DataExtension'
)
+ .filter((asKey) => {
+ // check if dataExtension ID is found on any attributeSet of this BU
+ if (sharedDataExtensionMap[metadataMap[asKey].storageReferenceID.value]) {
+ Util.logger.debug(
+ ` shared dataExtension ID ${metadataMap[asKey].storageReferenceID.value} found in attributeGroup ${asKey}`
+ );
+ return true;
+ } else {
+ return false;
+ }
+ })
+ .filter((asKey) => {
+ // check if any of the updated dataExtension fields dont exist on the attributeSet or are out of date
+ const deKey =
+ sharedDataExtensionMap[metadataMap[asKey].storageReferenceID.value];
+ const asFields = metadataMap[asKey].valueDefinitions;
+ if (!fixShared_fieldChange[deKey]) {
+ Util.logger.debug(
+ ` - No changed fields found. Assuming re-deploy with --fixShared flag`
+ );
+ return true;
+ }
+ const deFields = Object.values(fixShared_fieldChange[deKey]);
+ return deFields.some((deField) => {
+ const search = asFields.filter((asf) => asf.name === deField.Name);
+ if (!search.length) {
+ Util.logger.debug(
+ Util.getGrayMsg(
+ ` - Field ${deField.Name} not found in attributeSet`
+ )
+ );
+ return true;
+ }
+ const asField = search[0];
+ if (asField.dataType !== deField.FieldType) {
+ Util.logger.debug(
+ Util.getGrayMsg(
+ ` - Field ${deField.Name} FieldType changed (old: ${asField.dataType}; new: ${deField.FieldType})`
+ )
+ );
+ return true;
+ }
+ if (
+ (asField.defaultValue && deField.DefaultValue !== '') ||
+ (deField.FieldType === 'Boolean' &&
+ deField.DefaultValue !== '' &&
+ deField.DefaultValue
+ ? 'True'
+ : 'False' !== asField.defaultValue) ||
+ (deField.FieldType !== 'Boolean' &&
+ deField.DefaultValue !== asField.defaultValue)
+ ) {
+ Util.logger.debug(
+ Util.getGrayMsg(
+ ` - Field ${deField.Name} DefaultValue changed (old: ${asField.defaultValue}; new: ${deField.DefaultValue})`
+ )
+ );
+ return true;
+ }
+ // some field types don't carry the length property. reset to 0 to ease comparison
+ asField.length ||= 0;
+ if (asField.length !== deField.MaxLength) {
+ Util.logger.debug(
+ Util.getGrayMsg(
+ ` - Field ${deField.Name} MaxLength changed (old: ${asField.length}; new: ${deField.MaxLength})`
+ )
+ );
+ return true;
+ }
+ if (asField.isNullable !== deField.IsRequired) {
+ Util.logger.debug(
+ Util.getGrayMsg(
+ ` - Field ${deField.Name} IsRequired changed (old: ${asField.isNullable}; new: ${deField.IsRequired})`
+ )
+ );
+ return true;
+ }
+ if (asField.isPrimaryKey !== deField.IsPrimaryKey) {
+ Util.logger.debug(
+ Util.getGrayMsg(
+ ` - Field ${deField.Name} IsPrimaryKey changed (old: ${asField.isPrimaryKey}; new: ${deField.IsPrimaryKey})`
+ )
+ );
+ return true;
+ }
+ return false;
+ });
+ })
.map((key) => metadataMap[key].storageReferenceID.value)
.filter(Boolean);
- return sharedDEs;
+ return sharedDeIds;
} else {
// nothing to do - return empty array
return [];
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index acf737fe2..9215ff409 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -389,16 +389,19 @@ class DataExtension extends MetadataType {
return;
}
- const sharedDataExtensionsKeys = this.deployedSharedKeys.filter((key) =>
- DataExtensionField.fixShared_fieldChange.includes(key)
- );
+ const sharedDataExtensionsKeys = this.deployedSharedKeys;
this.deployedSharedKeys = null;
- if (!sharedDataExtensionsKeys.length) {
- // only if updates were made could the issue in https://issues.salesforce.com/#q=W-11031095 affect data designer
+ if (
+ !sharedDataExtensionsKeys.filter(
+ (deKey) =>
+ DataExtensionField.fixShared_fieldChange[deKey] &&
+ Object.keys(DataExtensionField.fixShared_fieldChange[deKey])?.length
+ )
+ ) {
Util.logger.debug(
- `Skipping fixShared logic because no fields were changed on updated Shared Data Extensions`
+ ` - No changed fields found. Assuming re-deploy with --fixShared flag`
);
- return;
+ return true;
}
if (Util.OPTIONS.fixShared) {
@@ -532,8 +535,9 @@ class DataExtension extends MetadataType {
AttributeSet.properties = this.properties;
AttributeSet.buObject = buObjectChildBu;
AttributeSet.client = clientChildBu;
- const sharedDeIdsUsedOnBU = await AttributeSet.retrieveForSharedDEs(
- Object.keys(sharedDataExtensionMap)
+ const sharedDeIdsUsedOnBU = await AttributeSet.fixShared_retrieve(
+ sharedDataExtensionMap,
+ DataExtensionField.fixShared_fieldChange
);
if (sharedDeIdsUsedOnBU.length) {
let sharedDataExtensionsKeys = sharedDeIdsUsedOnBU.map(
@@ -791,7 +795,7 @@ class DataExtension extends MetadataType {
/**
* get shared dataExtensions from parent BU and merge them into the cache
- * helper for {@link DataExtension.retrieve} and for AttributeSet.retrieveForSharedDEs
+ * helper for {@link DataExtension.retrieve} and for AttributeSet.fixShared_retrieve
*
* @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
* @returns {Promise.} keyField => metadata map
diff --git a/lib/metadataTypes/DataExtensionField.js b/lib/metadataTypes/DataExtensionField.js
index c993c15f9..4d81e45f1 100644
--- a/lib/metadataTypes/DataExtensionField.js
+++ b/lib/metadataTypes/DataExtensionField.js
@@ -99,6 +99,10 @@ class DataExtensionField extends MetadataType {
* @returns {Promise.>} existing fields by their original name to allow re-adding FieldType after update
*/
static async prepareDeployColumnsOnUpdate(deployColumns, deKey) {
+ // create list of DE keys that had changes to their fields to be able to use it as a filter in the --fixShared logic
+ this.fixShared_fieldChange ||= {};
+ this.fixShared_fieldChange[deKey] ||= {};
+
// get row count to know which field restrictions apply
let hasData = false;
try {
@@ -189,6 +193,9 @@ class DataExtensionField extends MetadataType {
Util.logger.verbose(`no change - removed field [${deKey}].[${item.Name}]`);
continue;
}
+ // track name of changed field
+ this.fixShared_fieldChange[deKey][item.Name] = JSON.parse(JSON.stringify(item));
+ this.fixShared_fieldChange[deKey][item.Name].FieldType = itemOld.FieldType;
// set the ObjectId for clear identification during update
item.ObjectID = itemOld.ObjectID;
@@ -217,6 +224,8 @@ class DataExtensionField extends MetadataType {
}
// Field doesn't exist in target, therefore Remove ObjectID if present
delete item.ObjectID;
+
+ this.fixShared_fieldChange[deKey][item.Name] = JSON.parse(JSON.stringify(item));
}
if (Util.isTrue(item.IsPrimaryKey) && Util.isFalse(item.IsRequired)) {
// applicable: with or without data
@@ -232,12 +241,14 @@ class DataExtensionField extends MetadataType {
`- Invalid value for 'IsRequired' of [${deKey}].[${item.Name}]. Found '${item.IsRequired}' instead of 'true'/'false'. Removing field from deploy!`
);
deployColumns.splice(i, 1);
+ delete this.fixShared_fieldChange[deKey][item.Name];
}
if (!Util.isTrue(item.IsPrimaryKey) && !Util.isFalse(item.IsPrimaryKey)) {
Util.logger.error(
`- Invalid value for 'IsPrimaryKey' of [${deKey}].[${item.Name}]. Found '${item.IsPrimaryKey}' instead of 'true'/'false'. Removing field from deploy!`
);
deployColumns.splice(i, 1);
+ delete this.fixShared_fieldChange[deKey][item.Name];
}
}
@@ -249,9 +260,9 @@ class DataExtensionField extends MetadataType {
)
);
// create list of DE keys that had changes to their fields to be able to use it as a filter in the --fixShared logic
- this.fixShared_fieldChange ||= [];
- if (deployColumns.length) {
- this.fixShared_fieldChange.push(deKey);
+ if (!deployColumns.length || !Object.keys(this.fixShared_fieldChange[deKey]).length) {
+ // no changed fields found. remove entry from list for easier processing
+ delete this.fixShared_fieldChange[deKey];
}
return existingFieldByName;
}
From 0630c5b16810c20e3e7fa3b470cd6bed7a0f763f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 15:30:29 +0200
Subject: [PATCH 20/70] #0: fix incorrect parameter count for retrieveREST
---
lib/metadataTypes/AttributeSet.js | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index a076d514d..7aa260442 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -31,13 +31,7 @@ class AttributeSet extends MetadataType {
const result = await AttributeGroup.retrieveForCache();
cache.setMetadata('attributeGroup', result.metadata);
}
- return super.retrieveREST(
- retrieveDir,
- '/hub/v1/contacts/schema/setDefinitions',
- null,
- null,
- key
- );
+ return super.retrieveREST(retrieveDir, '/hub/v1/contacts/schema/setDefinitions', null, key);
}
/**
* Retrieves Metadata of schema set definitions for caching.
From 773ff9925fe407fb531ea14a5e7aaa0613bbb791 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 15:32:29 +0200
Subject: [PATCH 21/70] #0: add missing attributeSet fields
---
.../definitions/AttributeSet.definition.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lib/metadataTypes/definitions/AttributeSet.definition.js b/lib/metadataTypes/definitions/AttributeSet.definition.js
index 47e77cde4..22d196ba0 100644
--- a/lib/metadataTypes/definitions/AttributeSet.definition.js
+++ b/lib/metadataTypes/definitions/AttributeSet.definition.js
@@ -119,6 +119,12 @@ module.exports = {
retrieving: true,
template: null,
},
+ 'dataRetentionProperties.periodLength': {
+ isCreateable: null,
+ isUpdateable: null,
+ retrieving: true,
+ template: null,
+ },
definitionID: {
isCreateable: null,
isUpdateable: null,
@@ -859,5 +865,11 @@ module.exports = {
retrieving: true,
template: null,
},
+ r__dataExtension_CustomerKey: {
+ isCreateable: null,
+ isUpdateable: null,
+ retrieving: true,
+ template: null,
+ },
},
};
From 9e6553900be109f6d24946d6de1a1eae23a15da4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 15:48:11 +0200
Subject: [PATCH 22/70] #940: jsdoc
---
docs/dist/documentation.md | 3 ++-
lib/metadataTypes/AttributeSet.js | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index f01ef5cf2..223bfdeb4 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -1355,7 +1355,8 @@ Retrieves Metadata of schema set definitions for caching.
### AttributeSet.fixShared\_retrieve(sharedDataExtensionMap, fixShared_fieldChange) ⇒ Promise.<Array.<string>>
-Retrieves Metadata of schema set definitions for caching.
+used to identify updated shared data extensions that are used in attributeSets.
+helper for DataExtension.#fixShared_onBU
**Kind**: static method of [AttributeSet
](#AttributeSet)
**Returns**: Promise.<Array.<string>>
- Promise of list of shared dataExtension IDs
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index 7aa260442..93fb43aa9 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -42,7 +42,8 @@ class AttributeSet extends MetadataType {
return super.retrieveREST(null, '/hub/v1/contacts/schema/setDefinitions');
}
/**
- * Retrieves Metadata of schema set definitions for caching.
+ * used to identify updated shared data extensions that are used in attributeSets.
+ * helper for DataExtension.#fixShared_onBU
*
* @param {Object.} sharedDataExtensionMap ID-Key relationship of shared data extensions
* @param {object} fixShared_fieldChange DataExtensionField.fixShared_fieldChange
From e9342501a8cfbea2f7bf0c20a4c05fe53e167da6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 16:13:51 +0200
Subject: [PATCH 23/70] #940: remove comments
---
test/type.dataExtension.test.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/test/type.dataExtension.test.js b/test/type.dataExtension.test.js
index addbf820c..17f30a354 100644
--- a/test/type.dataExtension.test.js
+++ b/test/type.dataExtension.test.js
@@ -342,7 +342,6 @@ describe('type: dataExtension', () => {
});
});
describe('Delete ================', () => {
- // TODO: add this test
it('Should delete the dataExtension', async () => {
// WHEN
const result = await handler.deleteByKey(
From 8cf5ae3743436bf0d81b89d55f65c28a09aabc13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 17:10:10 +0200
Subject: [PATCH 24/70] #940: fix test for --fixShared with added fields
---
lib/metadataTypes/AttributeSet.js | 33 ++++------
...ataExtensionShared.dataExtension-meta.json | 2 +-
.../dataExtension/update-expected.json | 2 +-
.../schema/setDefinitions/get-response.json | 60 -------------------
4 files changed, 15 insertions(+), 82 deletions(-)
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index 93fb43aa9..0c72a4dc1 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -66,7 +66,7 @@ class AttributeSet extends MetadataType {
// check if dataExtension ID is found on any attributeSet of this BU
if (sharedDataExtensionMap[metadataMap[asKey].storageReferenceID.value]) {
Util.logger.debug(
- ` shared dataExtension ID ${metadataMap[asKey].storageReferenceID.value} found in attributeGroup ${asKey}`
+ ` shared dataExtension ID ${metadataMap[asKey].storageReferenceID.value} found in attributeSet ${asKey}`
);
return true;
} else {
@@ -90,7 +90,7 @@ class AttributeSet extends MetadataType {
if (!search.length) {
Util.logger.debug(
Util.getGrayMsg(
- ` - Field ${deField.Name} not found in attributeSet`
+ ` - Field ${deField.Name} not found in attributeSet; Note: only first recognized difference is printed to log`
)
);
return true;
@@ -99,25 +99,24 @@ class AttributeSet extends MetadataType {
if (asField.dataType !== deField.FieldType) {
Util.logger.debug(
Util.getGrayMsg(
- ` - Field ${deField.Name} FieldType changed (old: ${asField.dataType}; new: ${deField.FieldType})`
+ ` - Field ${deField.Name} FieldType changed (old: ${asField.dataType}; new: ${deField.FieldType}); Note: only first recognized difference is printed to log`
)
);
return true;
}
+ asField.defaultValue ||= '';
if (
- (asField.defaultValue && deField.DefaultValue !== '') ||
+ (asField.defaultValue && deField.DefaultValue === '') ||
(deField.FieldType === 'Boolean' &&
- deField.DefaultValue !== '' &&
- deField.DefaultValue
- ? 'True'
- : 'False' !== asField.defaultValue) ||
+ deField.DefaultValue !== '' &&
+ (deField.DefaultValue
+ ? 'True'
+ : 'False' !== asField.defaultValue)) ||
(deField.FieldType !== 'Boolean' &&
deField.DefaultValue !== asField.defaultValue)
) {
Util.logger.debug(
- Util.getGrayMsg(
- ` - Field ${deField.Name} DefaultValue changed (old: ${asField.defaultValue}; new: ${deField.DefaultValue})`
- )
+ ` - Field ${deField.Name} DefaultValue changed (old: ${asField.defaultValue}; new: ${deField.DefaultValue}); Note: only first recognized difference is printed to log`
);
return true;
}
@@ -125,25 +124,19 @@ class AttributeSet extends MetadataType {
asField.length ||= 0;
if (asField.length !== deField.MaxLength) {
Util.logger.debug(
- Util.getGrayMsg(
- ` - Field ${deField.Name} MaxLength changed (old: ${asField.length}; new: ${deField.MaxLength})`
- )
+ ` - Field ${deField.Name} MaxLength changed (old: ${asField.length}; new: ${deField.MaxLength}); Note: only first recognized difference is printed to log`
);
return true;
}
if (asField.isNullable !== deField.IsRequired) {
Util.logger.debug(
- Util.getGrayMsg(
- ` - Field ${deField.Name} IsRequired changed (old: ${asField.isNullable}; new: ${deField.IsRequired})`
- )
+ ` - Field ${deField.Name} IsRequired changed (old: ${asField.isNullable}; new: ${deField.IsRequired}); Note: only first recognized difference is printed to log`
);
return true;
}
if (asField.isPrimaryKey !== deField.IsPrimaryKey) {
Util.logger.debug(
- Util.getGrayMsg(
- ` - Field ${deField.Name} IsPrimaryKey changed (old: ${asField.isPrimaryKey}; new: ${deField.IsPrimaryKey})`
- )
+ ` - Field ${deField.Name} IsPrimaryKey changed (old: ${asField.isPrimaryKey}; new: ${deField.IsPrimaryKey}); Note: only first recognized difference is printed to log`
);
return true;
}
diff --git a/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json b/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json
index 23a55d5a1..9af73620a 100644
--- a/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json
+++ b/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json
@@ -38,7 +38,7 @@
"FieldType": "EmailAddress"
},
{
- "Name": "testField",
+ "Name": "newField",
"DefaultValue": "",
"MaxLength": 254,
"IsRequired": false,
diff --git a/test/resources/1111111/dataExtension/update-expected.json b/test/resources/1111111/dataExtension/update-expected.json
index e889c1f87..bd074f2ad 100644
--- a/test/resources/1111111/dataExtension/update-expected.json
+++ b/test/resources/1111111/dataExtension/update-expected.json
@@ -41,7 +41,7 @@
"IsPrimaryKey": false,
"IsRequired": false,
"MaxLength": 254,
- "Name": "testField"
+ "Name": "newField"
}
],
"IsSendable": false,
diff --git a/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json b/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
index 150cb21ff..54e6f02ab 100644
--- a/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
+++ b/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
@@ -20075,66 +20075,6 @@
},
"parentIdentifier": "528b787a-5238-ee11-b85a-48df37d1de8a"
},
- {
- "baseType": "Text",
- "dataSourceName": {},
- "dataType": "Text",
- "description": "",
- "localizedDescription": {
- "value": ""
- },
- "definitionID": "538b787a-5238-ee11-b85a-48df37d1de8a",
- "definitionKey": "testField",
- "definitionName": {
- "value": "testField"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "displayOrder": 3,
- "fullyQualifiedName": "testExisting_dataExtensionShared.testField",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": true,
- "isPrimaryKey": false,
- "isReadOnly": false,
- "isSystemDefined": false,
- "isUpdateable": true,
- "length": 254,
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageTypeID": 1,
- "storageType": "Plain",
- "valueDefinitionID": "538b787a-5238-ee11-b85a-48df37d1de8a"
- },
- "ordinal": 3,
- "parentDefinition": {
- "definitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
- "definitionKey": "testExisting_dataExtensionShared",
- "definitionName": {
- "value": "testExisting_dataExtensionShared"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- }
- },
- "parentType": "Set",
- "storageName": "testField",
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "ec7a606d-f38e-4c91-a5f2-02bf231a0954"
- },
- "valueDefinitionID": "538b787a-5238-ee11-b85a-48df37d1de8a",
- "valueDefinitionKey": "testField",
- "name": "testField",
- "setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
- "setDefinitionKey": "testExisting_dataExtensionShared",
- "setDefinitionName": {
- "value": "testExisting_dataExtensionShared"
- },
- "parentIdentifier": "528b787a-5238-ee11-b85a-48df37d1de8a"
- },
{
"baseType": "Text",
"dataSourceName": {},
From 550ebb4ffdb71a9bfdb362f8b5507d123fabdec0 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 17 Aug 2023 15:16:13 +0000
Subject: [PATCH 25/70] Bump lint-staged from 13.2.3 to 14.0.0
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 13.2.3 to 14.0.0.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Commits](https://github.com/okonet/lint-staged/compare/v13.2.3...v14.0.0)
---
updated-dependencies:
- dependency-name: lint-staged
dependency-type: direct:development
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
---
package-lock.json | 649 +++++++++++++++++++++++++++++-----------------
package.json | 2 +-
2 files changed, 415 insertions(+), 236 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 380e2af9c..f418dd413 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -48,7 +48,7 @@
"fast-xml-parser": "4.2.7",
"husky": "8.0.3",
"jsdoc-to-markdown": "8.0.0",
- "lint-staged": "13.2.3",
+ "lint-staged": "14.0.0",
"mocha": "10.2.0",
"mock-fs": "5.2.0",
"npm-check": "6.0.1",
@@ -1409,15 +1409,6 @@
"node": "*"
}
},
- "node_modules/astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/async": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
@@ -2130,9 +2121,9 @@
}
},
"node_modules/cli-truncate/node_modules/strip-ansi": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
- "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"dependencies": {
"ansi-regex": "^6.0.1"
@@ -2253,9 +2244,9 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"node_modules/colorette": {
- "version": "2.0.19",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
- "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+ "version": "2.0.20",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true
},
"node_modules/colorspace": {
@@ -2372,12 +2363,12 @@
}
},
"node_modules/commander": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz",
- "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==",
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz",
+ "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==",
"dev": true,
"engines": {
- "node": ">=14"
+ "node": ">=16"
}
},
"node_modules/comment-parser": {
@@ -3501,10 +3492,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
+ "dev": true
+ },
"node_modules/execa": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.0.tgz",
- "integrity": "sha512-T6nIJO3LHxUZ6ahVRaxXz9WLEruXLqdcluA+UuTptXmLM7nDAn9lx9IfkxPyzEL21583qSt4RmL44pO71EHaJQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
+ "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.3",
@@ -4653,9 +4650,9 @@
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
},
"node_modules/human-signals": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.0.tgz",
- "integrity": "sha512-zyzVyMjpGBX2+6cDVZeFPCdtOtdsxOeseRhB9tkQ6xXmGUNrcnBzdEKPy3VPNYz+4gy1oukVOXcrJCunSyc6QQ==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
+ "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
"dev": true,
"engines": {
"node": ">=14.18.0"
@@ -5727,39 +5724,36 @@
}
},
"node_modules/lint-staged": {
- "version": "13.2.3",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.3.tgz",
- "integrity": "sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.0.tgz",
+ "integrity": "sha512-0tLf0pqZYkar/wu3nTctk4rVIG+d7PanDYv4/IQR4qwdqfQkTDziLRFnqMcLuLBTuUqmcLwsHPD2EjQ18d/oaA==",
"dev": true,
"dependencies": {
- "chalk": "5.2.0",
- "cli-truncate": "^3.1.0",
- "commander": "^10.0.0",
- "debug": "^4.3.4",
- "execa": "^7.0.0",
+ "chalk": "5.3.0",
+ "commander": "11.0.0",
+ "debug": "4.3.4",
+ "execa": "7.2.0",
"lilconfig": "2.1.0",
- "listr2": "^5.0.7",
- "micromatch": "^4.0.5",
- "normalize-path": "^3.0.0",
- "object-inspect": "^1.12.3",
- "pidtree": "^0.6.0",
- "string-argv": "^0.3.1",
- "yaml": "^2.2.2"
+ "listr2": "6.6.1",
+ "micromatch": "4.0.5",
+ "pidtree": "0.6.0",
+ "string-argv": "0.3.2",
+ "yaml": "2.3.1"
},
"bin": {
"lint-staged": "bin/lint-staged.js"
},
"engines": {
- "node": "^14.13.1 || >=16.0.0"
+ "node": "^16.14.0 || >=18.0.0"
},
"funding": {
"url": "https://opencollective.com/lint-staged"
}
},
"node_modules/lint-staged/node_modules/chalk": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz",
- "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
"dev": true,
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
@@ -5769,22 +5763,20 @@
}
},
"node_modules/listr2": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.8.tgz",
- "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==",
+ "version": "6.6.1",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz",
+ "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==",
"dev": true,
"dependencies": {
- "cli-truncate": "^2.1.0",
- "colorette": "^2.0.19",
- "log-update": "^4.0.0",
- "p-map": "^4.0.0",
+ "cli-truncate": "^3.1.0",
+ "colorette": "^2.0.20",
+ "eventemitter3": "^5.0.1",
+ "log-update": "^5.0.1",
"rfdc": "^1.3.0",
- "rxjs": "^7.8.0",
- "through": "^2.3.8",
- "wrap-ansi": "^7.0.0"
+ "wrap-ansi": "^8.1.0"
},
"engines": {
- "node": "^14.13.1 || >=16.0.0"
+ "node": ">=16.0.0"
},
"peerDependencies": {
"enquirer": ">= 2.3.0 < 3"
@@ -5795,43 +5787,83 @@
}
}
},
- "node_modules/listr2/node_modules/cli-truncate": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
- "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+ "node_modules/listr2/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/listr2/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/listr2/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true
+ },
+ "node_modules/listr2/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"dependencies": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
},
"engines": {
- "node": ">=8"
+ "node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/listr2/node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "node_modules/listr2/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
"engines": {
- "node": ">=8"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
- "node_modules/listr2/node_modules/slice-ansi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
- "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+ "node_modules/listr2/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"dependencies": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
},
"engines": {
- "node": ">=8"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/load-json-file": {
@@ -5972,61 +6004,159 @@
}
},
"node_modules/log-update": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
- "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz",
+ "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==",
"dev": true,
"dependencies": {
- "ansi-escapes": "^4.3.0",
- "cli-cursor": "^3.1.0",
- "slice-ansi": "^4.0.0",
- "wrap-ansi": "^6.2.0"
+ "ansi-escapes": "^5.0.0",
+ "cli-cursor": "^4.0.0",
+ "slice-ansi": "^5.0.0",
+ "strip-ansi": "^7.0.1",
+ "wrap-ansi": "^8.0.1"
},
"engines": {
- "node": ">=10"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/log-update/node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "node_modules/log-update/node_modules/ansi-escapes": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz",
+ "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==",
"dev": true,
+ "dependencies": {
+ "type-fest": "^1.0.2"
+ },
"engines": {
- "node": ">=8"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/log-update/node_modules/slice-ansi": {
+ "node_modules/log-update/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/log-update/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/log-update/node_modules/cli-cursor": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
+ "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
"dev": true,
"dependencies": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
+ "restore-cursor": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true
+ },
+ "node_modules/log-update/node_modules/restore-cursor": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
+ "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+ "dev": true,
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dev": true,
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-update/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
},
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/log-update/node_modules/type-fest": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
+ "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
+ "dev": true,
"engines": {
"node": ">=10"
},
"funding": {
- "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
},
"engines": {
- "node": ">=8"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/logform": {
@@ -7491,21 +7621,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-map": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
- "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
- "dev": true,
- "dependencies": {
- "aggregate-error": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -8828,9 +8943,9 @@
}
},
"node_modules/slice-ansi/node_modules/ansi-styles": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz",
- "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"engines": {
"node": ">=12"
@@ -9028,9 +9143,9 @@
}
},
"node_modules/string-argv": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
- "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
+ "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
"dev": true,
"engines": {
"node": ">=0.6.19"
@@ -9876,9 +9991,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yaml": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
- "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
+ "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
"dev": true,
"engines": {
"node": ">= 14"
@@ -10992,12 +11107,6 @@
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true
},
- "astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "dev": true
- },
"async": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
@@ -11501,9 +11610,9 @@
}
},
"strip-ansi": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
- "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"requires": {
"ansi-regex": "^6.0.1"
@@ -11603,9 +11712,9 @@
}
},
"colorette": {
- "version": "2.0.19",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
- "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+ "version": "2.0.20",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true
},
"colorspace": {
@@ -11704,9 +11813,9 @@
}
},
"commander": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz",
- "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==",
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz",
+ "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==",
"dev": true
},
"comment-parser": {
@@ -12551,10 +12660,16 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
+ "eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
+ "dev": true
+ },
"execa": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.0.tgz",
- "integrity": "sha512-T6nIJO3LHxUZ6ahVRaxXz9WLEruXLqdcluA+UuTptXmLM7nDAn9lx9IfkxPyzEL21583qSt4RmL44pO71EHaJQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
+ "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.3",
@@ -13387,9 +13502,9 @@
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
},
"human-signals": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.0.tgz",
- "integrity": "sha512-zyzVyMjpGBX2+6cDVZeFPCdtOtdsxOeseRhB9tkQ6xXmGUNrcnBzdEKPy3VPNYz+4gy1oukVOXcrJCunSyc6QQ==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
+ "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
"dev": true
},
"husky": {
@@ -14152,75 +14267,92 @@
}
},
"lint-staged": {
- "version": "13.2.3",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.3.tgz",
- "integrity": "sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.0.tgz",
+ "integrity": "sha512-0tLf0pqZYkar/wu3nTctk4rVIG+d7PanDYv4/IQR4qwdqfQkTDziLRFnqMcLuLBTuUqmcLwsHPD2EjQ18d/oaA==",
"dev": true,
"requires": {
- "chalk": "5.2.0",
- "cli-truncate": "^3.1.0",
- "commander": "^10.0.0",
- "debug": "^4.3.4",
- "execa": "^7.0.0",
+ "chalk": "5.3.0",
+ "commander": "11.0.0",
+ "debug": "4.3.4",
+ "execa": "7.2.0",
"lilconfig": "2.1.0",
- "listr2": "^5.0.7",
- "micromatch": "^4.0.5",
- "normalize-path": "^3.0.0",
- "object-inspect": "^1.12.3",
- "pidtree": "^0.6.0",
- "string-argv": "^0.3.1",
- "yaml": "^2.2.2"
+ "listr2": "6.6.1",
+ "micromatch": "4.0.5",
+ "pidtree": "0.6.0",
+ "string-argv": "0.3.2",
+ "yaml": "2.3.1"
},
"dependencies": {
"chalk": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz",
- "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
"dev": true
}
}
},
"listr2": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.8.tgz",
- "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==",
+ "version": "6.6.1",
+ "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz",
+ "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==",
"dev": true,
"requires": {
- "cli-truncate": "^2.1.0",
- "colorette": "^2.0.19",
- "log-update": "^4.0.0",
- "p-map": "^4.0.0",
+ "cli-truncate": "^3.1.0",
+ "colorette": "^2.0.20",
+ "eventemitter3": "^5.0.1",
+ "log-update": "^5.0.1",
"rfdc": "^1.3.0",
- "rxjs": "^7.8.0",
- "through": "^2.3.8",
- "wrap-ansi": "^7.0.0"
+ "wrap-ansi": "^8.1.0"
},
"dependencies": {
- "cli-truncate": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
- "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
+ "ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"requires": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
}
},
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
+ "strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^6.0.1"
+ }
},
- "slice-ansi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
- "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+ "wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
}
}
}
@@ -14345,43 +14477,99 @@
}
},
"log-update": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
- "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz",
+ "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==",
"dev": true,
"requires": {
- "ansi-escapes": "^4.3.0",
- "cli-cursor": "^3.1.0",
- "slice-ansi": "^4.0.0",
- "wrap-ansi": "^6.2.0"
+ "ansi-escapes": "^5.0.0",
+ "cli-cursor": "^4.0.0",
+ "slice-ansi": "^5.0.0",
+ "strip-ansi": "^7.0.1",
+ "wrap-ansi": "^8.0.1"
},
"dependencies": {
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "ansi-escapes": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz",
+ "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^1.0.2"
+ }
+ },
+ "ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true
},
- "slice-ansi": {
+ "cli-cursor": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz",
+ "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==",
"dev": true,
"requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
+ "restore-cursor": "^4.0.0"
+ }
+ },
+ "emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true
+ },
+ "restore-cursor": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
+ "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
+ "dev": true,
+ "requires": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dev": true,
+ "requires": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^6.0.1"
}
},
+ "type-fest": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
+ "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==",
+ "dev": true
+ },
"wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
}
}
}
@@ -15498,15 +15686,6 @@
}
}
},
- "p-map": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
- "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
- "dev": true,
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -16483,9 +16662,9 @@
},
"dependencies": {
"ansi-styles": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz",
- "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true
}
}
@@ -16647,9 +16826,9 @@
}
},
"string-argv": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
- "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
+ "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
"dev": true
},
"string-width": {
@@ -17292,9 +17471,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yaml": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
- "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
+ "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
"dev": true
},
"yargs": {
diff --git a/package.json b/package.json
index 35eb9fcc0..18c2ea3dc 100644
--- a/package.json
+++ b/package.json
@@ -94,7 +94,7 @@
"fast-xml-parser": "4.2.7",
"husky": "8.0.3",
"jsdoc-to-markdown": "8.0.0",
- "lint-staged": "13.2.3",
+ "lint-staged": "14.0.0",
"mocha": "10.2.0",
"mock-fs": "5.2.0",
"npm-check": "6.0.1",
From 3df6eae47adc7dcc3e0c9f7c4eadc1ed247b965f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 17 Aug 2023 15:19:22 +0000
Subject: [PATCH 26/70] Bump inquirer from 8.2.5 to 8.2.6
Bumps [inquirer](https://github.com/SBoudrias/Inquirer.js) from 8.2.5 to 8.2.6.
- [Release notes](https://github.com/SBoudrias/Inquirer.js/releases)
- [Commits](https://github.com/SBoudrias/Inquirer.js/compare/inquirer@8.2.5...inquirer@8.2.6)
---
updated-dependencies:
- dependency-name: inquirer
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
package-lock.json | 43 ++++++++++++++++++++++++++++++++++---------
package.json | 2 +-
2 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f418dd413..4e55a12d5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,7 +16,7 @@
"console.table": "0.10.0",
"deep-equal": "2.2.2",
"fs-extra": "11.1.0",
- "inquirer": "8.2.5",
+ "inquirer": "8.2.6",
"json-to-table": "4.2.1",
"mustache": "4.2.0",
"p-limit": "3.1.0",
@@ -4780,9 +4780,9 @@
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"node_modules/inquirer": {
- "version": "8.2.5",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
- "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
+ "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
"dependencies": {
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.1",
@@ -4798,12 +4798,25 @@
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0",
"through": "^2.3.6",
- "wrap-ansi": "^7.0.0"
+ "wrap-ansi": "^6.0.1"
},
"engines": {
"node": ">=12.0.0"
}
},
+ "node_modules/inquirer/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/internal-slot": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
@@ -13585,9 +13598,9 @@
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"inquirer": {
- "version": "8.2.5",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
- "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
+ "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
"requires": {
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.1",
@@ -13603,7 +13616,19 @@
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0",
"through": "^2.3.6",
- "wrap-ansi": "^7.0.0"
+ "wrap-ansi": "^6.0.1"
+ },
+ "dependencies": {
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ }
+ }
}
},
"internal-slot": {
diff --git a/package.json b/package.json
index 18c2ea3dc..ff158ff70 100644
--- a/package.json
+++ b/package.json
@@ -65,7 +65,7 @@
"console.table": "0.10.0",
"deep-equal": "2.2.2",
"fs-extra": "11.1.0",
- "inquirer": "8.2.5",
+ "inquirer": "8.2.6",
"json-to-table": "4.2.1",
"mustache": "4.2.0",
"p-limit": "3.1.0",
From a201068ecd38d5cf06efc9954b4d6c2daf4b5b25 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 17:41:44 +0200
Subject: [PATCH 27/70] #940: make sure ALL fields on the DE are compared with
the attributeSet; add test for field rename
---
docs/dist/documentation.md | 6 +++---
lib/metadataTypes/AttributeSet.js | 10 +++++-----
lib/metadataTypes/DataExtension.js | 2 +-
lib/metadataTypes/DataExtensionField.js | 6 ++++++
.../testExisting_dataExtension.dataExtension-meta.json | 1 +
.../9999999/dataExtension/update-expected.json | 2 +-
test/type.dataExtension.test.js | 3 +--
7 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 223bfdeb4..af33ea2e1 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -1325,7 +1325,7 @@ AttributeSet MetadataType
* [AttributeSet](#AttributeSet) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], [key])](#AttributeSet.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveForCache()](#AttributeSet.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.fixShared_retrieve(sharedDataExtensionMap, fixShared_fieldChange)](#AttributeSet.fixShared_retrieve) ⇒ Promise.<Array.<string>>
+ * [.fixShared_retrieve(sharedDataExtensionMap, fixShared_fields)](#AttributeSet.fixShared_retrieve) ⇒ Promise.<Array.<string>>
* [.parseResponseBody(body, [singleRetrieve])](#AttributeSet.parseResponseBody) ⇒ TYPE.MetadataTypeMap
* [.postRetrieveTasks(metadata)](#AttributeSet.postRetrieveTasks) ⇒ TYPE.MetadataTypeItem
* [._getSystemValueDefinitions()](#AttributeSet._getSystemValueDefinitions) ⇒ Array.<object>
@@ -1354,7 +1354,7 @@ Retrieves Metadata of schema set definitions for caching.
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise
-### AttributeSet.fixShared\_retrieve(sharedDataExtensionMap, fixShared_fieldChange) ⇒ Promise.<Array.<string>>
+### AttributeSet.fixShared\_retrieve(sharedDataExtensionMap, fixShared_fields) ⇒ Promise.<Array.<string>>
used to identify updated shared data extensions that are used in attributeSets.
helper for DataExtension.#fixShared_onBU
@@ -1364,7 +1364,7 @@ helper for DataExtension.#fixShared_onBU
| Param | Type | Description |
| --- | --- | --- |
| sharedDataExtensionMap | Object.<string, string>
| ID-Key relationship of shared data extensions |
-| fixShared_fieldChange | object
| DataExtensionField.fixShared_fieldChange |
+| fixShared_fields | object
| DataExtensionField.fixShared_fields |
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index 0c72a4dc1..ef8bd19d5 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -46,10 +46,10 @@ class AttributeSet extends MetadataType {
* helper for DataExtension.#fixShared_onBU
*
* @param {Object.} sharedDataExtensionMap ID-Key relationship of shared data extensions
- * @param {object} fixShared_fieldChange DataExtensionField.fixShared_fieldChange
+ * @param {object} fixShared_fields DataExtensionField.fixShared_fields
* @returns {Promise.} Promise of list of shared dataExtension IDs
*/
- static async fixShared_retrieve(sharedDataExtensionMap, fixShared_fieldChange) {
+ static async fixShared_retrieve(sharedDataExtensionMap, fixShared_fields) {
if (!Object.keys(sharedDataExtensionMap).length) {
return [];
}
@@ -74,17 +74,17 @@ class AttributeSet extends MetadataType {
}
})
.filter((asKey) => {
- // check if any of the updated dataExtension fields dont exist on the attributeSet or are out of date
+ // check if any of the dataExtension fields dont exist on the attributeSet or are out of date
const deKey =
sharedDataExtensionMap[metadataMap[asKey].storageReferenceID.value];
const asFields = metadataMap[asKey].valueDefinitions;
- if (!fixShared_fieldChange[deKey]) {
+ if (!fixShared_fields[deKey]) {
Util.logger.debug(
` - No changed fields found. Assuming re-deploy with --fixShared flag`
);
return true;
}
- const deFields = Object.values(fixShared_fieldChange[deKey]);
+ const deFields = Object.values(fixShared_fields[deKey]);
return deFields.some((deField) => {
const search = asFields.filter((asf) => asf.name === deField.Name);
if (!search.length) {
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 9215ff409..39a7e5601 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -537,7 +537,7 @@ class DataExtension extends MetadataType {
AttributeSet.client = clientChildBu;
const sharedDeIdsUsedOnBU = await AttributeSet.fixShared_retrieve(
sharedDataExtensionMap,
- DataExtensionField.fixShared_fieldChange
+ DataExtensionField.fixShared_fields
);
if (sharedDeIdsUsedOnBU.length) {
let sharedDataExtensionsKeys = sharedDeIdsUsedOnBU.map(
diff --git a/lib/metadataTypes/DataExtensionField.js b/lib/metadataTypes/DataExtensionField.js
index 4d81e45f1..c2755e073 100644
--- a/lib/metadataTypes/DataExtensionField.js
+++ b/lib/metadataTypes/DataExtensionField.js
@@ -100,6 +100,8 @@ class DataExtensionField extends MetadataType {
*/
static async prepareDeployColumnsOnUpdate(deployColumns, deKey) {
// create list of DE keys that had changes to their fields to be able to use it as a filter in the --fixShared logic
+ this.fixShared_fields ||= {};
+ this.fixShared_fields[deKey] ||= {};
this.fixShared_fieldChange ||= {};
this.fixShared_fieldChange[deKey] ||= {};
@@ -188,6 +190,9 @@ class DataExtensionField extends MetadataType {
changeFound = true;
}
}
+ this.fixShared_fields[deKey][item.Name] = JSON.parse(JSON.stringify(item));
+ this.fixShared_fields[deKey][item.Name].FieldType = itemOld.FieldType;
+
if (!changeFound) {
deployColumns.splice(i, 1);
Util.logger.verbose(`no change - removed field [${deKey}].[${item.Name}]`);
@@ -225,6 +230,7 @@ class DataExtensionField extends MetadataType {
// Field doesn't exist in target, therefore Remove ObjectID if present
delete item.ObjectID;
+ this.fixShared_fields[deKey][item.Name] = JSON.parse(JSON.stringify(item));
this.fixShared_fieldChange[deKey][item.Name] = JSON.parse(JSON.stringify(item));
}
if (Util.isTrue(item.IsPrimaryKey) && Util.isFalse(item.IsRequired)) {
diff --git a/test/mockRoot/deploy/testInstance/testBU/dataExtension/testExisting_dataExtension.dataExtension-meta.json b/test/mockRoot/deploy/testInstance/testBU/dataExtension/testExisting_dataExtension.dataExtension-meta.json
index f5c8c19af..ccd840273 100644
--- a/test/mockRoot/deploy/testInstance/testBU/dataExtension/testExisting_dataExtension.dataExtension-meta.json
+++ b/test/mockRoot/deploy/testInstance/testBU/dataExtension/testExisting_dataExtension.dataExtension-meta.json
@@ -31,6 +31,7 @@
},
{
"Name": "EmailAddress",
+ "Name_new": "Email",
"DefaultValue": "",
"MaxLength": 254,
"IsRequired": true,
diff --git a/test/resources/9999999/dataExtension/update-expected.json b/test/resources/9999999/dataExtension/update-expected.json
index 4de9f5b49..bc10677a2 100644
--- a/test/resources/9999999/dataExtension/update-expected.json
+++ b/test/resources/9999999/dataExtension/update-expected.json
@@ -26,7 +26,7 @@
"FieldType": "Text"
},
{
- "Name": "EmailAddress",
+ "Name": "Email",
"DefaultValue": "",
"MaxLength": 254,
"IsRequired": true,
diff --git a/test/type.dataExtension.test.js b/test/type.dataExtension.test.js
index 17f30a354..15dae6984 100644
--- a/test/type.dataExtension.test.js
+++ b/test/type.dataExtension.test.js
@@ -97,7 +97,7 @@ describe('type: dataExtension', () => {
beforeEach(() => {
testUtils.mockSetup(true);
});
- it('Should create & update a dataExtension', async () => {
+ it('Should create & update a dataExtension including a field rename', async () => {
// WHEN
const deployResult = await handler.deploy('testInstance/testBU', ['dataExtension']);
// THEN
@@ -235,7 +235,6 @@ describe('type: dataExtension', () => {
);
return;
});
- it('Should rename fields');
});
describe('Templating ================', () => {
it('Should create a dataExtension template via retrieveAsTemplate and build it', async () => {
From fbb99635a84b0a4d386fd3a38eb0dc974cf09e67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 17 Aug 2023 17:49:53 +0200
Subject: [PATCH 28/70] #940: simplified logic by no longer checking for
CHANGED fields but simply all fields
---
lib/metadataTypes/AttributeSet.js | 6 ------
lib/metadataTypes/DataExtension.js | 12 ------------
lib/metadataTypes/DataExtensionField.js | 15 ++-------------
3 files changed, 2 insertions(+), 31 deletions(-)
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index ef8bd19d5..575531ee7 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -78,12 +78,6 @@ class AttributeSet extends MetadataType {
const deKey =
sharedDataExtensionMap[metadataMap[asKey].storageReferenceID.value];
const asFields = metadataMap[asKey].valueDefinitions;
- if (!fixShared_fields[deKey]) {
- Util.logger.debug(
- ` - No changed fields found. Assuming re-deploy with --fixShared flag`
- );
- return true;
- }
const deFields = Object.values(fixShared_fields[deKey]);
return deFields.some((deField) => {
const search = asFields.filter((asf) => asf.name === deField.Name);
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 39a7e5601..6e96f463b 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -391,18 +391,6 @@ class DataExtension extends MetadataType {
const sharedDataExtensionsKeys = this.deployedSharedKeys;
this.deployedSharedKeys = null;
- if (
- !sharedDataExtensionsKeys.filter(
- (deKey) =>
- DataExtensionField.fixShared_fieldChange[deKey] &&
- Object.keys(DataExtensionField.fixShared_fieldChange[deKey])?.length
- )
- ) {
- Util.logger.debug(
- ` - No changed fields found. Assuming re-deploy with --fixShared flag`
- );
- return true;
- }
if (Util.OPTIONS.fixShared) {
// select which BUs to run this for
diff --git a/lib/metadataTypes/DataExtensionField.js b/lib/metadataTypes/DataExtensionField.js
index c2755e073..d5da433e8 100644
--- a/lib/metadataTypes/DataExtensionField.js
+++ b/lib/metadataTypes/DataExtensionField.js
@@ -102,8 +102,6 @@ class DataExtensionField extends MetadataType {
// create list of DE keys that had changes to their fields to be able to use it as a filter in the --fixShared logic
this.fixShared_fields ||= {};
this.fixShared_fields[deKey] ||= {};
- this.fixShared_fieldChange ||= {};
- this.fixShared_fieldChange[deKey] ||= {};
// get row count to know which field restrictions apply
let hasData = false;
@@ -190,6 +188,7 @@ class DataExtensionField extends MetadataType {
changeFound = true;
}
}
+ // share fields with fixShared logic
this.fixShared_fields[deKey][item.Name] = JSON.parse(JSON.stringify(item));
this.fixShared_fields[deKey][item.Name].FieldType = itemOld.FieldType;
@@ -198,9 +197,6 @@ class DataExtensionField extends MetadataType {
Util.logger.verbose(`no change - removed field [${deKey}].[${item.Name}]`);
continue;
}
- // track name of changed field
- this.fixShared_fieldChange[deKey][item.Name] = JSON.parse(JSON.stringify(item));
- this.fixShared_fieldChange[deKey][item.Name].FieldType = itemOld.FieldType;
// set the ObjectId for clear identification during update
item.ObjectID = itemOld.ObjectID;
@@ -231,7 +227,6 @@ class DataExtensionField extends MetadataType {
delete item.ObjectID;
this.fixShared_fields[deKey][item.Name] = JSON.parse(JSON.stringify(item));
- this.fixShared_fieldChange[deKey][item.Name] = JSON.parse(JSON.stringify(item));
}
if (Util.isTrue(item.IsPrimaryKey) && Util.isFalse(item.IsRequired)) {
// applicable: with or without data
@@ -247,14 +242,12 @@ class DataExtensionField extends MetadataType {
`- Invalid value for 'IsRequired' of [${deKey}].[${item.Name}]. Found '${item.IsRequired}' instead of 'true'/'false'. Removing field from deploy!`
);
deployColumns.splice(i, 1);
- delete this.fixShared_fieldChange[deKey][item.Name];
}
if (!Util.isTrue(item.IsPrimaryKey) && !Util.isFalse(item.IsPrimaryKey)) {
Util.logger.error(
`- Invalid value for 'IsPrimaryKey' of [${deKey}].[${item.Name}]. Found '${item.IsPrimaryKey}' instead of 'true'/'false'. Removing field from deploy!`
);
deployColumns.splice(i, 1);
- delete this.fixShared_fieldChange[deKey][item.Name];
}
}
@@ -265,11 +258,7 @@ class DataExtensionField extends MetadataType {
}` + deployColumns.map((item) => item.Name).join(', ')
)
);
- // create list of DE keys that had changes to their fields to be able to use it as a filter in the --fixShared logic
- if (!deployColumns.length || !Object.keys(this.fixShared_fieldChange[deKey]).length) {
- // no changed fields found. remove entry from list for easier processing
- delete this.fixShared_fieldChange[deKey];
- }
+
return existingFieldByName;
}
From f6aee7bcc130f23bd0ff322e5f8f6716a670f3c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 18 Aug 2023 15:52:43 +0200
Subject: [PATCH 29/70] #325: add support to retrieve, cache & upsert
dataVerification activities
---
docs/dist/documentation.md | 155 ++++++++++++++-
lib/Deployer.js | 8 +-
lib/MetadataTypeDefinitions.js | 1 +
lib/MetadataTypeInfo.js | 1 +
lib/metadataTypes/Automation.js | 30 ++-
lib/metadataTypes/DataVerification.js | 178 ++++++++++++++++++
lib/metadataTypes/MetadataType.js | 13 +-
.../definitions/Automation.definition.js | 4 +-
.../DataVerification.definition.js | 82 ++++++++
types/mcdev.d.js | 14 ++
10 files changed, 471 insertions(+), 15 deletions(-)
create mode 100644 lib/metadataTypes/DataVerification.js
create mode 100644 lib/metadataTypes/definitions/DataVerification.definition.js
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index af33ea2e1..00eaf1571 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -46,6 +46,9 @@ Source and target business units are also compared before the deployment to appl
Only for Caching No retrieve/upsert is required
as this is a configuration in the EID
+DataVerification ⇐ MetadataType
+DataVerification MetadataType
+
Discovery ⇐ MetadataType
ImportFile MetadataType
@@ -293,6 +296,8 @@ helper for DataExtension.#fixShared_item
AutomationItem : object
+DataVerificationItem : object
+
SDK : Object.<string, AutomationItem>
skipInteraction : object
@@ -2353,6 +2358,126 @@ Retrieves Metadata of Data Extract Type for caching.
**Kind**: static method of [DataExtractType
](#DataExtractType)
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
+
+
+## DataVerification ⇐ [MetadataType
](#MetadataType)
+DataVerification MetadataType
+
+**Kind**: global class
+**Extends**: [MetadataType
](#MetadataType)
+
+* [DataVerification](#DataVerification) ⇐ [MetadataType
](#MetadataType)
+ * [.retrieve(retrieveDir, [_], [__], key)](#DataVerification.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.retrieveForCache([_], [__], [keyArr])](#DataVerification.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.create(metadata)](#DataVerification.create) ⇒ Promise
+ * [.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields)](#DataVerification.postCreateTasks) ⇒ void
+ * [.update(metadata)](#DataVerification.update) ⇒ Promise
+ * [.preDeployTasks(metadata)](#DataVerification.preDeployTasks) ⇒ TYPE.DataVerificationItem
+ * [.postRetrieveTasks(metadata)](#DataVerification.postRetrieveTasks) ⇒ TYPE.DataVerificationItem
+ * [.deleteByKey(key)](#DataVerification.deleteByKey) ⇒ Promise.<boolean>
+
+
+
+### DataVerification.retrieve(retrieveDir, [_], [__], key) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+Retrieves Metadata of Data Verification Activity.
+
+**Kind**: static method of [DataVerification
](#DataVerification)
+**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
+
+| Param | Type | Description |
+| --- | --- | --- |
+| retrieveDir | string
| Directory where retrieved metadata directory will be saved |
+| [_] | void
| unused parameter |
+| [__] | void
| unused parameter |
+| key | string
| customer key of single item to retrieve |
+
+
+
+### DataVerification.retrieveForCache([_], [__], [keyArr]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+Retrieves Metadata of Data Extract Activity for caching
+
+**Kind**: static method of [DataVerification
](#DataVerification)
+**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
+
+| Param | Type | Description |
+| --- | --- | --- |
+| [_] | void
| not used |
+| [__] | void
| not used |
+| [keyArr] | Array.<string>
| customer key of single item to retrieve |
+
+
+
+### DataVerification.create(metadata) ⇒ Promise
+Creates a single Data Extract
+
+**Kind**: static method of [DataVerification
](#DataVerification)
+**Returns**: Promise
- Promise
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadata | TYPE.DataVerificationItem
| a single Data Extract |
+
+
+
+### DataVerification.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) ⇒ void
+helper for [createREST](#MetadataType.createREST)
+
+**Kind**: static method of [DataVerification
](#DataVerification)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadataEntry | TYPE.MetadataTypeItem
| a single metadata Entry |
+| apiResponse | object
| varies depending on the API call |
+| metadataEntryWithAllFields | TYPE.MetadataTypeItem
| like metadataEntry but before non-creatable fields were stripped |
+
+
+
+### DataVerification.update(metadata) ⇒ Promise
+Updates a single Data Extract
+
+**Kind**: static method of [DataVerification
](#DataVerification)
+**Returns**: Promise
- Promise
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadata | TYPE.DataVerificationItem
| a single Data Extract |
+
+
+
+### DataVerification.preDeployTasks(metadata) ⇒ TYPE.DataVerificationItem
+prepares a dataVerification for deployment
+
+**Kind**: static method of [DataVerification
](#DataVerification)
+**Returns**: TYPE.DataVerificationItem
- metadata object
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadata | TYPE.DataVerificationItem
| a single dataVerification activity definition |
+
+
+
+### DataVerification.postRetrieveTasks(metadata) ⇒ TYPE.DataVerificationItem
+parses retrieved Metadata before saving
+
+**Kind**: static method of [DataVerification
](#DataVerification)
+**Returns**: TYPE.DataVerificationItem
- Array with one metadata object and one sql string
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadata | TYPE.DataVerificationItem
| a single dataVerification activity definition |
+
+
+
+### DataVerification.deleteByKey(key) ⇒ Promise.<boolean>
+Delete a metadata item from the specified business unit
+
+**Kind**: static method of [DataVerification
](#DataVerification)
+**Returns**: Promise.<boolean>
- deletion success status
+
+| Param | Type | Description |
+| --- | --- | --- |
+| key | string
| Identifier of item |
+
## Discovery ⇐ [MetadataType
](#MetadataType)
@@ -3382,7 +3507,7 @@ Provides default functionality that can be overwritten by child metadata type cl
* [.getFieldNamesToRetrieve([additionalFields], [isCaching])](#MetadataType.getFieldNamesToRetrieve) ⇒ Array.<string>
* [.deploy(metadata, deployDir, retrieveDir)](#MetadataType.deploy) ⇒ Promise.<TYPE.MetadataTypeMap>
* [.postDeployTasks(upsertResults, originalMetadata, createdUpdated)](#MetadataType.postDeployTasks) ⇒ void
- * [.postCreateTasks(metadataEntry, apiResponse)](#MetadataType.postCreateTasks) ⇒ void
+ * [.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields)](#MetadataType.postCreateTasks) ⇒ void
* [.postUpdateTasks(metadataEntry, apiResponse)](#MetadataType.postUpdateTasks) ⇒ void
* [.postDeployTasks_legacyApi(metadataEntry, apiResponse)](#MetadataType.postDeployTasks_legacyApi) ⇒ Promise.<void>
* [.postRetrieveTasks(metadata, targetDir, [isTemplating])](#MetadataType.postRetrieveTasks) ⇒ TYPE.MetadataTypeItem
@@ -3390,7 +3515,7 @@ Provides default functionality that can be overwritten by child metadata type cl
* [.setFolderId(metadata)](#MetadataType.setFolderId)
* [.retrieve(retrieveDir, [additionalFields], [subTypeArr], [key])](#MetadataType.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveChangelog([additionalFields], [subTypeArr])](#MetadataType.retrieveChangelog) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.retrieveForCache([additionalFields], [subTypeArr], [key])](#MetadataType.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.retrieveForCache([additionalFields], [subTypeArr], [keyArr])](#MetadataType.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveAsTemplate(templateDir, name, templateVariables, [subType])](#MetadataType.retrieveAsTemplate) ⇒ Promise.<TYPE.MetadataTypeItemObj>
* [.retrieveTemplateREST(templateDir, uri, templateVariables, name)](#MetadataType.retrieveTemplateREST) ⇒ Promise.<{metadata: TYPE.MetadataTypeItem, type: string}>
* [.buildTemplate(retrieveDir, templateDir, key, templateVariables)](#MetadataType.buildTemplate) ⇒ Promise.<TYPE.MetadataTypeItemObj>
@@ -3512,7 +3637,7 @@ Gets executed after deployment of metadata type
-### MetadataType.postCreateTasks(metadataEntry, apiResponse) ⇒ void
+### MetadataType.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) ⇒ void
helper for [createREST](#MetadataType.createREST)
**Kind**: static method of [MetadataType
](#MetadataType)
@@ -3521,6 +3646,7 @@ helper for [createREST](#MetadataType.createREST)
| --- | --- | --- |
| metadataEntry | TYPE.MetadataTypeItem
| a single metadata Entry |
| apiResponse | object
| varies depending on the API call |
+| metadataEntryWithAllFields | TYPE.MetadataTypeItem
| like metadataEntry but before non-creatable fields were stripped |
@@ -3613,7 +3739,7 @@ Gets metadata from Marketing Cloud
-### MetadataType.retrieveForCache([additionalFields], [subTypeArr], [key]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+### MetadataType.retrieveForCache([additionalFields], [subTypeArr], [keyArr]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
Gets metadata cache with limited fields and does not store value to disk
**Kind**: static method of [MetadataType
](#MetadataType)
@@ -3623,7 +3749,7 @@ Gets metadata cache with limited fields and does not store value to disk
| --- | --- | --- |
| [additionalFields] | Array.<string>
| Returns specified fields even if their retrieve definition is not set to true |
| [subTypeArr] | Array.<string>
| optionally limit to a single subtype |
-| [key] | string
| customer key of single item to retrieve |
+| [keyArr] | Array.<string>
| customer key of single item to retrieve |
@@ -9035,6 +9161,25 @@ SOAP format
| r__folder_Path | string
| folder path |
| [categoryId] | string
| holds folder ID, replaced with r__folder_Path during retrieve |
+
+
+## DataVerificationItem : object
+**Kind**: global typedef
+**Properties**
+
+| Name | Type | Description |
+| --- | --- | --- |
+| dataVerificationDefinitionId | string
| ID / Key |
+| verificationType | 'IsEqualTo'
\| 'IsLessThan'
\| 'IsGreaterThan'
\| 'IsOutsideRange'
\| 'IsInsideRange'
\| 'IsNotEqualTo'
\| 'IsNotLessThan'
\| 'IsNotGreaterThan'
\| 'IsNotOutsideRange'
\| 'IsNotInsideRange'
| key |
+| value1 | number
| used for all verificationTypes; lower value for IsOutsideRange, IsInsideRange, IsNotOutsideRange, IsNotInsideRange |
+| value2 | number
| only used for IsOutsideRange, IsInsideRange, IsNotOutsideRange, IsNotInsideRange; otherwise set to 0 |
+| shouldStopOnFailure | boolean
| flag to stop automation if verification fails |
+| shouldEmailOnFailure | boolean
| flag to send email if verification fails |
+| notificationEmailAddress | string
| email address to send notification to; empty string if shouldEmailOnFailure=false |
+| notificationEmailMessage | string
| email message to send; empty string if shouldEmailOnFailure=false |
+| createdBy | number
| user id of creator |
+| r__dataExtension_CustomerKey | string
| key of target data extension |
+
## SDK : Object.<string, AutomationItem>
diff --git a/lib/Deployer.js b/lib/Deployer.js
index 5b4d283ff..51ed12328 100644
--- a/lib/Deployer.js
+++ b/lib/Deployer.js
@@ -279,7 +279,13 @@ class Deployer {
MetadataTypeInfo[type].buObject = this.buObject;
Util.logger.info(`Caching dependent Metadata: ${metadataType}`);
Util.logSubtypes(subTypeArr);
- const result = await MetadataTypeInfo[type].retrieveForCache(null, subTypeArr);
+ const result = await MetadataTypeInfo[type].retrieveForCache(
+ null,
+ subTypeArr,
+ MetadataTypeInfo[type].definition.retrieveRequiresKey
+ ? Object.keys(this.metadata[type])
+ : undefined
+ );
cache.setMetadata(type, result.metadata);
}
/** @type {TYPE.MultiMetadataTypeMap} */
diff --git a/lib/MetadataTypeDefinitions.js b/lib/MetadataTypeDefinitions.js
index 477774ef5..014644d34 100644
--- a/lib/MetadataTypeDefinitions.js
+++ b/lib/MetadataTypeDefinitions.js
@@ -15,6 +15,7 @@ const MetadataTypeDefinitions = {
dataExtensionTemplate: require('./metadataTypes/definitions/DataExtensionTemplate.definition'),
dataExtract: require('./metadataTypes/definitions/DataExtract.definition'),
dataExtractType: require('./metadataTypes/definitions/DataExtractType.definition'),
+ dataVerification: require('./metadataTypes/definitions/DataVerification.definition'),
discovery: require('./metadataTypes/definitions/Discovery.definition'),
email: require('./metadataTypes/definitions/Email.definition'),
emailSend: require('./metadataTypes/definitions/EmailSend.definition'),
diff --git a/lib/MetadataTypeInfo.js b/lib/MetadataTypeInfo.js
index 0622a8f84..3c991c6b0 100644
--- a/lib/MetadataTypeInfo.js
+++ b/lib/MetadataTypeInfo.js
@@ -15,6 +15,7 @@ const MetadataTypeInfo = {
dataExtensionTemplate: require('./metadataTypes/DataExtensionTemplate'),
dataExtract: require('./metadataTypes/DataExtract'),
dataExtractType: require('./metadataTypes/DataExtractType'),
+ dataVerification: require('./metadataTypes/DataVerification'),
discovery: require('./metadataTypes/Discovery'),
email: require('./metadataTypes/Email'),
emailSend: require('./metadataTypes/EmailSend'),
diff --git a/lib/metadataTypes/Automation.js b/lib/metadataTypes/Automation.js
index d68105298..ba61d319b 100644
--- a/lib/metadataTypes/Automation.js
+++ b/lib/metadataTypes/Automation.js
@@ -5,6 +5,7 @@ const TYPE = require('../../types/mcdev.d');
const Util = require('../util/util');
const File = require('../util/file');
const Definitions = require('../MetadataTypeDefinitions');
+const DataVerification = require('./DataVerification');
const cache = require('../util/cache');
const pLimit = require('p-limit');
@@ -90,6 +91,7 @@ class Automation extends MetadataType {
// * retrieveDir can be empty when we use it in the context of postDeployTasks
if (retrieveDir) {
+ this.retrieveDir = retrieveDir;
metadataMap = await this.saveResults(metadataMap, retrieveDir, null, null);
Util.logger.info(
`Downloaded: ${this.definition.type} (${Object.keys(metadataMap).length})` +
@@ -363,7 +365,7 @@ class Automation extends MetadataType {
* @param {TYPE.AutomationItem} metadata a single automation
* @returns {TYPE.AutomationItem | void} parsed item
*/
- static postRetrieveTasks(metadata) {
+ static async postRetrieveTasks(metadata) {
// folder
this.setFolderPath(metadata);
// automations are often skipped due to lack of support.
@@ -423,7 +425,13 @@ class Automation extends MetadataType {
} due to missing activityObjectId: ${JSON.stringify(activity)}`
);
// empty if block
- } else if (!this.definition.dependencies.includes(activity.r__type)) {
+ continue;
+ } else if (
+ !this.definition.dependencies.includes(activity.r__type) &&
+ !this.definition.manuallyRetrievedDependencies.includes(
+ activity.r__type
+ )
+ ) {
Util.logger.debug(
` - skipping ${
metadata[this.definition.keyField]
@@ -433,9 +441,25 @@ class Automation extends MetadataType {
activity.r__type
} is not set up as a dependency for ${this.definition.type}`
);
+ continue;
+ }
+ if (activity.r__type === 'dataVerification') {
+ // data verifications can only be retrieved 1-by-1. The get-API does not work without IDs it seems.
+ DataVerification.client = this.client;
+ DataVerification.buObject = this.buObject;
+ DataVerification.properties = this.properties;
+ const dvResult = await DataVerification.retrieve(
+ this.retrieveDir,
+ undefined,
+ undefined,
+ activity.activityObjectId
+ );
+ if (dvResult?.metadata) {
+ cache.mergeMetadata('dataVerification', dvResult.metadata);
+ }
}
// / if managed by cache we can update references to support deployment
- else if (
+ if (
Definitions[activity.r__type]?.['idField'] &&
cache.getCache(this.buObject.mid)[activity.r__type]
) {
diff --git a/lib/metadataTypes/DataVerification.js b/lib/metadataTypes/DataVerification.js
new file mode 100644
index 000000000..aac8a0a13
--- /dev/null
+++ b/lib/metadataTypes/DataVerification.js
@@ -0,0 +1,178 @@
+'use strict';
+
+const TYPE = require('../../types/mcdev.d');
+const MetadataType = require('./MetadataType');
+const Util = require('../util/util');
+const cache = require('../util/cache');
+
+/**
+ * DataVerification MetadataType
+ *
+ * @augments MetadataType
+ */
+class DataVerification extends MetadataType {
+ /**
+ * Retrieves Metadata of Data Verification Activity.
+ *
+ * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
+ * @param {void} [_] unused parameter
+ * @param {void} [__] unused parameter
+ * @param {string} key customer key of single item to retrieve
+ * @returns {Promise.} Promise of metadata
+ */
+ static async retrieve(retrieveDir, _, __, key) {
+ let param = '';
+ if (key?.startsWith('id:')) {
+ param = key.slice(3);
+ } else if (key) {
+ param = key;
+ }
+ if (param === '') {
+ throw new Error('DataVerification can only be retrieved if the ID is known');
+ }
+ try {
+ return await super.retrieveREST(
+ null,
+ '/automation/v1/dataverifications/' + param,
+ null,
+ key
+ );
+ } catch (ex) {
+ if (
+ ex.message === 'Not Found' ||
+ ex.message === 'Request failed with status code 400'
+ ) {
+ if (retrieveDir) {
+ Util.logger.info(
+ `Downloaded: ${this.definition.type} (0)${Util.getKeysString(param)}`
+ );
+ }
+ // if the ID is too short, the system will throw the 400 error
+ return { metadata: {} };
+ } else {
+ throw ex;
+ }
+ }
+ }
+ /**
+ * Retrieves Metadata of Data Extract Activity for caching
+ *
+ * @param {void} [_] not used
+ * @param {void} [__] not used
+ * @param {string[]} [keyArr] customer key of single item to retrieve
+ * @returns {Promise.} Promise of metadata
+ */
+ static async retrieveForCache(_, __, keyArr) {
+ const resultArr = await Promise.all(
+ keyArr.map(async (key) => this.retrieve(null, null, null, key))
+ );
+ const base = resultArr[0];
+ if (resultArr.length > 1) {
+ base.metadata = resultArr.reduce((acc, cur) => {
+ if (cur?.metadata) {
+ acc.metadata = Object.assign(acc.metadata, cur.metadata);
+ }
+ return acc;
+ }).metadata;
+ }
+ return base;
+ }
+
+ /**
+ * Creates a single Data Extract
+ *
+ * @param {TYPE.DataVerificationItem} metadata a single Data Extract
+ * @returns {Promise} Promise
+ */
+ static create(metadata) {
+ return super.createREST(metadata, '/automation/v1/dataverifications/');
+ }
+
+ /**
+ * helper for {@link MetadataType.createREST}
+ *
+ * @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
+ * @param {object} apiResponse varies depending on the API call
+ * @param {TYPE.MetadataTypeItem} metadataEntryWithAllFields like metadataEntry but before non-creatable fields were stripped
+ * @returns {void}
+ */
+ static async postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) {
+ if (!apiResponse?.[this.definition.idField]) {
+ return;
+ }
+ Util.logger.warn(
+ ` - ${this.definition.type} ${
+ metadataEntryWithAllFields?.[this.definition.idField]
+ }: new key ${
+ apiResponse?.[this.definition.idField]
+ } automatically assigned during creation`
+ );
+ metadataEntry[this.definition.idField] = apiResponse?.[this.definition.idField];
+ }
+
+ /**
+ * Updates a single Data Extract
+ *
+ * @param {TYPE.DataVerificationItem} metadata a single Data Extract
+ * @returns {Promise} Promise
+ */
+ static update(metadata) {
+ return super.updateREST(
+ metadata,
+ '/automation/v1/dataverifications/' + metadata.dataVerificationDefinitionId
+ );
+ }
+
+ /**
+ * prepares a dataVerification for deployment
+ *
+ * @param {TYPE.DataVerificationItem} metadata a single dataVerification activity definition
+ * @returns {TYPE.DataVerificationItem} metadata object
+ */
+ static preDeployTasks(metadata) {
+ metadata.targetObjectId = cache.searchForField(
+ 'dataExtension',
+ metadata.r__dataExtension_CustomerKey,
+ 'CustomerKey',
+ 'ObjectID'
+ );
+ delete metadata.r__dataExtension_CustomerKey;
+ return metadata;
+ }
+ /**
+ * parses retrieved Metadata before saving
+ *
+ * @param {TYPE.DataVerificationItem} metadata a single dataVerification activity definition
+ * @returns {TYPE.DataVerificationItem} Array with one metadata object and one sql string
+ */
+ static postRetrieveTasks(metadata) {
+ try {
+ metadata.r__dataExtension_CustomerKey = cache.searchForField(
+ 'dataExtension',
+ metadata.targetObjectId,
+ 'ObjectID',
+ 'CustomerKey'
+ );
+ delete metadata.targetObjectId;
+ } catch (ex) {
+ Util.logger.warn(
+ ` - ${this.definition.type} ${metadata[this.definition.keyField]}: ${ex.message}`
+ );
+ }
+ return metadata;
+ }
+ /**
+ * Delete a metadata item from the specified business unit
+ *
+ * @param {string} key Identifier of item
+ * @returns {Promise.} deletion success status
+ */
+ static deleteByKey(key) {
+ return super.deleteByKeyREST('/automation/v1/dataverifications/' + key, key);
+ }
+}
+
+// Assign definition to static attributes
+DataVerification.definition = require('../MetadataTypeDefinitions').dataVerification;
+
+module.exports = DataVerification;
diff --git a/lib/metadataTypes/MetadataType.js b/lib/metadataTypes/MetadataType.js
index 36f5f52bc..0d98601a8 100644
--- a/lib/metadataTypes/MetadataType.js
+++ b/lib/metadataTypes/MetadataType.js
@@ -139,9 +139,10 @@ class MetadataType {
*
* @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
* @param {object} apiResponse varies depending on the API call
+ * @param {TYPE.MetadataTypeItem} metadataEntryWithAllFields like metadataEntry but before non-creatable fields were stripped
* @returns {void}
*/
- static postCreateTasks(metadataEntry, apiResponse) {}
+ static postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) {}
/**
* helper for {@link MetadataType.updateREST}
@@ -265,11 +266,11 @@ class MetadataType {
*
* @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
* @param {string[]} [subTypeArr] optionally limit to a single subtype
- * @param {string} [key] customer key of single item to retrieve
+ * @param {string[]} [keyArr] customer key of single item to retrieve
* @returns {Promise.} metadata
*/
- static async retrieveForCache(additionalFields, subTypeArr, key) {
- return this.retrieve(null, additionalFields, subTypeArr, key);
+ static async retrieveForCache(additionalFields, subTypeArr, keyArr) {
+ return this.retrieve(null, additionalFields, subTypeArr, keyArr);
}
/**
* Gets metadata cache with limited fields and does not store value to disk
@@ -808,11 +809,12 @@ class MetadataType {
* @returns {Promise. | null} Promise of API response or null in case of an error
*/
static async createREST(metadataEntry, uri) {
+ const metadataClone = JSON.parse(JSON.stringify(metadataEntry));
this.removeNotCreateableFields(metadataEntry);
try {
// set to empty object in case API returned nothing to be able to update it in helper classes
const response = (await this.client.rest.post(uri, metadataEntry)) || {};
- await this.postCreateTasks(metadataEntry, response);
+ await this.postCreateTasks(metadataEntry, response, metadataClone);
Util.logger.info(
` - created ${this.definition.type}: ${
metadataEntry[this.definition.keyField] ||
@@ -1060,6 +1062,7 @@ class MetadataType {
const results = this.parseResponseBody(response, singleRetrieve);
// get extended metadata if applicable
if (this.definition.hasExtended) {
+ Util.logger.debug(' - retrieving extended metadata');
const extended = await this.client.rest.getCollection(
Object.keys(results).map((key) => uri + results[key][this.definition.idField])
);
diff --git a/lib/metadataTypes/definitions/Automation.definition.js b/lib/metadataTypes/definitions/Automation.definition.js
index e34b258ca..f78db4e95 100644
--- a/lib/metadataTypes/definitions/Automation.definition.js
+++ b/lib/metadataTypes/definitions/Automation.definition.js
@@ -11,7 +11,7 @@ module.exports = {
journeyEntryOld: 733,
query: 300,
script: 423,
- verification: 1000,
+ dataVerification: 1000,
wait: 467,
push: 736,
sms: 725,
@@ -23,7 +23,9 @@ module.exports = {
importMobileContact: 726,
},
bodyIteratorField: 'items',
+ manuallyRetrievedDependencies: ['dataVerification'],
dependencies: [
+ 'dataExtension', // for dataVerification
'dataExtract',
'emailSend',
'fileTransfer',
diff --git a/lib/metadataTypes/definitions/DataVerification.definition.js b/lib/metadataTypes/definitions/DataVerification.definition.js
new file mode 100644
index 000000000..ecd4b8969
--- /dev/null
+++ b/lib/metadataTypes/definitions/DataVerification.definition.js
@@ -0,0 +1,82 @@
+module.exports = {
+ bodyIteratorField: 'items',
+ dependencies: ['dataExtension'],
+ hasExtended: false,
+ idField: 'dataVerificationDefinitionId',
+ keyIsFixed: true,
+ keyField: 'dataVerificationDefinitionId',
+ createdDateField: null,
+ createdNameField: 'createdBy',
+ lastmodDateField: null,
+ lastmodNameField: null,
+ nameField: 'dataVerificationDefinitionId',
+ restPagination: false,
+ retrieveRequiresKey: true,
+ maxKeyLength: 36, // confirmed max length
+ type: 'dataVerification',
+ typeDescription: 'Check DataExtension for a row count',
+ typeRetrieveByDefault: true,
+ typeName: 'Automation: Data Verification Activity',
+ fields: {
+ createdBy: {
+ isCreateable: false,
+ isUpdateable: false,
+ retrieving: true,
+ template: false,
+ },
+ dataVerificationDefinitionId: {
+ isCreateable: false, // auto-assigned during creation by SFMC
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ notificationEmailAddress: {
+ isCreateable: true,
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ notificationEmailMessage: {
+ isCreateable: true,
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ shouldEmailOnFailure: {
+ isCreateable: true,
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ shouldStopOnFailure: {
+ isCreateable: true,
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ targetObjectId: {
+ isCreateable: true,
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ value1: {
+ isCreateable: true,
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ value2: {
+ isCreateable: true,
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ verificationType: {
+ isCreateable: true,
+ isUpdateable: true,
+ retrieving: true,
+ template: true,
+ },
+ },
+};
diff --git a/types/mcdev.d.js b/types/mcdev.d.js
index b1dced361..fce52d0c3 100644
--- a/types/mcdev.d.js
+++ b/types/mcdev.d.js
@@ -251,6 +251,20 @@ const SDK = require('sfmc-sdk');
* @property {string} r__folder_Path folder path
* @property {string} [categoryId] holds folder ID, replaced with r__folder_Path during retrieve
*/
+/**
+ * @typedef {object} DataVerificationItem
+ * @property {string} dataVerificationDefinitionId ID / Key
+ * @property {'IsEqualTo'|'IsLessThan'|'IsGreaterThan'|'IsOutsideRange'|'IsInsideRange'|'IsNotEqualTo'|'IsNotLessThan'|'IsNotGreaterThan'|'IsNotOutsideRange'|'IsNotInsideRange'} verificationType key
+ * @property {number} value1 used for all verificationTypes; lower value for IsOutsideRange, IsInsideRange, IsNotOutsideRange, IsNotInsideRange
+ * @property {number} value2 only used for IsOutsideRange, IsInsideRange, IsNotOutsideRange, IsNotInsideRange; otherwise set to 0
+ * @property {boolean} shouldStopOnFailure flag to stop automation if verification fails
+ * @property {boolean} shouldEmailOnFailure flag to send email if verification fails
+ * @property {string} notificationEmailAddress email address to send notification to; empty string if shouldEmailOnFailure=false
+ * @property {string} notificationEmailMessage email message to send; empty string if shouldEmailOnFailure=false
+ * @property {number} createdBy user id of creator
+ * @property {string} r__dataExtension_CustomerKey key of target data extension
+ */
+
/**
* @typedef {Object.} AutomationMap
* @typedef {{metadata:AutomationMap,type:string}} AutomationMapObj
From 141fa350f42bf825b4437fbc2e3742356e9dcf2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Sat, 19 Aug 2023 16:03:31 +0200
Subject: [PATCH 30/70] #0: fix incorrect delete logic for mobileKeyword
---
lib/metadataTypes/MobileKeyword.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/metadataTypes/MobileKeyword.js b/lib/metadataTypes/MobileKeyword.js
index 12b796bc0..61bc9c409 100644
--- a/lib/metadataTypes/MobileKeyword.js
+++ b/lib/metadataTypes/MobileKeyword.js
@@ -501,7 +501,7 @@ class MobileKeyword extends MetadataType {
*/
static async deleteByKey(key) {
// get id from cache
- const { metadata } = await this.retrieveForCache(key);
+ const { metadata } = await this.retrieveForCache(undefined, undefined, key);
if (!metadata[key]) {
Util.logger.error(`Could not find ${this.definition.type} with key ${key}.`);
return false;
From 2cbe93fcb4f8a72bc1f2e234a41c5706a7cf972a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Sat, 19 Aug 2023 16:06:11 +0200
Subject: [PATCH 31/70] #0: fix incorrect delete-tests (array of key passed
instead of single key)
---
test/type.automation.test.js | 8 +++++---
test/type.dataExtract.test.js | 8 +++++---
test/type.fileTransfer.test.js | 8 +++++---
test/type.importFile.test.js | 8 +++++---
test/type.mobileKeyword.test.js | 8 +++++---
test/type.mobileMessage.test.js | 8 +++++---
test/type.query.test.js | 12 +++++++-----
test/type.triggeredSend.test.js | 8 +++++---
8 files changed, 42 insertions(+), 26 deletions(-)
diff --git a/test/type.automation.test.js b/test/type.automation.test.js
index b4643f3fe..3caf3b474 100644
--- a/test/type.automation.test.js
+++ b/test/type.automation.test.js
@@ -653,9 +653,11 @@ describe('type: automation', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey('testInstance/testBU', 'automation', [
- 'testExisting_automation',
- ]);
+ const result = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'automation',
+ 'testExisting_automation'
+ );
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
diff --git a/test/type.dataExtract.test.js b/test/type.dataExtract.test.js
index 6c2b3434e..0f55f5c8e 100644
--- a/test/type.dataExtract.test.js
+++ b/test/type.dataExtract.test.js
@@ -172,9 +172,11 @@ describe('type: dataExtract', () => {
describe('Delete ================', () => {
it('Should NOT delete the item', async () => {
// WHEN
- await handler.deleteByKey('testInstance/testBU', 'dataExtract', [
- 'testExisting_fileTranfer',
- ]);
+ await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'dataExtract',
+ 'testExisting_fileTranfer'
+ );
// THEN
assert.equal(
process.exitCode,
diff --git a/test/type.fileTransfer.test.js b/test/type.fileTransfer.test.js
index 2d33c05b7..9424c893e 100644
--- a/test/type.fileTransfer.test.js
+++ b/test/type.fileTransfer.test.js
@@ -170,9 +170,11 @@ describe('type: fileTransfer', () => {
describe('Delete ================', () => {
it('Should NOT delete the item', async () => {
// WHEN
- await handler.deleteByKey('testInstance/testBU', 'fileTransfer', [
- 'testExisting_fileTranfer',
- ]);
+ await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'fileTransfer',
+ 'testExisting_fileTranfer'
+ );
// THEN
assert.equal(
process.exitCode,
diff --git a/test/type.importFile.test.js b/test/type.importFile.test.js
index 76e9c3642..7b4bc1c3b 100644
--- a/test/type.importFile.test.js
+++ b/test/type.importFile.test.js
@@ -171,9 +171,11 @@ describe('type: importFile', () => {
describe('Delete ================', () => {
it('Should NOT delete the item', async () => {
// WHEN
- await handler.deleteByKey('testInstance/testBU', 'importFile', [
- 'testExisting_fileTranfer',
- ]);
+ await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'importFile',
+ 'testExisting_fileTranfer'
+ );
// THEN
assert.equal(
process.exitCode,
diff --git a/test/type.mobileKeyword.test.js b/test/type.mobileKeyword.test.js
index 9f15adaf0..83d49810d 100644
--- a/test/type.mobileKeyword.test.js
+++ b/test/type.mobileKeyword.test.js
@@ -245,9 +245,11 @@ describe('type: mobileKeyword', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey('testInstance/testBU', 'mobileKeyword', [
- '4912312345678.TESTEXISTING_KEYWORD',
- ]);
+ const result = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'mobileKeyword',
+ '4912312345678.TESTEXISTING_KEYWORD'
+ );
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
diff --git a/test/type.mobileMessage.test.js b/test/type.mobileMessage.test.js
index a77416471..4562434ee 100644
--- a/test/type.mobileMessage.test.js
+++ b/test/type.mobileMessage.test.js
@@ -163,9 +163,11 @@ describe('type: mobileMessage', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey('testInstance/testBU', 'mobileMessage', [
- 'NTIzOjc4OjA',
- ]);
+ const result = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'mobileMessage',
+ 'NTIzOjc4OjA'
+ );
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
diff --git a/test/type.query.test.js b/test/type.query.test.js
index c63420be7..01c3dd7c2 100644
--- a/test/type.query.test.js
+++ b/test/type.query.test.js
@@ -458,7 +458,7 @@ describe('type: query', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 33,
+ 36,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -498,7 +498,7 @@ describe('type: query', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 35,
+ 38,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -656,9 +656,11 @@ describe('type: query', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey('testInstance/testBU', 'query', [
- 'testExisting_query',
- ]);
+ const result = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'query',
+ 'testExisting_query'
+ );
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
diff --git a/test/type.triggeredSend.test.js b/test/type.triggeredSend.test.js
index ee548e28c..a4fd91b4e 100644
--- a/test/type.triggeredSend.test.js
+++ b/test/type.triggeredSend.test.js
@@ -130,9 +130,11 @@ describe('type: triggeredSend', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey('testInstance/testBU', 'triggeredSend', [
- 'testExisting_triggeredSend',
- ]);
+ const result = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'triggeredSend',
+ 'testExisting_triggeredSend'
+ );
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
From c8ef4332241823c2acd558f8ca957df94f7a5644 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Mon, 21 Aug 2023 16:47:55 +0200
Subject: [PATCH 32/70] #325: rename from dataVerification to verification to
match name in SFMC GUI
---
docs/dist/documentation.md | 252 +++++++++---------
lib/MetadataTypeDefinitions.js | 2 +-
lib/MetadataTypeInfo.js | 2 +-
lib/metadataTypes/Automation.js | 14 +-
.../{DataVerification.js => Verification.js} | 26 +-
.../definitions/Automation.definition.js | 6 +-
...finition.js => Verification.definition.js} | 2 +-
types/mcdev.d.js | 2 +-
8 files changed, 153 insertions(+), 153 deletions(-)
rename lib/metadataTypes/{DataVerification.js => Verification.js} (84%)
rename lib/metadataTypes/definitions/{DataVerification.definition.js => Verification.definition.js} (98%)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 00eaf1571..79a3cb8a1 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -46,9 +46,6 @@ Source and target business units are also compared before the deployment to appl
Only for Caching No retrieve/upsert is required
as this is a configuration in the EID
-DataVerification ⇐ MetadataType
-DataVerification MetadataType
-
Discovery ⇐ MetadataType
ImportFile MetadataType
@@ -129,6 +126,9 @@ Provides default functionality that can be overwritten by child metadata type cl
User ⇐ MetadataType
MetadataType
+Verification ⇐ MetadataType
+Verification MetadataType
+
Retriever
Retrieves metadata from a business unit and saves it to the local filesystem.
@@ -296,7 +296,7 @@ helper for DataExtension.#fixShared_item
AutomationItem : object
-DataVerificationItem : object
+VerificationItem : object
SDK : Object.<string, AutomationItem>
@@ -2358,126 +2358,6 @@ Retrieves Metadata of Data Extract Type for caching.
**Kind**: static method of [DataExtractType
](#DataExtractType)
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
-
-
-## DataVerification ⇐ [MetadataType
](#MetadataType)
-DataVerification MetadataType
-
-**Kind**: global class
-**Extends**: [MetadataType
](#MetadataType)
-
-* [DataVerification](#DataVerification) ⇐ [MetadataType
](#MetadataType)
- * [.retrieve(retrieveDir, [_], [__], key)](#DataVerification.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.retrieveForCache([_], [__], [keyArr])](#DataVerification.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.create(metadata)](#DataVerification.create) ⇒ Promise
- * [.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields)](#DataVerification.postCreateTasks) ⇒ void
- * [.update(metadata)](#DataVerification.update) ⇒ Promise
- * [.preDeployTasks(metadata)](#DataVerification.preDeployTasks) ⇒ TYPE.DataVerificationItem
- * [.postRetrieveTasks(metadata)](#DataVerification.postRetrieveTasks) ⇒ TYPE.DataVerificationItem
- * [.deleteByKey(key)](#DataVerification.deleteByKey) ⇒ Promise.<boolean>
-
-
-
-### DataVerification.retrieve(retrieveDir, [_], [__], key) ⇒ Promise.<TYPE.MetadataTypeMapObj>
-Retrieves Metadata of Data Verification Activity.
-
-**Kind**: static method of [DataVerification
](#DataVerification)
-**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
-
-| Param | Type | Description |
-| --- | --- | --- |
-| retrieveDir | string
| Directory where retrieved metadata directory will be saved |
-| [_] | void
| unused parameter |
-| [__] | void
| unused parameter |
-| key | string
| customer key of single item to retrieve |
-
-
-
-### DataVerification.retrieveForCache([_], [__], [keyArr]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
-Retrieves Metadata of Data Extract Activity for caching
-
-**Kind**: static method of [DataVerification
](#DataVerification)
-**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
-
-| Param | Type | Description |
-| --- | --- | --- |
-| [_] | void
| not used |
-| [__] | void
| not used |
-| [keyArr] | Array.<string>
| customer key of single item to retrieve |
-
-
-
-### DataVerification.create(metadata) ⇒ Promise
-Creates a single Data Extract
-
-**Kind**: static method of [DataVerification
](#DataVerification)
-**Returns**: Promise
- Promise
-
-| Param | Type | Description |
-| --- | --- | --- |
-| metadata | TYPE.DataVerificationItem
| a single Data Extract |
-
-
-
-### DataVerification.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) ⇒ void
-helper for [createREST](#MetadataType.createREST)
-
-**Kind**: static method of [DataVerification
](#DataVerification)
-
-| Param | Type | Description |
-| --- | --- | --- |
-| metadataEntry | TYPE.MetadataTypeItem
| a single metadata Entry |
-| apiResponse | object
| varies depending on the API call |
-| metadataEntryWithAllFields | TYPE.MetadataTypeItem
| like metadataEntry but before non-creatable fields were stripped |
-
-
-
-### DataVerification.update(metadata) ⇒ Promise
-Updates a single Data Extract
-
-**Kind**: static method of [DataVerification
](#DataVerification)
-**Returns**: Promise
- Promise
-
-| Param | Type | Description |
-| --- | --- | --- |
-| metadata | TYPE.DataVerificationItem
| a single Data Extract |
-
-
-
-### DataVerification.preDeployTasks(metadata) ⇒ TYPE.DataVerificationItem
-prepares a dataVerification for deployment
-
-**Kind**: static method of [DataVerification
](#DataVerification)
-**Returns**: TYPE.DataVerificationItem
- metadata object
-
-| Param | Type | Description |
-| --- | --- | --- |
-| metadata | TYPE.DataVerificationItem
| a single dataVerification activity definition |
-
-
-
-### DataVerification.postRetrieveTasks(metadata) ⇒ TYPE.DataVerificationItem
-parses retrieved Metadata before saving
-
-**Kind**: static method of [DataVerification
](#DataVerification)
-**Returns**: TYPE.DataVerificationItem
- Array with one metadata object and one sql string
-
-| Param | Type | Description |
-| --- | --- | --- |
-| metadata | TYPE.DataVerificationItem
| a single dataVerification activity definition |
-
-
-
-### DataVerification.deleteByKey(key) ⇒ Promise.<boolean>
-Delete a metadata item from the specified business unit
-
-**Kind**: static method of [DataVerification
](#DataVerification)
-**Returns**: Promise.<boolean>
- deletion success status
-
-| Param | Type | Description |
-| --- | --- | --- |
-| key | string
| Identifier of item |
-
## Discovery ⇐ [MetadataType
](#MetadataType)
@@ -6158,6 +6038,126 @@ manages post retrieve steps
| --- | --- | --- |
| metadata | TYPE.MetadataTypeItem
| a single item |
+
+
+## Verification ⇐ [MetadataType
](#MetadataType)
+Verification MetadataType
+
+**Kind**: global class
+**Extends**: [MetadataType
](#MetadataType)
+
+* [Verification](#Verification) ⇐ [MetadataType
](#MetadataType)
+ * [.retrieve(retrieveDir, [_], [__], key)](#Verification.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.retrieveForCache([_], [__], [keyArr])](#Verification.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.create(metadata)](#Verification.create) ⇒ Promise
+ * [.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields)](#Verification.postCreateTasks) ⇒ void
+ * [.update(metadata)](#Verification.update) ⇒ Promise
+ * [.preDeployTasks(metadata)](#Verification.preDeployTasks) ⇒ TYPE.VerificationItem
+ * [.postRetrieveTasks(metadata)](#Verification.postRetrieveTasks) ⇒ TYPE.VerificationItem
+ * [.deleteByKey(key)](#Verification.deleteByKey) ⇒ Promise.<boolean>
+
+
+
+### Verification.retrieve(retrieveDir, [_], [__], key) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+Retrieves Metadata of Data Verification Activity.
+
+**Kind**: static method of [Verification
](#Verification)
+**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
+
+| Param | Type | Description |
+| --- | --- | --- |
+| retrieveDir | string
| Directory where retrieved metadata directory will be saved |
+| [_] | void
| unused parameter |
+| [__] | void
| unused parameter |
+| key | string
| customer key of single item to retrieve |
+
+
+
+### Verification.retrieveForCache([_], [__], [keyArr]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+Retrieves Metadata of Data Extract Activity for caching
+
+**Kind**: static method of [Verification
](#Verification)
+**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
+
+| Param | Type | Description |
+| --- | --- | --- |
+| [_] | void
| not used |
+| [__] | void
| not used |
+| [keyArr] | Array.<string>
| customer key of single item to retrieve |
+
+
+
+### Verification.create(metadata) ⇒ Promise
+Creates a single Data Extract
+
+**Kind**: static method of [Verification
](#Verification)
+**Returns**: Promise
- Promise
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadata | TYPE.VerificationItem
| a single Data Extract |
+
+
+
+### Verification.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) ⇒ void
+helper for [createREST](#MetadataType.createREST)
+
+**Kind**: static method of [Verification
](#Verification)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadataEntry | TYPE.MetadataTypeItem
| a single metadata Entry |
+| apiResponse | object
| varies depending on the API call |
+| metadataEntryWithAllFields | TYPE.MetadataTypeItem
| like metadataEntry but before non-creatable fields were stripped |
+
+
+
+### Verification.update(metadata) ⇒ Promise
+Updates a single Data Extract
+
+**Kind**: static method of [Verification
](#Verification)
+**Returns**: Promise
- Promise
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadata | TYPE.VerificationItem
| a single Data Extract |
+
+
+
+### Verification.preDeployTasks(metadata) ⇒ TYPE.VerificationItem
+prepares a verification for deployment
+
+**Kind**: static method of [Verification
](#Verification)
+**Returns**: TYPE.VerificationItem
- metadata object
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadata | TYPE.VerificationItem
| a single verification activity definition |
+
+
+
+### Verification.postRetrieveTasks(metadata) ⇒ TYPE.VerificationItem
+parses retrieved Metadata before saving
+
+**Kind**: static method of [Verification
](#Verification)
+**Returns**: TYPE.VerificationItem
- Array with one metadata object and one sql string
+
+| Param | Type | Description |
+| --- | --- | --- |
+| metadata | TYPE.VerificationItem
| a single verification activity definition |
+
+
+
+### Verification.deleteByKey(key) ⇒ Promise.<boolean>
+Delete a metadata item from the specified business unit
+
+**Kind**: static method of [Verification
](#Verification)
+**Returns**: Promise.<boolean>
- deletion success status
+
+| Param | Type | Description |
+| --- | --- | --- |
+| key | string
| Identifier of item |
+
## Retriever
@@ -9161,9 +9161,9 @@ SOAP format
| r__folder_Path | string
| folder path |
| [categoryId] | string
| holds folder ID, replaced with r__folder_Path during retrieve |
-
+
-## DataVerificationItem : object
+## VerificationItem : object
**Kind**: global typedef
**Properties**
diff --git a/lib/MetadataTypeDefinitions.js b/lib/MetadataTypeDefinitions.js
index 014644d34..e6c0e9331 100644
--- a/lib/MetadataTypeDefinitions.js
+++ b/lib/MetadataTypeDefinitions.js
@@ -15,7 +15,6 @@ const MetadataTypeDefinitions = {
dataExtensionTemplate: require('./metadataTypes/definitions/DataExtensionTemplate.definition'),
dataExtract: require('./metadataTypes/definitions/DataExtract.definition'),
dataExtractType: require('./metadataTypes/definitions/DataExtractType.definition'),
- dataVerification: require('./metadataTypes/definitions/DataVerification.definition'),
discovery: require('./metadataTypes/definitions/Discovery.definition'),
email: require('./metadataTypes/definitions/Email.definition'),
emailSend: require('./metadataTypes/definitions/EmailSend.definition'),
@@ -39,6 +38,7 @@ const MetadataTypeDefinitions = {
transactionalSMS: require('./metadataTypes/definitions/TransactionalSMS.definition'),
triggeredSend: require('./metadataTypes/definitions/TriggeredSend.definition'),
user: require('./metadataTypes/definitions/User.definition'),
+ verification: require('./metadataTypes/definitions/Verification.definition'),
};
module.exports = MetadataTypeDefinitions;
diff --git a/lib/MetadataTypeInfo.js b/lib/MetadataTypeInfo.js
index 3c991c6b0..40d7bafce 100644
--- a/lib/MetadataTypeInfo.js
+++ b/lib/MetadataTypeInfo.js
@@ -15,7 +15,6 @@ const MetadataTypeInfo = {
dataExtensionTemplate: require('./metadataTypes/DataExtensionTemplate'),
dataExtract: require('./metadataTypes/DataExtract'),
dataExtractType: require('./metadataTypes/DataExtractType'),
- dataVerification: require('./metadataTypes/DataVerification'),
discovery: require('./metadataTypes/Discovery'),
email: require('./metadataTypes/Email'),
emailSend: require('./metadataTypes/EmailSend'),
@@ -39,6 +38,7 @@ const MetadataTypeInfo = {
transactionalSMS: require('./metadataTypes/TransactionalSMS'),
triggeredSend: require('./metadataTypes/TriggeredSend'),
user: require('./metadataTypes/User'),
+ verification: require('./metadataTypes/Verification'),
};
module.exports = MetadataTypeInfo;
diff --git a/lib/metadataTypes/Automation.js b/lib/metadataTypes/Automation.js
index ba61d319b..21160bdba 100644
--- a/lib/metadataTypes/Automation.js
+++ b/lib/metadataTypes/Automation.js
@@ -5,7 +5,7 @@ const TYPE = require('../../types/mcdev.d');
const Util = require('../util/util');
const File = require('../util/file');
const Definitions = require('../MetadataTypeDefinitions');
-const DataVerification = require('./DataVerification');
+const Verification = require('./Verification');
const cache = require('../util/cache');
const pLimit = require('p-limit');
@@ -443,19 +443,19 @@ class Automation extends MetadataType {
);
continue;
}
- if (activity.r__type === 'dataVerification') {
+ if (activity.r__type === 'verification') {
// data verifications can only be retrieved 1-by-1. The get-API does not work without IDs it seems.
- DataVerification.client = this.client;
- DataVerification.buObject = this.buObject;
- DataVerification.properties = this.properties;
- const dvResult = await DataVerification.retrieve(
+ Verification.client = this.client;
+ Verification.buObject = this.buObject;
+ Verification.properties = this.properties;
+ const dvResult = await Verification.retrieve(
this.retrieveDir,
undefined,
undefined,
activity.activityObjectId
);
if (dvResult?.metadata) {
- cache.mergeMetadata('dataVerification', dvResult.metadata);
+ cache.mergeMetadata('verification', dvResult.metadata);
}
}
// / if managed by cache we can update references to support deployment
diff --git a/lib/metadataTypes/DataVerification.js b/lib/metadataTypes/Verification.js
similarity index 84%
rename from lib/metadataTypes/DataVerification.js
rename to lib/metadataTypes/Verification.js
index aac8a0a13..2345fc1b8 100644
--- a/lib/metadataTypes/DataVerification.js
+++ b/lib/metadataTypes/Verification.js
@@ -6,11 +6,11 @@ const Util = require('../util/util');
const cache = require('../util/cache');
/**
- * DataVerification MetadataType
+ * Verification MetadataType
*
* @augments MetadataType
*/
-class DataVerification extends MetadataType {
+class Verification extends MetadataType {
/**
* Retrieves Metadata of Data Verification Activity.
*
@@ -28,7 +28,7 @@ class DataVerification extends MetadataType {
param = key;
}
if (param === '') {
- throw new Error('DataVerification can only be retrieved if the ID is known');
+ throw new Error('Verification can only be retrieved if the ID is known');
}
try {
return await super.retrieveREST(
@@ -81,7 +81,7 @@ class DataVerification extends MetadataType {
/**
* Creates a single Data Extract
*
- * @param {TYPE.DataVerificationItem} metadata a single Data Extract
+ * @param {TYPE.VerificationItem} metadata a single Data Extract
* @returns {Promise} Promise
*/
static create(metadata) {
@@ -113,21 +113,21 @@ class DataVerification extends MetadataType {
/**
* Updates a single Data Extract
*
- * @param {TYPE.DataVerificationItem} metadata a single Data Extract
+ * @param {TYPE.VerificationItem} metadata a single Data Extract
* @returns {Promise} Promise
*/
static update(metadata) {
return super.updateREST(
metadata,
- '/automation/v1/dataverifications/' + metadata.dataVerificationDefinitionId
+ '/automation/v1/dataverifications/' + metadata.verificationDefinitionId
);
}
/**
- * prepares a dataVerification for deployment
+ * prepares a verification for deployment
*
- * @param {TYPE.DataVerificationItem} metadata a single dataVerification activity definition
- * @returns {TYPE.DataVerificationItem} metadata object
+ * @param {TYPE.VerificationItem} metadata a single verification activity definition
+ * @returns {TYPE.VerificationItem} metadata object
*/
static preDeployTasks(metadata) {
metadata.targetObjectId = cache.searchForField(
@@ -142,8 +142,8 @@ class DataVerification extends MetadataType {
/**
* parses retrieved Metadata before saving
*
- * @param {TYPE.DataVerificationItem} metadata a single dataVerification activity definition
- * @returns {TYPE.DataVerificationItem} Array with one metadata object and one sql string
+ * @param {TYPE.VerificationItem} metadata a single verification activity definition
+ * @returns {TYPE.VerificationItem} Array with one metadata object and one sql string
*/
static postRetrieveTasks(metadata) {
try {
@@ -173,6 +173,6 @@ class DataVerification extends MetadataType {
}
// Assign definition to static attributes
-DataVerification.definition = require('../MetadataTypeDefinitions').dataVerification;
+Verification.definition = require('../MetadataTypeDefinitions').verification;
-module.exports = DataVerification;
+module.exports = Verification;
diff --git a/lib/metadataTypes/definitions/Automation.definition.js b/lib/metadataTypes/definitions/Automation.definition.js
index f78db4e95..06597cd23 100644
--- a/lib/metadataTypes/definitions/Automation.definition.js
+++ b/lib/metadataTypes/definitions/Automation.definition.js
@@ -11,7 +11,7 @@ module.exports = {
journeyEntryOld: 733,
query: 300,
script: 423,
- dataVerification: 1000,
+ verification: 1000,
wait: 467,
push: 736,
sms: 725,
@@ -23,9 +23,9 @@ module.exports = {
importMobileContact: 726,
},
bodyIteratorField: 'items',
- manuallyRetrievedDependencies: ['dataVerification'],
+ manuallyRetrievedDependencies: ['verification'],
dependencies: [
- 'dataExtension', // for dataVerification
+ 'dataExtension', // for verification
'dataExtract',
'emailSend',
'fileTransfer',
diff --git a/lib/metadataTypes/definitions/DataVerification.definition.js b/lib/metadataTypes/definitions/Verification.definition.js
similarity index 98%
rename from lib/metadataTypes/definitions/DataVerification.definition.js
rename to lib/metadataTypes/definitions/Verification.definition.js
index ecd4b8969..a9eb290d5 100644
--- a/lib/metadataTypes/definitions/DataVerification.definition.js
+++ b/lib/metadataTypes/definitions/Verification.definition.js
@@ -13,7 +13,7 @@ module.exports = {
restPagination: false,
retrieveRequiresKey: true,
maxKeyLength: 36, // confirmed max length
- type: 'dataVerification',
+ type: 'verification',
typeDescription: 'Check DataExtension for a row count',
typeRetrieveByDefault: true,
typeName: 'Automation: Data Verification Activity',
diff --git a/types/mcdev.d.js b/types/mcdev.d.js
index fce52d0c3..0367a38f8 100644
--- a/types/mcdev.d.js
+++ b/types/mcdev.d.js
@@ -252,7 +252,7 @@ const SDK = require('sfmc-sdk');
* @property {string} [categoryId] holds folder ID, replaced with r__folder_Path during retrieve
*/
/**
- * @typedef {object} DataVerificationItem
+ * @typedef {object} VerificationItem
* @property {string} dataVerificationDefinitionId ID / Key
* @property {'IsEqualTo'|'IsLessThan'|'IsGreaterThan'|'IsOutsideRange'|'IsInsideRange'|'IsNotEqualTo'|'IsNotLessThan'|'IsNotGreaterThan'|'IsNotOutsideRange'|'IsNotInsideRange'} verificationType key
* @property {number} value1 used for all verificationTypes; lower value for IsOutsideRange, IsInsideRange, IsNotOutsideRange, IsNotInsideRange
From 470d7511d3585dd4e739d0589b62524c04b198ac Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 21 Aug 2023 20:26:57 +0000
Subject: [PATCH 33/70] Bump eslint-plugin-jsdoc from 46.4.6 to 46.5.0
Bumps [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from 46.4.6 to 46.5.0.
- [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases)
- [Changelog](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/.releaserc)
- [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v46.4.6...v46.5.0)
---
updated-dependencies:
- dependency-name: eslint-plugin-jsdoc
dependency-type: direct:development
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
package-lock.json | 14 +++++++-------
package.json | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 4e55a12d5..621e1b89d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -41,7 +41,7 @@
"eslint": "8.47.0",
"eslint-config-prettier": "9.0.0",
"eslint-config-ssjs": "1.1.11",
- "eslint-plugin-jsdoc": "46.4.6",
+ "eslint-plugin-jsdoc": "46.5.0",
"eslint-plugin-mocha": "10.1.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-unicorn": "48.0.0",
@@ -3219,9 +3219,9 @@
}
},
"node_modules/eslint-plugin-jsdoc": {
- "version": "46.4.6",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.6.tgz",
- "integrity": "sha512-z4SWYnJfOqftZI+b3RM9AtWL1vF/sLWE/LlO9yOKDof9yN2+n3zOdOJTGX/pRE/xnPsooOLG2Rq6e4d+XW3lNw==",
+ "version": "46.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.5.0.tgz",
+ "integrity": "sha512-aulXdA4I1dyWpzyS1Nh/GNoS6PavzeucxEapnMR4JUERowWvaEk2Y4A5irpHAcdXtBBHLVe8WIhdXNjoAlGQgA==",
"dev": true,
"dependencies": {
"@es-joy/jsdoccomment": "~0.40.1",
@@ -12515,9 +12515,9 @@
"requires": {}
},
"eslint-plugin-jsdoc": {
- "version": "46.4.6",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.6.tgz",
- "integrity": "sha512-z4SWYnJfOqftZI+b3RM9AtWL1vF/sLWE/LlO9yOKDof9yN2+n3zOdOJTGX/pRE/xnPsooOLG2Rq6e4d+XW3lNw==",
+ "version": "46.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.5.0.tgz",
+ "integrity": "sha512-aulXdA4I1dyWpzyS1Nh/GNoS6PavzeucxEapnMR4JUERowWvaEk2Y4A5irpHAcdXtBBHLVe8WIhdXNjoAlGQgA==",
"dev": true,
"requires": {
"@es-joy/jsdoccomment": "~0.40.1",
diff --git a/package.json b/package.json
index ff158ff70..af4d4948d 100644
--- a/package.json
+++ b/package.json
@@ -87,7 +87,7 @@
"eslint": "8.47.0",
"eslint-config-prettier": "9.0.0",
"eslint-config-ssjs": "1.1.11",
- "eslint-plugin-jsdoc": "46.4.6",
+ "eslint-plugin-jsdoc": "46.5.0",
"eslint-plugin-mocha": "10.1.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-unicorn": "48.0.0",
From 1a8fa4fad647894825c399de57322a2aa1e54c1f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 22 Aug 2023 08:25:58 +0000
Subject: [PATCH 34/70] Bump lint-staged from 14.0.0 to 14.0.1
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 14.0.0 to 14.0.1.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Commits](https://github.com/okonet/lint-staged/compare/v14.0.0...v14.0.1)
---
updated-dependencies:
- dependency-name: lint-staged
dependency-type: direct:development
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
package-lock.json | 14 +++++++-------
package.json | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 621e1b89d..a9cffb152 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -48,7 +48,7 @@
"fast-xml-parser": "4.2.7",
"husky": "8.0.3",
"jsdoc-to-markdown": "8.0.0",
- "lint-staged": "14.0.0",
+ "lint-staged": "14.0.1",
"mocha": "10.2.0",
"mock-fs": "5.2.0",
"npm-check": "6.0.1",
@@ -5737,9 +5737,9 @@
}
},
"node_modules/lint-staged": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.0.tgz",
- "integrity": "sha512-0tLf0pqZYkar/wu3nTctk4rVIG+d7PanDYv4/IQR4qwdqfQkTDziLRFnqMcLuLBTuUqmcLwsHPD2EjQ18d/oaA==",
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.1.tgz",
+ "integrity": "sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==",
"dev": true,
"dependencies": {
"chalk": "5.3.0",
@@ -14292,9 +14292,9 @@
}
},
"lint-staged": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.0.tgz",
- "integrity": "sha512-0tLf0pqZYkar/wu3nTctk4rVIG+d7PanDYv4/IQR4qwdqfQkTDziLRFnqMcLuLBTuUqmcLwsHPD2EjQ18d/oaA==",
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.1.tgz",
+ "integrity": "sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==",
"dev": true,
"requires": {
"chalk": "5.3.0",
diff --git a/package.json b/package.json
index af4d4948d..94eb5c31e 100644
--- a/package.json
+++ b/package.json
@@ -94,7 +94,7 @@
"fast-xml-parser": "4.2.7",
"husky": "8.0.3",
"jsdoc-to-markdown": "8.0.0",
- "lint-staged": "14.0.0",
+ "lint-staged": "14.0.1",
"mocha": "10.2.0",
"mock-fs": "5.2.0",
"npm-check": "6.0.1",
From 50875e1b8725be8598a6bf761548c00ea7edd7be Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 22 Aug 2023 08:28:46 +0000
Subject: [PATCH 35/70] Bump fsevents from 2.3.2 to 2.3.3
Bumps [fsevents](https://github.com/fsevents/fsevents) from 2.3.2 to 2.3.3.
- [Release notes](https://github.com/fsevents/fsevents/releases)
- [Commits](https://github.com/fsevents/fsevents/compare/v2.3.2...v2.3.3)
---
updated-dependencies:
- dependency-name: fsevents
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
package-lock.json | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index a9cffb152..f035492e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"console.table": "0.10.0",
"deep-equal": "2.2.2",
"fs-extra": "11.1.0",
+ "fsevents": "*",
"inquirer": "8.2.6",
"json-to-table": "4.2.1",
"mustache": "4.2.0",
@@ -4085,9 +4086,9 @@
"dev": true
},
"node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"optional": true,
"os": [
@@ -13103,9 +13104,9 @@
"dev": true
},
"fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"optional": true
},
"function-bind": {
From 27504e117d20ec3ed3d3fd6658343d56dbebc9ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Tue, 22 Aug 2023 13:49:07 +0200
Subject: [PATCH 36/70] #325: enable retrieve-all for type verification
via caching automations first
---
lib/metadataTypes/Automation.js | 135 ++++++++----------
lib/metadataTypes/Verification.js | 106 +++++++++++---
.../definitions/Automation.definition.js | 3 +-
3 files changed, 146 insertions(+), 98 deletions(-)
diff --git a/lib/metadataTypes/Automation.js b/lib/metadataTypes/Automation.js
index 21160bdba..ddb6dfe3f 100644
--- a/lib/metadataTypes/Automation.js
+++ b/lib/metadataTypes/Automation.js
@@ -5,7 +5,6 @@ const TYPE = require('../../types/mcdev.d');
const Util = require('../util/util');
const File = require('../util/file');
const Definitions = require('../MetadataTypeDefinitions');
-const Verification = require('./Verification');
const cache = require('../util/cache');
const pLimit = require('p-limit');
@@ -26,65 +25,75 @@ class Automation extends MetadataType {
* @returns {Promise.} Promise of metadata
*/
static async retrieve(retrieveDir, _, __, key) {
- /** @type {TYPE.SoapRequestParams} */
- let requestParams = null;
- if (key) {
- requestParams = {
- filter: {
- leftOperand: 'CustomerKey',
- operator: 'equals',
- rightOperand: key,
- },
- };
- }
- const results = await this.client.soap.retrieveBulk('Program', ['ObjectID'], requestParams);
- if (results.Results?.length && !key) {
- // empty results will come back without "Results" defined
- Util.logger.info(
- Util.getGrayMsg(
- ` - ${results.Results?.length} automation${
- results.Results?.length === 1 ? '' : 's'
- } found. Retrieving details...`
- )
+ let metadataMap;
+ if (!key && this._cachedMetadataMap) {
+ metadataMap = this._cachedMetadataMap;
+ delete this._cachedMetadataMap;
+ } else {
+ /** @type {TYPE.SoapRequestParams} */
+ let requestParams = null;
+ if (key) {
+ requestParams = {
+ filter: {
+ leftOperand: 'CustomerKey',
+ operator: 'equals',
+ rightOperand: key,
+ },
+ };
+ }
+ const results = await this.client.soap.retrieveBulk(
+ 'Program',
+ ['ObjectID'],
+ requestParams
);
- }
- // the API seems to handle 50 concurrent requests nicely
- const rateLimit = pLimit(50);
+ if (results.Results?.length && !key) {
+ // empty results will come back without "Results" defined
+ Util.logger.info(
+ Util.getGrayMsg(
+ ` - ${results.Results?.length} automation${
+ results.Results?.length === 1 ? '' : 's'
+ } found. Retrieving details...`
+ )
+ );
+ }
+ // the API seems to handle 50 concurrent requests nicely
+ const rateLimit = pLimit(50);
- const details = results.Results
- ? await Promise.all(
- results.Results.map(async (item) =>
- rateLimit(async () => {
- try {
- return await this.client.rest.get(
- '/automation/v1/automations/' + item.ObjectID
- );
- } catch (ex) {
+ const details = results.Results
+ ? await Promise.all(
+ results.Results.map(async (item) =>
+ rateLimit(async () => {
try {
- if (ex.message == 'socket hang up') {
- // one more retry; it's a rare case but retrying again should solve the issue gracefully
- return await this.client.rest.get(
- '/automation/v1/automations/' + item.ObjectID
- );
+ return await this.client.rest.get(
+ '/automation/v1/automations/' + item.ObjectID
+ );
+ } catch (ex) {
+ try {
+ if (ex.message == 'socket hang up') {
+ // one more retry; it's a rare case but retrying again should solve the issue gracefully
+ return await this.client.rest.get(
+ '/automation/v1/automations/' + item.ObjectID
+ );
+ }
+ } catch {
+ // no extra action needed, handled below
}
- } catch {
- // no extra action needed, handled below
+ // if we do get here, we should log the error and continue instead of failing to download all automations
+ Util.logger.error(
+ ` ☇ skipping Automation ${item.ObjectID}: ${ex.message} ${ex.code}`
+ );
+ return null;
}
- // if we do get here, we should log the error and continue instead of failing to download all automations
- Util.logger.error(
- ` ☇ skipping Automation ${item.ObjectID}: ${ex.message} ${ex.code}`
- );
- return null;
- }
- })
+ })
+ )
)
- )
- : [];
+ : [];
- // * if retrieving some automations fails, a null element would remain in the details-array for each of them that needs to be filtered to prevent it from causing issues elsewhere
- let metadataMap = this.parseResponseBody({ items: details.filter(Boolean) });
+ // * if retrieving some automations fails, a null element would remain in the details-array for each of them that needs to be filtered to prevent it from causing issues elsewhere
+ metadataMap = this.parseResponseBody({ items: details.filter(Boolean) });
+ }
- if (Object.keys(metadataMap).length) {
+ if (!this._skipNotificationRetrieve && Object.keys(metadataMap).length) {
// attach notification information to each automation that has any
await this.#getAutomationNotificationsREST(metadataMap);
}
@@ -426,12 +435,7 @@ class Automation extends MetadataType {
);
// empty if block
continue;
- } else if (
- !this.definition.dependencies.includes(activity.r__type) &&
- !this.definition.manuallyRetrievedDependencies.includes(
- activity.r__type
- )
- ) {
+ } else if (!this.definition.dependencies.includes(activity.r__type)) {
Util.logger.debug(
` - skipping ${
metadata[this.definition.keyField]
@@ -443,21 +447,6 @@ class Automation extends MetadataType {
);
continue;
}
- if (activity.r__type === 'verification') {
- // data verifications can only be retrieved 1-by-1. The get-API does not work without IDs it seems.
- Verification.client = this.client;
- Verification.buObject = this.buObject;
- Verification.properties = this.properties;
- const dvResult = await Verification.retrieve(
- this.retrieveDir,
- undefined,
- undefined,
- activity.activityObjectId
- );
- if (dvResult?.metadata) {
- cache.mergeMetadata('verification', dvResult.metadata);
- }
- }
// / if managed by cache we can update references to support deployment
if (
Definitions[activity.r__type]?.['idField'] &&
diff --git a/lib/metadataTypes/Verification.js b/lib/metadataTypes/Verification.js
index 2345fc1b8..693f288bd 100644
--- a/lib/metadataTypes/Verification.js
+++ b/lib/metadataTypes/Verification.js
@@ -2,6 +2,7 @@
const TYPE = require('../../types/mcdev.d');
const MetadataType = require('./MetadataType');
+const Automation = require('./Automation');
const Util = require('../util/util');
const cache = require('../util/cache');
@@ -21,38 +22,97 @@ class Verification extends MetadataType {
* @returns {Promise.} Promise of metadata
*/
static async retrieve(retrieveDir, _, __, key) {
- let param = '';
+ let paramArr = [];
if (key?.startsWith('id:')) {
- param = key.slice(3);
+ paramArr = [key.slice(3)];
} else if (key) {
- param = key;
+ paramArr = [key];
}
- if (param === '') {
- throw new Error('Verification can only be retrieved if the ID is known');
+ if (!paramArr.length) {
+ // there is no API endpoint to retrieve all dataVerification items, so we need to retrieve all automations and iterate over their activities
+ Util.logger.info(` - Caching dependent Metadata: automation`);
+ Automation.client = this.client;
+ Automation.buObject = this.buObject;
+ Automation.properties = this.properties;
+ Automation._skipNotificationRetrieve = true;
+ const automationsMapObj = await Automation.retrieve();
+ delete Automation._skipNotificationRetrieve;
+ if (automationsMapObj?.metadata && Object.keys(automationsMapObj?.metadata).length) {
+ if (!key) {
+ // if we are not retrieving a single item, cache the automations for later use during retrieval of automations
+ Automation._cachedMetadataMap = automationsMapObj?.metadata;
+ }
+ // automations found, lets iterate over their activities to find the dataVerification items
+ const dataVerificationIds = [];
+ for (const automation of Object.values(automationsMapObj.metadata)) {
+ if (automation.steps) {
+ for (const step of automation.steps) {
+ for (const activity of step.activities) {
+ if (
+ activity.objectTypeId === 1000 &&
+ activity.activityObjectId &&
+ activity.activityObjectId !==
+ '00000000-0000-0000-0000-000000000000'
+ ) {
+ dataVerificationIds.push(activity.activityObjectId);
+ }
+ }
+ }
+ }
+ }
+ if (dataVerificationIds.length) {
+ paramArr.push(...dataVerificationIds);
+ }
+ }
}
- try {
- return await super.retrieveREST(
- null,
- '/automation/v1/dataverifications/' + param,
- null,
- key
- );
- } catch (ex) {
- if (
- ex.message === 'Not Found' ||
- ex.message === 'Request failed with status code 400'
- ) {
- if (retrieveDir) {
- Util.logger.info(
- `Downloaded: ${this.definition.type} (0)${Util.getKeysString(param)}`
+ const results = {};
+ if (paramArr.length) {
+ if (key) {
+ try {
+ const verification = await super.retrieveREST(
+ null,
+ '/automation/v1/dataverifications/' + paramArr[0],
+ null,
+ key
);
+ const key = Object.values(verification?.metadata)[0]?.[
+ this.definition.keyField
+ ];
+ results[key] = verification?.metadata[key];
+ } catch (ex) {
+ if (
+ ex.message === 'Not Found' ||
+ ex.message === 'Request failed with status code 400'
+ ) {
+ // if the ID is too short, the system will throw the 400 error
+ } else {
+ throw ex;
+ }
}
- // if the ID is too short, the system will throw the 400 error
- return { metadata: {} };
} else {
- throw ex;
+ const uri = '/automation/v1/dataverifications/';
+
+ const verificationArr = await this.client.rest.getCollection(
+ paramArr.map((id) => uri + id)
+ );
+ for (const verification of verificationArr) {
+ const key = verification[this.definition.keyField];
+ results[key] = verification;
+ }
}
}
+ if (retrieveDir) {
+ const savedMetadata = await this.saveResults(results, retrieveDir, null, null);
+ Util.logger.info(
+ `Downloaded: ${this.definition.type} (${Object.keys(savedMetadata).length})` +
+ Util.getKeysString(key)
+ );
+ }
+
+ return {
+ metadata: results,
+ type: this.definition.type,
+ };
}
/**
* Retrieves Metadata of Data Extract Activity for caching
diff --git a/lib/metadataTypes/definitions/Automation.definition.js b/lib/metadataTypes/definitions/Automation.definition.js
index 06597cd23..656bcf659 100644
--- a/lib/metadataTypes/definitions/Automation.definition.js
+++ b/lib/metadataTypes/definitions/Automation.definition.js
@@ -23,9 +23,7 @@ module.exports = {
importMobileContact: 726,
},
bodyIteratorField: 'items',
- manuallyRetrievedDependencies: ['verification'],
dependencies: [
- 'dataExtension', // for verification
'dataExtract',
'emailSend',
'fileTransfer',
@@ -33,6 +31,7 @@ module.exports = {
'importFile',
'query',
'script',
+ 'verification',
],
folderType: 'automation',
hasExtended: false,
From 6960bc7e176fbb7ada5618eb96666f5649affca2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Tue, 22 Aug 2023 15:34:57 +0200
Subject: [PATCH 37/70] #325: avoid SDK's getCollection method as it seems to
have some kind of async issue
---
lib/metadataTypes/Verification.js | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/lib/metadataTypes/Verification.js b/lib/metadataTypes/Verification.js
index 693f288bd..8b8bd2ef3 100644
--- a/lib/metadataTypes/Verification.js
+++ b/lib/metadataTypes/Verification.js
@@ -5,6 +5,7 @@ const MetadataType = require('./MetadataType');
const Automation = require('./Automation');
const Util = require('../util/util');
const cache = require('../util/cache');
+const pLimit = require('p-limit');
/**
* Verification MetadataType
@@ -35,6 +36,7 @@ class Verification extends MetadataType {
Automation.buObject = this.buObject;
Automation.properties = this.properties;
Automation._skipNotificationRetrieve = true;
+ delete Automation._cachedMetadataMap;
const automationsMapObj = await Automation.retrieve();
delete Automation._skipNotificationRetrieve;
if (automationsMapObj?.metadata && Object.keys(automationsMapObj?.metadata).length) {
@@ -90,11 +92,29 @@ class Verification extends MetadataType {
}
}
} else {
+ const rateLimit = pLimit(10);
const uri = '/automation/v1/dataverifications/';
- const verificationArr = await this.client.rest.getCollection(
- paramArr.map((id) => uri + id)
- );
+ const verificationArr = paramArr.length
+ ? await Promise.all(
+ paramArr.map(async (id) =>
+ rateLimit(async () => {
+ try {
+ return await this.client.rest.get(uri + id);
+ } catch (ex) {
+ if (
+ ex.message === 'Not Found' ||
+ ex.message === 'Request failed with status code 400'
+ ) {
+ // if the ID is too short, the system will throw the 400 error
+ } else {
+ throw ex;
+ }
+ }
+ })
+ )
+ )
+ : [];
for (const verification of verificationArr) {
const key = verification[this.definition.keyField];
results[key] = verification;
From a40883690bbabade1c78d5fb7f16fd94cae8e157 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Tue, 22 Aug 2023 16:21:45 +0200
Subject: [PATCH 38/70] #325: bundle verification retrieve logic in generic
retrieveRESTcollection
---
docs/dist/documentation.md | 40 ++++++++++++++++
lib/metadataTypes/MetadataType.js | 46 ++++++++++++++++++
lib/metadataTypes/Verification.js | 78 +++++++++++--------------------
3 files changed, 113 insertions(+), 51 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 79a3cb8a1..7e9ba8905 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -3417,6 +3417,8 @@ Provides default functionality that can be overwritten by child metadata type cl
* [.getSOAPErrorMsg(ex)](#MetadataType.getSOAPErrorMsg) ⇒ string
* [.retrieveSOAP(retrieveDir, [requestParams], [singleRetrieve], [additionalFields])](#MetadataType.retrieveSOAP) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveREST(retrieveDir, uri, [templateVariables], [singleRetrieve])](#MetadataType.retrieveREST) ⇒ Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
+ * [.retrieveRESTcollection(urlArray, [concurrentRequests])](#MetadataType.retrieveRESTcollection) ⇒ Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
+ * [.handleRESTErrors(ex, id)](#MetadataType.handleRESTErrors) ⇒ null
* [.executeREST(uri, key)](#MetadataType.executeREST) ⇒ Promise.<{key:string, response:string}>
* [.executeSOAP([metadataEntry])](#MetadataType.executeSOAP) ⇒ Promise.<{key:string, response:object}>
* [.runDocumentOnRetrieve([singleRetrieve], metadataMap)](#MetadataType.runDocumentOnRetrieve) ⇒ Promise.<void>
@@ -3896,6 +3898,30 @@ Retrieves Metadata for Rest Types
| [templateVariables] | TYPE.TemplateMap
| variables to be replaced in the metadata |
| [singleRetrieve] | string
\| number
| key of single item to filter by |
+
+
+### MetadataType.retrieveRESTcollection(urlArray, [concurrentRequests]) ⇒ Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
+**Kind**: static method of [MetadataType
](#MetadataType)
+**Returns**: Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
- Promise of item map (single item for templated result)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| urlArray | Array.<object>
| {uri: string, id: string} combo of URL and ID/key of metadata |
+| [concurrentRequests] | number
| optionally set a different amount of concurrent requests |
+
+
+
+### MetadataType.handleRESTErrors(ex, id) ⇒ null
+helper for [this.retrieveRESTcollection](this.retrieveRESTcollection)
+
+**Kind**: static method of [MetadataType
](#MetadataType)
+**Returns**: null
- -
+
+| Param | Type | Description |
+| --- | --- | --- |
+| ex | Error
| exception |
+| id | string
| id or key of item |
+
### MetadataType.executeREST(uri, key) ⇒ Promise.<{key:string, response:string}>
@@ -6048,6 +6074,7 @@ Verification MetadataType
* [Verification](#Verification) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], key)](#Verification.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.handleRESTErrors(ex, id)](#Verification.handleRESTErrors) ⇒ null
* [.retrieveForCache([_], [__], [keyArr])](#Verification.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.create(metadata)](#Verification.create) ⇒ Promise
* [.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields)](#Verification.postCreateTasks) ⇒ void
@@ -6071,6 +6098,19 @@ Retrieves Metadata of Data Verification Activity.
| [__] | void
| unused parameter |
| key | string
| customer key of single item to retrieve |
+
+
+### Verification.handleRESTErrors(ex, id) ⇒ null
+helper for [this.retrieveRESTcollection](this.retrieveRESTcollection)
+
+**Kind**: static method of [Verification
](#Verification)
+**Returns**: null
- -
+
+| Param | Type | Description |
+| --- | --- | --- |
+| ex | Error
| exception |
+| id | string
| id or key of item |
+
### Verification.retrieveForCache([_], [__], [keyArr]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
diff --git a/lib/metadataTypes/MetadataType.js b/lib/metadataTypes/MetadataType.js
index 0d98601a8..12a824f61 100644
--- a/lib/metadataTypes/MetadataType.js
+++ b/lib/metadataTypes/MetadataType.js
@@ -1091,6 +1091,52 @@ class MetadataType {
type: this.definition.type,
};
}
+ /**
+ *
+ * @param {object[]} urlArray {uri: string, id: string} combo of URL and ID/key of metadata
+ * @param {number} [concurrentRequests] optionally set a different amount of concurrent requests
+ * @returns {Promise.<{metadata: (TYPE.MetadataTypeMap | TYPE.MetadataTypeItem), type: string}>} Promise of item map (single item for templated result)
+ */
+ static async retrieveRESTcollection(urlArray, concurrentRequests) {
+ const rateLimit = pLimit(concurrentRequests || 10);
+
+ const metadataArr = urlArray.length
+ ? await Promise.all(
+ urlArray.map(async (item) =>
+ rateLimit(async () => {
+ try {
+ return await this.client.rest.get(item.uri);
+ } catch (ex) {
+ return this.handleRESTErrors(ex, item.id);
+ }
+ })
+ )
+ )
+ : [];
+ const results = {};
+ for (const item of metadataArr) {
+ const key = item[this.definition.keyField];
+ results[key] = item;
+ }
+ return {
+ metadata: results,
+ type: this.definition.type,
+ };
+ }
+
+ /**
+ * helper for {@link this.retrieveRESTcollection}
+ *
+ * @param {Error} ex exception
+ * @param {string} id id or key of item
+ * @returns {null} -
+ */
+ static handleRESTErrors(ex, id) {
+ // if the ID is too short, the system will throw the 400 error
+ Util.logger.debug(` ☇ skipping ${this.definition.type} ${id}: ${ex.message} ${ex.code}`);
+
+ return null;
+ }
/**
* Used to execute a query/automation etc.
*
diff --git a/lib/metadataTypes/Verification.js b/lib/metadataTypes/Verification.js
index 8b8bd2ef3..a628e463b 100644
--- a/lib/metadataTypes/Verification.js
+++ b/lib/metadataTypes/Verification.js
@@ -5,7 +5,6 @@ const MetadataType = require('./MetadataType');
const Automation = require('./Automation');
const Util = require('../util/util');
const cache = require('../util/cache');
-const pLimit = require('p-limit');
/**
* Verification MetadataType
@@ -69,56 +68,11 @@ class Verification extends MetadataType {
}
const results = {};
if (paramArr.length) {
- if (key) {
- try {
- const verification = await super.retrieveREST(
- null,
- '/automation/v1/dataverifications/' + paramArr[0],
- null,
- key
- );
- const key = Object.values(verification?.metadata)[0]?.[
- this.definition.keyField
- ];
- results[key] = verification?.metadata[key];
- } catch (ex) {
- if (
- ex.message === 'Not Found' ||
- ex.message === 'Request failed with status code 400'
- ) {
- // if the ID is too short, the system will throw the 400 error
- } else {
- throw ex;
- }
- }
- } else {
- const rateLimit = pLimit(10);
- const uri = '/automation/v1/dataverifications/';
-
- const verificationArr = paramArr.length
- ? await Promise.all(
- paramArr.map(async (id) =>
- rateLimit(async () => {
- try {
- return await this.client.rest.get(uri + id);
- } catch (ex) {
- if (
- ex.message === 'Not Found' ||
- ex.message === 'Request failed with status code 400'
- ) {
- // if the ID is too short, the system will throw the 400 error
- } else {
- throw ex;
- }
- }
- })
- )
- )
- : [];
- for (const verification of verificationArr) {
- const key = verification[this.definition.keyField];
- results[key] = verification;
- }
+ const response = await this.retrieveRESTcollection(
+ paramArr.map((id) => ({ id, uri: '/automation/v1/dataverifications/' + id }))
+ );
+ if (response?.metadata) {
+ Object.assign(results, response.metadata);
}
}
if (retrieveDir) {
@@ -134,6 +88,28 @@ class Verification extends MetadataType {
type: this.definition.type,
};
}
+ /**
+ * helper for {@link this.retrieveRESTcollection}
+ *
+ * @param {Error} ex exception
+ * @param {string} id id or key of item
+ * @returns {null} -
+ */
+ static handleRESTErrors(ex, id) {
+ if (ex.message === 'Not Found' || ex.message === 'Request failed with status code 400') {
+ // if the ID is too short, the system will throw the 400 error
+ Util.logger.debug(
+ ` ☇ skipping ${this.definition.type} ${id}: ${ex.message} ${ex.code}`
+ );
+ } else {
+ // if we do get here, we should log the error and continue instead of failing to download all automations
+ Util.logger.error(
+ ` ☇ skipping ${this.definition.type} ${id}: ${ex.message} ${ex.code}`
+ );
+ }
+ return null;
+ }
+
/**
* Retrieves Metadata of Data Extract Activity for caching
*
From 55a92ee9580f2396181a3323cb88ac1349714cae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Tue, 22 Aug 2023 16:33:48 +0200
Subject: [PATCH 39/70] #325: upgrade Automation class to use new
retrieveRESTcollection()
---
docs/dist/documentation.md | 14 ++++++++
lib/metadataTypes/Automation.js | 63 ++++++++++++++++-----------------
2 files changed, 44 insertions(+), 33 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 7e9ba8905..9c1370795 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -1413,6 +1413,7 @@ Automation MetadataType
* [Automation](#Automation) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], [key])](#Automation.retrieve) ⇒ Promise.<TYPE.AutomationMapObj>
+ * [.handleRESTErrors(ex, id)](#Automation.handleRESTErrors) ⇒ null
* [.retrieveChangelog()](#Automation.retrieveChangelog) ⇒ Promise.<TYPE.AutomationMapObj>
* [.retrieveForCache()](#Automation.retrieveForCache) ⇒ Promise.<TYPE.AutomationMapObj>
* [.retrieveAsTemplate(templateDir, name, templateVariables)](#Automation.retrieveAsTemplate) ⇒ Promise.<TYPE.AutomationItemObj>
@@ -1450,6 +1451,19 @@ Retrieves Metadata of Automation
| [__] | void
| unused parameter |
| [key] | string
| customer key of single item to retrieve |
+
+
+### Automation.handleRESTErrors(ex, id) ⇒ null
+helper for [this.retrieveRESTcollection](this.retrieveRESTcollection)
+
+**Kind**: static method of [Automation
](#Automation)
+**Returns**: null
- -
+
+| Param | Type | Description |
+| --- | --- | --- |
+| ex | Error
| exception |
+| id | string
| id or key of item |
+
### Automation.retrieveChangelog() ⇒ Promise.<TYPE.AutomationMapObj>
diff --git a/lib/metadataTypes/Automation.js b/lib/metadataTypes/Automation.js
index ddb6dfe3f..61926367d 100644
--- a/lib/metadataTypes/Automation.js
+++ b/lib/metadataTypes/Automation.js
@@ -57,40 +57,16 @@ class Automation extends MetadataType {
);
}
// the API seems to handle 50 concurrent requests nicely
- const rateLimit = pLimit(50);
-
- const details = results.Results
- ? await Promise.all(
- results.Results.map(async (item) =>
- rateLimit(async () => {
- try {
- return await this.client.rest.get(
- '/automation/v1/automations/' + item.ObjectID
- );
- } catch (ex) {
- try {
- if (ex.message == 'socket hang up') {
- // one more retry; it's a rare case but retrying again should solve the issue gracefully
- return await this.client.rest.get(
- '/automation/v1/automations/' + item.ObjectID
- );
- }
- } catch {
- // no extra action needed, handled below
- }
- // if we do get here, we should log the error and continue instead of failing to download all automations
- Util.logger.error(
- ` ☇ skipping Automation ${item.ObjectID}: ${ex.message} ${ex.code}`
- );
- return null;
- }
- })
- )
+ const response = results?.Results?.length
+ ? await this.retrieveRESTcollection(
+ results?.Results.map((item) => ({
+ id: item.ObjectID,
+ uri: '/automation/v1/automations/' + item.ObjectID,
+ })),
+ 50
)
- : [];
-
- // * if retrieving some automations fails, a null element would remain in the details-array for each of them that needs to be filtered to prevent it from causing issues elsewhere
- metadataMap = this.parseResponseBody({ items: details.filter(Boolean) });
+ : null;
+ metadataMap = response?.metadata || {};
}
if (!this._skipNotificationRetrieve && Object.keys(metadataMap).length) {
@@ -112,6 +88,27 @@ class Automation extends MetadataType {
return { metadata: metadataMap, type: this.definition.type };
}
+ /**
+ * helper for {@link this.retrieveRESTcollection}
+ *
+ * @param {Error} ex exception
+ * @param {string} id id or key of item
+ * @returns {null} -
+ */
+ static async handleRESTErrors(ex, id) {
+ try {
+ if (ex.message == 'socket hang up') {
+ // one more retry; it's a rare case but retrying again should solve the issue gracefully
+ return await this.client.rest.get('/automation/v1/automations/' + id);
+ }
+ } catch {
+ // no extra action needed, handled below
+ }
+ // if we do get here, we should log the error and continue instead of failing to download all automations
+ Util.logger.error(` ☇ skipping Automation ${id}: ${ex.message} ${ex.code}`);
+ return null;
+ }
+
/**
* helper for {@link Automation.retrieve} to get Automation Notifications
*
From bf8f6f4015a6242e70db139aaded6ec14a71e17f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Tue, 22 Aug 2023 21:25:43 +0200
Subject: [PATCH 40/70] #0: improve logs
---
lib/index.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/index.js b/lib/index.js
index 535fa4f08..d781897a6 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -312,7 +312,8 @@ class Mcdev {
triggeredSend: 'triggeredSendDefinition',
user: 'accountUser',
};
- Util.logger.info(`:: Retrieving ${cred}/${bu}\n`);
+ Util.logger.info('');
+ Util.logger.info(`:: Retrieving ${cred}/${bu}`);
const retrieveTypesArr = [];
if (selectedTypesArr) {
for (const selectedType of Array.isArray(selectedTypesArr)
From 4e62e7f7491fbb06443eb472b2a95287a0e70860 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 23 Aug 2023 10:13:08 +0200
Subject: [PATCH 41/70] #325: revert require-key logic
---
docs/dist/documentation.md | 16 ++++------------
lib/Deployer.js | 8 +-------
lib/metadataTypes/MetadataType.js | 5 ++---
lib/metadataTypes/Verification.js | 19 ++-----------------
.../definitions/Verification.definition.js | 1 -
5 files changed, 9 insertions(+), 40 deletions(-)
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 9c1370795..404c2f588 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -3409,7 +3409,7 @@ Provides default functionality that can be overwritten by child metadata type cl
* [.setFolderId(metadata)](#MetadataType.setFolderId)
* [.retrieve(retrieveDir, [additionalFields], [subTypeArr], [key])](#MetadataType.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveChangelog([additionalFields], [subTypeArr])](#MetadataType.retrieveChangelog) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.retrieveForCache([additionalFields], [subTypeArr], [keyArr])](#MetadataType.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.retrieveForCache([additionalFields], [subTypeArr])](#MetadataType.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveAsTemplate(templateDir, name, templateVariables, [subType])](#MetadataType.retrieveAsTemplate) ⇒ Promise.<TYPE.MetadataTypeItemObj>
* [.retrieveTemplateREST(templateDir, uri, templateVariables, name)](#MetadataType.retrieveTemplateREST) ⇒ Promise.<{metadata: TYPE.MetadataTypeItem, type: string}>
* [.buildTemplate(retrieveDir, templateDir, key, templateVariables)](#MetadataType.buildTemplate) ⇒ Promise.<TYPE.MetadataTypeItemObj>
@@ -3635,7 +3635,7 @@ Gets metadata from Marketing Cloud
-### MetadataType.retrieveForCache([additionalFields], [subTypeArr], [keyArr]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+### MetadataType.retrieveForCache([additionalFields], [subTypeArr]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
Gets metadata cache with limited fields and does not store value to disk
**Kind**: static method of [MetadataType
](#MetadataType)
@@ -3645,7 +3645,6 @@ Gets metadata cache with limited fields and does not store value to disk
| --- | --- | --- |
| [additionalFields] | Array.<string>
| Returns specified fields even if their retrieve definition is not set to true |
| [subTypeArr] | Array.<string>
| optionally limit to a single subtype |
-| [keyArr] | Array.<string>
| customer key of single item to retrieve |
@@ -6089,7 +6088,7 @@ Verification MetadataType
* [Verification](#Verification) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], key)](#Verification.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.handleRESTErrors(ex, id)](#Verification.handleRESTErrors) ⇒ null
- * [.retrieveForCache([_], [__], [keyArr])](#Verification.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.retrieveForCache()](#Verification.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.create(metadata)](#Verification.create) ⇒ Promise
* [.postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields)](#Verification.postCreateTasks) ⇒ void
* [.update(metadata)](#Verification.update) ⇒ Promise
@@ -6127,18 +6126,11 @@ helper for [this.retrieveRESTcollection](this.retrieveRESTcollection)
-### Verification.retrieveForCache([_], [__], [keyArr]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+### Verification.retrieveForCache() ⇒ Promise.<TYPE.MetadataTypeMapObj>
Retrieves Metadata of Data Extract Activity for caching
**Kind**: static method of [Verification
](#Verification)
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
-
-| Param | Type | Description |
-| --- | --- | --- |
-| [_] | void
| not used |
-| [__] | void
| not used |
-| [keyArr] | Array.<string>
| customer key of single item to retrieve |
-
### Verification.create(metadata) ⇒ Promise
diff --git a/lib/Deployer.js b/lib/Deployer.js
index 51ed12328..5b4d283ff 100644
--- a/lib/Deployer.js
+++ b/lib/Deployer.js
@@ -279,13 +279,7 @@ class Deployer {
MetadataTypeInfo[type].buObject = this.buObject;
Util.logger.info(`Caching dependent Metadata: ${metadataType}`);
Util.logSubtypes(subTypeArr);
- const result = await MetadataTypeInfo[type].retrieveForCache(
- null,
- subTypeArr,
- MetadataTypeInfo[type].definition.retrieveRequiresKey
- ? Object.keys(this.metadata[type])
- : undefined
- );
+ const result = await MetadataTypeInfo[type].retrieveForCache(null, subTypeArr);
cache.setMetadata(type, result.metadata);
}
/** @type {TYPE.MultiMetadataTypeMap} */
diff --git a/lib/metadataTypes/MetadataType.js b/lib/metadataTypes/MetadataType.js
index 12a824f61..9b71aac6e 100644
--- a/lib/metadataTypes/MetadataType.js
+++ b/lib/metadataTypes/MetadataType.js
@@ -266,11 +266,10 @@ class MetadataType {
*
* @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
* @param {string[]} [subTypeArr] optionally limit to a single subtype
- * @param {string[]} [keyArr] customer key of single item to retrieve
* @returns {Promise.} metadata
*/
- static async retrieveForCache(additionalFields, subTypeArr, keyArr) {
- return this.retrieve(null, additionalFields, subTypeArr, keyArr);
+ static async retrieveForCache(additionalFields, subTypeArr) {
+ return this.retrieve(null, additionalFields, subTypeArr);
}
/**
* Gets metadata cache with limited fields and does not store value to disk
diff --git a/lib/metadataTypes/Verification.js b/lib/metadataTypes/Verification.js
index a628e463b..c4a75069a 100644
--- a/lib/metadataTypes/Verification.js
+++ b/lib/metadataTypes/Verification.js
@@ -113,25 +113,10 @@ class Verification extends MetadataType {
/**
* Retrieves Metadata of Data Extract Activity for caching
*
- * @param {void} [_] not used
- * @param {void} [__] not used
- * @param {string[]} [keyArr] customer key of single item to retrieve
* @returns {Promise.} Promise of metadata
*/
- static async retrieveForCache(_, __, keyArr) {
- const resultArr = await Promise.all(
- keyArr.map(async (key) => this.retrieve(null, null, null, key))
- );
- const base = resultArr[0];
- if (resultArr.length > 1) {
- base.metadata = resultArr.reduce((acc, cur) => {
- if (cur?.metadata) {
- acc.metadata = Object.assign(acc.metadata, cur.metadata);
- }
- return acc;
- }).metadata;
- }
- return base;
+ static async retrieveForCache() {
+ return this.retrieve();
}
/**
diff --git a/lib/metadataTypes/definitions/Verification.definition.js b/lib/metadataTypes/definitions/Verification.definition.js
index a9eb290d5..468fc9bc4 100644
--- a/lib/metadataTypes/definitions/Verification.definition.js
+++ b/lib/metadataTypes/definitions/Verification.definition.js
@@ -11,7 +11,6 @@ module.exports = {
lastmodNameField: null,
nameField: 'dataVerificationDefinitionId',
restPagination: false,
- retrieveRequiresKey: true,
maxKeyLength: 36, // confirmed max length
type: 'verification',
typeDescription: 'Check DataExtension for a row count',
From 8975371720ece906b05ad29542e21211501f2b15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 23 Aug 2023 10:59:37 +0200
Subject: [PATCH 42/70] #1088: attributeSet cannot find shared data extension
folders
---
.../definitions/AttributeSet.definition.js | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/lib/metadataTypes/definitions/AttributeSet.definition.js b/lib/metadataTypes/definitions/AttributeSet.definition.js
index 22d196ba0..f29abfd0d 100644
--- a/lib/metadataTypes/definitions/AttributeSet.definition.js
+++ b/lib/metadataTypes/definitions/AttributeSet.definition.js
@@ -1,6 +1,15 @@
module.exports = {
bodyIteratorField: 'setDefinition',
- dependencies: ['folder-hidden', 'folder-dataextension', 'dataExtension'], // future may have dependency on Data Extensions
+ dependencies: [
+ 'folder-hidden',
+ 'folder-dataextension',
+ 'folder-salesforcedataextension',
+ 'folder-shared_data',
+ 'folder-shared_dataextension',
+ 'folder-shared_salesforcedataextension',
+ 'folder-synchronizeddataextension',
+ 'dataExtension',
+ ],
hasExtended: false,
idField: 'definitionID',
keyIsFixed: null,
From 17a00e0cd48d316685225fce176a387170c403cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 23 Aug 2023 11:25:10 +0200
Subject: [PATCH 43/70] #1088: switch attributeSet test to looking into custom
attributeSet
---
.../attributeSet/retrieve-expected.json | 738 ++++--------------
...extensionORContentType=hidden-response.xml | 117 +++
test/type.attributeSet.test.js | 2 +-
3 files changed, 263 insertions(+), 594 deletions(-)
create mode 100644 test/resources/9999999/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml
diff --git a/test/resources/9999999/attributeSet/retrieve-expected.json b/test/resources/9999999/attributeSet/retrieve-expected.json
index a81a4fe12..ebcfcb66d 100644
--- a/test/resources/9999999/attributeSet/retrieve-expected.json
+++ b/test/resources/9999999/attributeSet/retrieve-expected.json
@@ -1,746 +1,298 @@
{
- "applicationID": "e25893f9-08f3-480f-8def-7f8ab0583611",
- "applicationKey": "com.exacttarget.mobileconnect",
"attributeCount": 0,
- "canAddValues": false,
- "canChangeValues": false,
- "canModify": false,
- "canRemove": false,
- "createDate": "2017-01-24T06:33:00",
- "createdBy": -1000,
+ "canAddValues": true,
+ "canChangeValues": true,
+ "canModify": true,
+ "canRemove": true,
+ "createDate": "2023-08-11T08:22:00",
+ "createdBy": 700301950,
"dataRetentionProperties": {
"isDeleteAtEndOfRetentionPeriod": false,
"isResetRetentionPeriodOnImport": false,
- "isRowBasedRetention": false
+ "isRowBasedRetention": true,
+ "periodLength": 6,
+ "periodUnitOfMeasure": 5
},
- "definitionKey": "MobileSubscriptions",
+ "definitionKey": "testExisting_dataExtensionShared",
"isCustomObjectBacked": true,
"isEvent": false,
"isHidden": false,
"isReadOnly": false,
"isRoot": false,
- "isSendable": false,
- "isShared": false,
- "isSystemDefined": true,
- "isTestaable": false,
- "localizedDescription": {},
- "name": "MobileConnect Subscriptions",
+ "isSendable": true,
+ "isShared": true,
+ "isSystemDefined": false,
+ "isTestaable": true,
+ "localizedDescription": {
+ "value": "Container for my test emails"
+ },
+ "name": "testExisting_dataExtensionShared",
"parentID": "00000000-0000-0000-0000-000000000000",
- "r__folder_Path": "Data Extensions",
- "relationshipCount": 0,
- "setDefinitionKey": "MobileSubscriptions",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtensionShared",
+ "r__folder_Path": "Shared Items/Shared Data Extensions",
+ "relationshipCount": 1,
+ "relationships": [
+ {
+ "canModify": true,
+ "canRemove": true,
+ "isGroupToSetRelationship": true,
+ "isHidden": false,
+ "isSystemDefined": false,
+ "leftItem": {
+ "cardinality": "One",
+ "r__attributeGroup_definitionKey": "testExisting_attributeGroup",
+ "relationshipType": "AttributeGroup"
+ },
+ "leftRelationshipIDs": [
+ {
+ "type": "int16",
+ "value": "3"
+ }
+ ],
+ "leftRelationshipReferenceType": "CustomerData",
+ "relationshipAttributes": [
+ {
+ "c__rightFullyQualifiedName": "testExisting_dataExtensionShared.ContactKey",
+ "leftAttributeID": "37778523-13f7-e911-a2d8-1402ec938a35",
+ "leftConnectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ }
+ ],
+ "relationshipID": "598b787a-5238-ee11-b85a-48df37d1de8a",
+ "rightItem": {
+ "cardinality": "One",
+ "r__attributeSet_definitionKey": "testExisting_dataExtensionShared",
+ "relationshipType": "AttributeSet"
+ }
+ }
+ ],
+ "sendAttributeStorageName": "ContactKey",
+ "sendContactKeyStorageName": "_SubscriberKey",
+ "setDefinitionKey": "testExisting_dataExtensionShared",
"storageLogicalType": "DataExtension",
- "storageName": "_MobileSubscription",
- "storageObjectIDs": ["2252de3f-31e2-e611-80cc-1402ec7222b4"],
- "storageReferenceID": {
- "type": "guid",
- "value": "7793dc39-31e2-e611-80cc-1402ec7222b4"
- },
+ "storageObjectIDs": ["5b8b787a-5238-ee11-b85a-48df37d1de8a"],
"valueDefinitions": [
{
"baseType": "Numeric",
"connectingID": {
"identifierType": "FullyQualifiedName"
},
- "dataSourceID": 3,
"dataSourceName": {},
"dataType": "LongNumber",
- "definitionID": "3252de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "CreatedBy",
+ "definitionID": "548b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "CustomObjectKey",
"definitionName": {
- "value": "Created By"
+ "value": "Custom Object Key"
},
"description": "",
- "displayOrder": 1,
- "fullyQualifiedName": "MobileConnect Subscriptions.Created By",
+ "fullyQualifiedName": "testExisting_dataExtensionShared.Custom Object Key",
"isHidden": true,
- "isIdentityValue": false,
- "isNullable": true,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "localizedDescription": {
- "value": ""
- },
- "name": "Created By",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3252de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 1,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "a64a3ed9-b8fd-46cc-a10b-1d5fdf074ce6"
- },
- "storageName": "_CreatedBy",
- "valueDefinitionID": "3252de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "CreatedBy"
- },
- {
- "baseType": "Date",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "Date",
- "defaultValue": "GETDATE()",
- "definitionID": "3352de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "CreatedDate",
- "definitionName": {
- "value": "Created Date"
- },
- "description": "",
- "displayOrder": 2,
- "fullyQualifiedName": "MobileConnect Subscriptions.Created Date",
- "isHidden": false,
- "isIdentityValue": false,
+ "isIdentityValue": true,
"isNullable": false,
"isPrimaryKey": false,
"isReadOnly": true,
"isSystemDefined": true,
- "isUpdateable": false,
+ "isUpdateable": true,
"localizedDescription": {
"value": ""
},
- "name": "Created Date",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3352de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 2,
+ "name": "Custom Object Key",
"parentType": "Set",
"setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "dfc3f6fb-a250-4ef8-93ed-bb079ced468d"
+ "value": "testExisting_dataExtensionShared"
},
- "storageName": "_CreatedDate",
- "valueDefinitionID": "3352de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "CreatedDate"
+ "storageName": "_CustomObjectKey",
+ "valueDefinitionID": "548b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "CustomObjectKey"
},
{
"baseType": "Text",
"connectingID": {
"identifierType": "FullyQualifiedName"
},
- "dataSourceID": 3,
"dataSourceName": {},
"dataType": "Text",
- "definitionID": "3f52de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "SubscriptionDefinitionID",
- "definitionName": {
- "value": "Keyword"
- },
- "description": "",
- "displayOrder": 3,
- "fullyQualifiedName": "MobileConnect Subscriptions.Keyword",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": false,
- "isPrimaryKey": true,
- "isReadOnly": false,
- "isSystemDefined": true,
- "isUpdateable": false,
- "length": 200,
- "localizedDescription": {
- "value": ""
- },
- "name": "Keyword",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3f52de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 3,
- "parentType": "Set",
- "restrictionLookupListID": 7,
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "c13ab46d-6e65-475a-990d-291bd43e5063"
- },
- "storageName": "_SubscriptionDefinitionID",
- "valueDefinitionID": "3f52de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "SubscriptionDefinitionID"
- },
- {
- "baseType": "Text",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "Phone",
- "definitionID": "3452de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "MobileNumber",
- "definitionName": {
- "value": "Mobile Number"
- },
- "description": "",
- "displayOrder": 4,
- "fullyQualifiedName": "MobileConnect Subscriptions.Mobile Number",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": false,
- "isPrimaryKey": true,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "length": 15,
- "localizedDescription": {
- "value": ""
- },
- "name": "Mobile Number",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3452de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 4,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "ead8a6d2-bc6c-4768-a6e3-c3cc749bfc1d"
- },
- "storageName": "_MobileNumber",
- "valueDefinitionID": "3452de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "MobileNumber"
- },
- {
- "baseType": "Numeric",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "LongNumber",
- "definitionID": "53dd5f89-bca1-ed11-b852-48df37d1df5b",
- "definitionKey": "MobileSubscriptionID",
- "definitionName": {
- "value": "Mobile Subscription ID"
- },
- "description": "",
- "displayOrder": 5,
- "fullyQualifiedName": "MobileConnect Subscriptions.Mobile Subscription ID",
- "isHidden": true,
- "isIdentityValue": true,
- "isNullable": false,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "localizedDescription": {
- "value": ""
- },
- "name": "Mobile Subscription ID",
- "ordinal": 5,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageName": "_MobileSubscriptionID",
- "valueDefinitionID": "53dd5f89-bca1-ed11-b852-48df37d1df5b",
- "valueDefinitionKey": "MobileSubscriptionID"
- },
- {
- "baseType": "Numeric",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "LongNumber",
- "definitionID": "3552de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "ModifiedBy",
- "definitionName": {
- "value": "Modified By"
- },
- "description": "",
- "displayOrder": 6,
- "fullyQualifiedName": "MobileConnect Subscriptions.Modified By",
- "isHidden": true,
- "isIdentityValue": false,
- "isNullable": true,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "localizedDescription": {
- "value": ""
- },
- "name": "Modified By",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3552de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 6,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "30d7ec39-85d1-46dc-9888-771f11ffe10d"
- },
- "storageName": "_ModifiedBy",
- "valueDefinitionID": "3552de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "ModifiedBy"
- },
- {
- "baseType": "Date",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "Date",
- "defaultValue": "GETDATE()",
- "definitionID": "3652de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "ModifiedDate",
- "definitionName": {
- "value": "Modified Date"
- },
- "description": "",
- "displayOrder": 7,
- "fullyQualifiedName": "MobileConnect Subscriptions.Modified Date",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": false,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "localizedDescription": {
- "value": ""
- },
- "name": "Modified Date",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3652de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 7,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "b68155cc-e483-4949-82f9-fb47cbd59764"
- },
- "storageName": "_ModifiedDate",
- "valueDefinitionID": "3652de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "ModifiedDate"
- },
- {
- "baseType": "Date",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "Date",
- "definitionID": "3752de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "OptInDate",
+ "definitionID": "588b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "FirstName",
"definitionName": {
- "value": "Opt In Date"
+ "value": "FirstName"
},
"description": "",
- "displayOrder": 8,
- "fullyQualifiedName": "MobileConnect Subscriptions.Opt In Date",
+ "displayOrder": 0,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.FirstName",
"isHidden": false,
"isIdentityValue": false,
"isNullable": true,
"isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "localizedDescription": {
- "value": ""
- },
- "name": "Opt In Date",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3752de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 8,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "8da557ee-7ba7-44f4-99ba-0681cbeb1ba1"
- },
- "storageName": "_OptInDate",
- "valueDefinitionID": "3752de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "OptInDate"
- },
- {
- "baseType": "Numeric",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "Byte",
- "definitionID": "3852de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "OptInMethodID",
- "definitionName": {
- "value": "Opt In Method"
- },
- "description": "",
- "displayOrder": 9,
- "fullyQualifiedName": "MobileConnect Subscriptions.Opt In Method",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": true,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "localizedDescription": {
- "value": ""
- },
- "name": "Opt In Method",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3852de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 9,
- "parentType": "Set",
- "restrictionLookupListID": 2,
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "da2713ab-a802-4cd6-9e05-0a7444d62388"
- },
- "storageName": "_OptInMethodID",
- "valueDefinitionID": "3852de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "OptInMethodID"
- },
- {
- "baseType": "Numeric",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "Byte",
- "definitionID": "3952de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "OptInStatusID",
- "definitionName": {
- "value": "Opt In Status"
- },
- "description": "",
- "displayOrder": 10,
- "fullyQualifiedName": "MobileConnect Subscriptions.Opt In Status",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": false,
- "isPrimaryKey": false,
"isReadOnly": false,
- "isSystemDefined": true,
- "isUpdateable": false,
- "localizedDescription": {
- "value": ""
- },
- "name": "Opt In Status",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3952de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 10,
- "parentType": "Set",
- "restrictionLookupListID": 1,
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "c733b80d-2ed5-4fb6-94a3-9c996cbae558"
- },
- "storageName": "_OptInStatusID",
- "valueDefinitionID": "3952de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "OptInStatusID"
- },
- {
- "baseType": "Date",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "Date",
- "definitionID": "3a52de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "OptOutDate",
- "definitionName": {
- "value": "Opt Out Date"
- },
- "description": "",
- "displayOrder": 11,
- "fullyQualifiedName": "MobileConnect Subscriptions.Opt Out Date",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": true,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "localizedDescription": {
- "value": ""
- },
- "name": "Opt Out Date",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "3a52de3f-31e2-e611-80cc-1402ec7222b4"
- },
- "ordinal": 11,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "MobileConnect Subscriptions"
- },
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "27c3ccec-47ad-4578-9051-a41f85178049"
- },
- "storageName": "_OptOutDate",
- "valueDefinitionID": "3a52de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "OptOutDate"
- },
- {
- "baseType": "Numeric",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceID": 3,
- "dataSourceName": {},
- "dataType": "Byte",
- "definitionID": "3b52de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "OptOutMethodID",
- "definitionName": {
- "value": "Opt Out Method"
- },
- "description": "",
- "displayOrder": 12,
- "fullyQualifiedName": "MobileConnect Subscriptions.Opt Out Method",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": true,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 50,
"localizedDescription": {
"value": ""
},
- "name": "Opt Out Method",
+ "name": "FirstName",
"obfuscationProperties": {
"maskType": "None",
"maskTypeID": 0,
"storageType": "Plain",
"storageTypeID": 1,
- "valueDefinitionID": "3b52de3f-31e2-e611-80cc-1402ec7222b4"
+ "valueDefinitionID": "588b787a-5238-ee11-b85a-48df37d1de8a"
},
- "ordinal": 12,
+ "ordinal": 0,
"parentType": "Set",
- "restrictionLookupListID": 4,
"setDefinitionName": {
- "value": "MobileConnect Subscriptions"
+ "value": "testExisting_dataExtensionShared"
},
"storageFieldReferenceID": {
"type": "guid",
- "value": "089b96fc-bfc6-402e-a481-1e18d3e18a8d"
+ "value": "391bfc9e-ea85-4610-a24b-d8400a36cdfc"
},
- "storageName": "_OptOutMethodID",
- "valueDefinitionID": "3b52de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "OptOutMethodID"
+ "storageName": "FirstName",
+ "valueDefinitionID": "588b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "FirstName"
},
{
- "baseType": "Numeric",
+ "baseType": "Text",
"connectingID": {
"identifierType": "FullyQualifiedName"
},
- "dataSourceID": 3,
"dataSourceName": {},
- "dataType": "Byte",
- "definitionID": "3c52de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "OptOutStatusID",
+ "dataType": "Text",
+ "definitionID": "578b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "LastName",
"definitionName": {
- "value": "Opt Out Status"
+ "value": "LastName"
},
"description": "",
- "displayOrder": 13,
- "fullyQualifiedName": "MobileConnect Subscriptions.Opt Out Status",
+ "displayOrder": 1,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.LastName",
"isHidden": false,
"isIdentityValue": false,
"isNullable": true,
"isPrimaryKey": false,
"isReadOnly": false,
- "isSystemDefined": true,
- "isUpdateable": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 55,
"localizedDescription": {
"value": ""
},
- "name": "Opt Out Status",
+ "name": "LastName",
"obfuscationProperties": {
"maskType": "None",
"maskTypeID": 0,
"storageType": "Plain",
"storageTypeID": 1,
- "valueDefinitionID": "3c52de3f-31e2-e611-80cc-1402ec7222b4"
+ "valueDefinitionID": "578b787a-5238-ee11-b85a-48df37d1de8a"
},
- "ordinal": 13,
+ "ordinal": 1,
"parentType": "Set",
- "restrictionLookupListID": 3,
"setDefinitionName": {
- "value": "MobileConnect Subscriptions"
+ "value": "testExisting_dataExtensionShared"
},
"storageFieldReferenceID": {
"type": "guid",
- "value": "67194503-acd8-4c1c-b042-9dfb3f3ebd44"
+ "value": "3f80ba1f-f957-400f-88cb-a9303491026d"
},
- "storageName": "_OptOutStatusID",
- "valueDefinitionID": "3c52de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "OptOutStatusID"
+ "storageName": "LastName",
+ "valueDefinitionID": "578b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "LastName"
},
{
- "baseType": "Numeric",
+ "baseType": "Text",
"connectingID": {
"identifierType": "FullyQualifiedName"
},
- "dataSourceID": 3,
"dataSourceName": {},
- "dataType": "Byte",
- "definitionID": "3d52de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "Source",
+ "dataType": "EmailAddress",
+ "definitionID": "568b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "EmailAddress",
"definitionName": {
- "value": "Source"
+ "value": "EmailAddress"
},
"description": "",
- "displayOrder": 14,
- "fullyQualifiedName": "MobileConnect Subscriptions.Source",
+ "displayOrder": 2,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.EmailAddress",
"isHidden": false,
"isIdentityValue": false,
- "isNullable": true,
+ "isNullable": false,
"isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
+ "isReadOnly": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 254,
"localizedDescription": {
"value": ""
},
- "name": "Source",
+ "name": "EmailAddress",
"obfuscationProperties": {
"maskType": "None",
"maskTypeID": 0,
"storageType": "Plain",
"storageTypeID": 1,
- "valueDefinitionID": "3d52de3f-31e2-e611-80cc-1402ec7222b4"
+ "valueDefinitionID": "568b787a-5238-ee11-b85a-48df37d1de8a"
},
- "ordinal": 14,
+ "ordinal": 2,
"parentType": "Set",
- "restrictionLookupListID": 5,
"setDefinitionName": {
- "value": "MobileConnect Subscriptions"
+ "value": "testExisting_dataExtensionShared"
},
"storageFieldReferenceID": {
"type": "guid",
- "value": "2e903257-43e8-4a7b-8ed4-757ca772ddbb"
+ "value": "41b9575b-da06-41ed-8551-f76868451a51"
},
- "storageName": "_Source",
- "valueDefinitionID": "3d52de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "Source"
+ "storageName": "EmailAddress",
+ "valueDefinitionID": "568b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "EmailAddress"
},
{
"baseType": "Text",
"connectingID": {
"identifierType": "FullyQualifiedName"
},
- "dataSourceID": 3,
"dataSourceName": {},
"dataType": "Text",
- "definitionID": "3e52de3f-31e2-e611-80cc-1402ec7222b4",
- "definitionKey": "SourceObjectID",
+ "definitionID": "558b787a-5238-ee11-b85a-48df37d1de8a",
+ "definitionKey": "ContactKey",
"definitionName": {
- "value": "Source Object ID"
+ "value": "ContactKey"
},
"description": "",
- "displayOrder": 15,
- "fullyQualifiedName": "MobileConnect Subscriptions.Source Object ID",
+ "displayOrder": 4,
+ "fullyQualifiedName": "testExisting_dataExtensionShared.ContactKey",
"isHidden": false,
"isIdentityValue": false,
- "isNullable": true,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "length": 200,
+ "isNullable": false,
+ "isPrimaryKey": true,
+ "isReadOnly": false,
+ "isSystemDefined": false,
+ "isUpdateable": true,
+ "length": 50,
"localizedDescription": {
"value": ""
},
- "name": "Source Object ID",
+ "name": "ContactKey",
"obfuscationProperties": {
"maskType": "None",
"maskTypeID": 0,
"storageType": "Plain",
"storageTypeID": 1,
- "valueDefinitionID": "3e52de3f-31e2-e611-80cc-1402ec7222b4"
+ "valueDefinitionID": "558b787a-5238-ee11-b85a-48df37d1de8a"
},
- "ordinal": 15,
+ "ordinal": 4,
"parentType": "Set",
"setDefinitionName": {
- "value": "MobileConnect Subscriptions"
+ "value": "testExisting_dataExtensionShared"
},
"storageFieldReferenceID": {
"type": "guid",
- "value": "1d4f26f5-ec91-46de-9fc1-d819832f07e7"
+ "value": "49d0db37-dff0-49d9-9d82-eb29b345f238"
},
- "storageName": "_SourceObjectId",
- "valueDefinitionID": "3e52de3f-31e2-e611-80cc-1402ec7222b4",
- "valueDefinitionKey": "SourceObjectID"
+ "storageName": "ContactKey",
+ "valueDefinitionID": "558b787a-5238-ee11-b85a-48df37d1de8a",
+ "valueDefinitionKey": "ContactKey"
}
]
}
diff --git a/test/resources/9999999/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml b/test/resources/9999999/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml
new file mode 100644
index 000000000..d51b42687
--- /dev/null
+++ b/test/resources/9999999/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml
@@ -0,0 +1,117 @@
+
+
+
+ RetrieveResponse
+ urn:uuid:f36f3303-3b5a-4641-8109-b26447634d91
+ urn:uuid:33983968-28c4-4379-bb5f-f80ae32eb988
+ http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
+
+
+ 2022-04-19T20:03:41Z
+ 2022-04-19T20:08:41Z
+
+
+
+
+
+ OK
+ 02cd5ccb-8f84-4651-826f-71169eeecf05
+
+
+ 9999999
+
+
+ 2016-07-22T11:52:19.6
+ 2016-07-22T11:52:19.6
+ 2
+
+ dataextension_default
+
+
+ 0
+
+
+ Data Extensions
+
+ dataextension
+ true
+ false
+ true
+
+
+
+ 9999999
+
+
+ 2017-02-08T10:19:37.123
+ 2017-02-08T10:19:37.123
+ 386
+
+
+
+
+ 2
+
+ dataextension_default
+
+ Einstein
+
+ dataextension
+ true
+ true
+ true
+
+
+
+ 1111111
+
+
+ 2016-07-22T11:52:19.603
+ 2016-07-22T11:52:19.603
+ 89356
+
+ shared_dataextension_default
+
+
+ 89344
+
+ shared_data_default
+
+ Shared Data Extensions
+
+ shared_dataextension
+ true
+ false
+ true
+
+
+
+ 1111111
+
+
+ 2016-07-22T11:52:18.73
+ 2016-07-22T11:52:19.603
+ 89344
+
+ shared_data_default
+
+
+ 0
+
+
+ Shared Items
+
+ shared_data
+ true
+ false
+ false
+
+
+
+
+
diff --git a/test/type.attributeSet.test.js b/test/type.attributeSet.test.js
index a894b7f09..2a55fb9ce 100644
--- a/test/type.attributeSet.test.js
+++ b/test/type.attributeSet.test.js
@@ -38,7 +38,7 @@ describe('type: attributeSet', () => {
);
assert.deepEqual(
- await testUtils.getActualJson('MobileSubscriptions', 'attributeSet'),
+ await testUtils.getActualJson('testExisting_dataExtensionShared', 'attributeSet'),
await testUtils.getExpectedJson('9999999', 'attributeSet', 'retrieve'),
'returned metadata was not equal expected'
From f363b65b5142a40e8f724c3b722d7e9d4e6aaf06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 23 Aug 2023 12:03:02 +0200
Subject: [PATCH 44/70] #1088: clean up field list of attributeSet
---
.../definitions/AttributeSet.definition.js | 52 +++++--
.../attributeSet/retrieve-expected.json | 136 +-----------------
2 files changed, 42 insertions(+), 146 deletions(-)
diff --git a/lib/metadataTypes/definitions/AttributeSet.definition.js b/lib/metadataTypes/definitions/AttributeSet.definition.js
index f29abfd0d..4c2dcbea8 100644
--- a/lib/metadataTypes/definitions/AttributeSet.definition.js
+++ b/lib/metadataTypes/definitions/AttributeSet.definition.js
@@ -153,14 +153,14 @@ module.exports = {
template: false,
},
'definitionName.value': {
- // equal to 'name'; auto-populated by preDeployTasks
+ // equal to 'name'
isCreateable: true,
isUpdateable: true,
retrieving: false,
template: false,
},
fullyQualifiedName: {
- // equal to 'name'; auto-populated by preDeployTasks
+ // equal to 'name'
isCreateable: true,
isUpdateable: true,
retrieving: false,
@@ -617,9 +617,10 @@ module.exports = {
template: null,
},
'valueDefinitions[].baseType': {
+ // "Numeric", "Text", ... valueDefinitions[].dataType is more relevant
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].customerDataID': {
@@ -628,6 +629,12 @@ module.exports = {
retrieving: true,
template: null,
},
+ 'valueDefinitions[].connectingID': {
+ isCreateable: null,
+ isUpdateable: null,
+ retrieving: false,
+ template: null,
+ },
'valueDefinitions[].dataSourceID': {
isCreateable: null,
isUpdateable: null,
@@ -637,7 +644,7 @@ module.exports = {
'valueDefinitions[].dataSourceName': {
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].dataType': {
@@ -664,10 +671,11 @@ module.exports = {
retrieving: true,
template: null,
},
- 'valueDefinitions[].definitionName.value': {
+ 'valueDefinitions[].definitionName': {
+ // equal to valueDefinitions[].name
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].description': {
@@ -677,15 +685,17 @@ module.exports = {
template: null,
},
'valueDefinitions[].displayOrder': {
+ // merely a numeric counter; equal to valueDefinitions[].ordinal; not given for isHidden:true entries
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].fullyQualifiedName': {
+ // dataExtension name + field name
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].identifierType': {
@@ -742,10 +752,11 @@ module.exports = {
retrieving: true,
template: null,
},
- 'valueDefinitions[].localizedDescription.value': {
+ 'valueDefinitions[].localizedDescription': {
+ // always equal to { value: "" }
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].name': {
@@ -754,6 +765,13 @@ module.exports = {
retrieving: true,
template: null,
},
+ 'valueDefinitions[].obfuscationProperties': {
+ // might become relevant when fields are encrypted but for most cases we should simply skip it
+ isCreateable: null,
+ isUpdateable: null,
+ retrieving: false,
+ template: null,
+ },
'valueDefinitions[].obfuscationProperties.maskType': {
isCreateable: null,
isUpdateable: null,
@@ -785,9 +803,10 @@ module.exports = {
template: null,
},
'valueDefinitions[].ordinal': {
+ // merely a numeric counter; equal to valueDefinitions[].displayOrder; not given for isHidden:true entries
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].parentDefinition': {
@@ -803,9 +822,10 @@ module.exports = {
template: null,
},
'valueDefinitions[].parentType': {
+ // always "Set"
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].restrictionLookupListID': {
@@ -832,7 +852,7 @@ module.exports = {
retrieving: false,
template: null,
},
- 'valueDefinitions[].setDefinitionName.value': {
+ 'valueDefinitions[].setDefinitionName': {
isCreateable: null,
isUpdateable: null,
retrieving: false,
@@ -857,15 +877,17 @@ module.exports = {
template: null,
},
'valueDefinitions[].valueDefinitionID': {
+ // equal to valueDefinitions[].definitionID
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].valueDefinitionKey': {
+ // equal to valueDefinitions[].definitionKey
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
r__folder_Path: {
diff --git a/test/resources/9999999/attributeSet/retrieve-expected.json b/test/resources/9999999/attributeSet/retrieve-expected.json
index ebcfcb66d..f0b87afe9 100644
--- a/test/resources/9999999/attributeSet/retrieve-expected.json
+++ b/test/resources/9999999/attributeSet/retrieve-expected.json
@@ -74,19 +74,10 @@
"storageObjectIDs": ["5b8b787a-5238-ee11-b85a-48df37d1de8a"],
"valueDefinitions": [
{
- "baseType": "Numeric",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceName": {},
"dataType": "LongNumber",
"definitionID": "548b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "CustomObjectKey",
- "definitionName": {
- "value": "Custom Object Key"
- },
"description": "",
- "fullyQualifiedName": "testExisting_dataExtensionShared.Custom Object Key",
"isHidden": true,
"isIdentityValue": true,
"isNullable": false,
@@ -94,33 +85,14 @@
"isReadOnly": true,
"isSystemDefined": true,
"isUpdateable": true,
- "localizedDescription": {
- "value": ""
- },
"name": "Custom Object Key",
- "parentType": "Set",
- "setDefinitionName": {
- "value": "testExisting_dataExtensionShared"
- },
- "storageName": "_CustomObjectKey",
- "valueDefinitionID": "548b787a-5238-ee11-b85a-48df37d1de8a",
- "valueDefinitionKey": "CustomObjectKey"
+ "storageName": "_CustomObjectKey"
},
{
- "baseType": "Text",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceName": {},
"dataType": "Text",
"definitionID": "588b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "FirstName",
- "definitionName": {
- "value": "FirstName"
- },
"description": "",
- "displayOrder": 0,
- "fullyQualifiedName": "testExisting_dataExtensionShared.FirstName",
"isHidden": false,
"isIdentityValue": false,
"isNullable": true,
@@ -129,45 +101,18 @@
"isSystemDefined": false,
"isUpdateable": true,
"length": 50,
- "localizedDescription": {
- "value": ""
- },
"name": "FirstName",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "588b787a-5238-ee11-b85a-48df37d1de8a"
- },
- "ordinal": 0,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "testExisting_dataExtensionShared"
- },
"storageFieldReferenceID": {
"type": "guid",
"value": "391bfc9e-ea85-4610-a24b-d8400a36cdfc"
},
- "storageName": "FirstName",
- "valueDefinitionID": "588b787a-5238-ee11-b85a-48df37d1de8a",
- "valueDefinitionKey": "FirstName"
+ "storageName": "FirstName"
},
{
- "baseType": "Text",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceName": {},
"dataType": "Text",
"definitionID": "578b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "LastName",
- "definitionName": {
- "value": "LastName"
- },
"description": "",
- "displayOrder": 1,
- "fullyQualifiedName": "testExisting_dataExtensionShared.LastName",
"isHidden": false,
"isIdentityValue": false,
"isNullable": true,
@@ -176,45 +121,18 @@
"isSystemDefined": false,
"isUpdateable": true,
"length": 55,
- "localizedDescription": {
- "value": ""
- },
"name": "LastName",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "578b787a-5238-ee11-b85a-48df37d1de8a"
- },
- "ordinal": 1,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "testExisting_dataExtensionShared"
- },
"storageFieldReferenceID": {
"type": "guid",
"value": "3f80ba1f-f957-400f-88cb-a9303491026d"
},
- "storageName": "LastName",
- "valueDefinitionID": "578b787a-5238-ee11-b85a-48df37d1de8a",
- "valueDefinitionKey": "LastName"
+ "storageName": "LastName"
},
{
- "baseType": "Text",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceName": {},
"dataType": "EmailAddress",
"definitionID": "568b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "EmailAddress",
- "definitionName": {
- "value": "EmailAddress"
- },
"description": "",
- "displayOrder": 2,
- "fullyQualifiedName": "testExisting_dataExtensionShared.EmailAddress",
"isHidden": false,
"isIdentityValue": false,
"isNullable": false,
@@ -223,45 +141,18 @@
"isSystemDefined": false,
"isUpdateable": true,
"length": 254,
- "localizedDescription": {
- "value": ""
- },
"name": "EmailAddress",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "568b787a-5238-ee11-b85a-48df37d1de8a"
- },
- "ordinal": 2,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "testExisting_dataExtensionShared"
- },
"storageFieldReferenceID": {
"type": "guid",
"value": "41b9575b-da06-41ed-8551-f76868451a51"
},
- "storageName": "EmailAddress",
- "valueDefinitionID": "568b787a-5238-ee11-b85a-48df37d1de8a",
- "valueDefinitionKey": "EmailAddress"
+ "storageName": "EmailAddress"
},
{
- "baseType": "Text",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "dataSourceName": {},
"dataType": "Text",
"definitionID": "558b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "ContactKey",
- "definitionName": {
- "value": "ContactKey"
- },
"description": "",
- "displayOrder": 4,
- "fullyQualifiedName": "testExisting_dataExtensionShared.ContactKey",
"isHidden": false,
"isIdentityValue": false,
"isNullable": false,
@@ -270,29 +161,12 @@
"isSystemDefined": false,
"isUpdateable": true,
"length": 50,
- "localizedDescription": {
- "value": ""
- },
"name": "ContactKey",
- "obfuscationProperties": {
- "maskType": "None",
- "maskTypeID": 0,
- "storageType": "Plain",
- "storageTypeID": 1,
- "valueDefinitionID": "558b787a-5238-ee11-b85a-48df37d1de8a"
- },
- "ordinal": 4,
- "parentType": "Set",
- "setDefinitionName": {
- "value": "testExisting_dataExtensionShared"
- },
"storageFieldReferenceID": {
"type": "guid",
"value": "49d0db37-dff0-49d9-9d82-eb29b345f238"
},
- "storageName": "ContactKey",
- "valueDefinitionID": "558b787a-5238-ee11-b85a-48df37d1de8a",
- "valueDefinitionKey": "ContactKey"
+ "storageName": "ContactKey"
}
]
}
From 9af8def21ca718194596b1d0b9f4293571de3b39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 23 Aug 2023 13:07:26 +0200
Subject: [PATCH 45/70] #1088: add All Contacts to attributeSet response
---
.../attributeSet/retrieve-expected.json | 7 +-
.../schema/setDefinitions/get-response.json | 276 +++++++++++++++++-
2 files changed, 277 insertions(+), 6 deletions(-)
diff --git a/test/resources/9999999/attributeSet/retrieve-expected.json b/test/resources/9999999/attributeSet/retrieve-expected.json
index f0b87afe9..c994c2dec 100644
--- a/test/resources/9999999/attributeSet/retrieve-expected.json
+++ b/test/resources/9999999/attributeSet/retrieve-expected.json
@@ -52,11 +52,8 @@
"leftRelationshipReferenceType": "CustomerData",
"relationshipAttributes": [
{
- "c__rightFullyQualifiedName": "testExisting_dataExtensionShared.ContactKey",
- "leftAttributeID": "37778523-13f7-e911-a2d8-1402ec938a35",
- "leftConnectingID": {
- "identifierType": "FullyQualifiedName"
- }
+ "c__leftFullyQualifiedName": "Contact.Contact Key",
+ "c__rightFullyQualifiedName": "testExisting_dataExtensionShared.ContactKey"
}
],
"relationshipID": "598b787a-5238-ee11-b85a-48df37d1de8a",
diff --git a/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json b/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
index 54e6f02ab..2826a4f3b 100644
--- a/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
+++ b/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
@@ -19827,7 +19827,7 @@
"leftRelationshipReferenceType": "CustomerData",
"relationshipAttributes": [
{
- "leftAttributeID": "37778523-13f7-e911-a2d8-1402ec938a35",
+ "leftAttributeID": "9503534e-6816-e811-80d0-1402ec7222b5",
"leftConnectingID": {
"identifierType": "FullyQualifiedName"
},
@@ -20180,6 +20180,280 @@
"setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
"setDefinitionKey": "testExisting_dataExtensionShared",
"name": "testExisting_dataExtensionShared"
+ },
+ {
+ "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "definitionKey": "Contact",
+ "definitionName": {
+ "value": "Contact"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "relationships": [
+ {
+ "canModify": false,
+ "canRemove": false,
+ "isHidden": false,
+ "isSystemDefined": false,
+ "isGroupToSetRelationship": true,
+ "leftItem": {
+ "cardinality": "One",
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "identifier": "9103534e-6816-e811-80d0-1402ec7222b5",
+ "relationshipType": "AttributeGroup"
+ },
+ "leftRelationshipIDs": [
+ {
+ "type": "int16",
+ "value": "2"
+ }
+ ],
+ "leftRelationshipReferenceType": "CustomerData",
+ "relationshipAttributes": [
+ {
+ "leftAttributeID": "9403534e-6816-e811-80d0-1402ec7222b5",
+ "leftConnectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "rightAttributeID": "9403534e-6816-e811-80d0-1402ec7222b5",
+ "rightConnectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ }
+ ],
+ "relationshipID": "9a03534e-6816-e811-80d0-1402ec7222b5",
+ "rightItem": {
+ "cardinality": "One",
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "identifier": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "relationshipType": "AttributeSet"
+ }
+ }
+ ],
+ "valueDefinitions": [
+ {
+ "baseType": "Numeric",
+ "customerDataID": 9,
+ "dataSourceID": 1,
+ "dataSourceName": {},
+ "dataType": "Byte",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "660eea87-ed21-ee11-b861-48df37d1dc79",
+ "definitionKey": "Status",
+ "definitionName": {
+ "value": "Status"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "fullyQualifiedName": "Contact.Status",
+ "isHidden": true,
+ "isIdentityValue": false,
+ "isNullable": true,
+ "isPrimaryKey": false,
+ "isReadOnly": true,
+ "isSystemDefined": true,
+ "isUpdateable": false,
+ "parentDefinition": {
+ "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "definitionKey": "Contact",
+ "definitionName": {
+ "value": "Contact"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "Status",
+ "valueDefinitionID": "660eea87-ed21-ee11-b861-48df37d1dc79",
+ "valueDefinitionKey": "Status",
+ "name": "Status",
+ "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "setDefinitionKey": "Contact",
+ "setDefinitionName": {
+ "value": "Contact"
+ },
+ "parentIdentifier": "9203534e-6816-e811-80d0-1402ec7222b5"
+ },
+ {
+ "baseType": "Numeric",
+ "customerDataID": 1,
+ "dataSourceID": 1,
+ "dataSourceName": {},
+ "dataType": "Number",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "9303534e-6816-e811-80d0-1402ec7222b5",
+ "definitionKey": "BusinessUnitID",
+ "definitionName": {
+ "value": "Business Unit ID"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "fullyQualifiedName": "Contact.Business Unit ID",
+ "isHidden": true,
+ "isIdentityValue": false,
+ "isNullable": false,
+ "isPrimaryKey": true,
+ "isReadOnly": true,
+ "isSystemDefined": true,
+ "isUpdateable": false,
+ "parentDefinition": {
+ "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "definitionKey": "Contact",
+ "definitionName": {
+ "value": "Contact"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "ClientID",
+ "valueDefinitionID": "9303534e-6816-e811-80d0-1402ec7222b5",
+ "valueDefinitionKey": "BusinessUnitID",
+ "name": "Business Unit ID",
+ "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "setDefinitionKey": "Contact",
+ "setDefinitionName": {
+ "value": "Contact"
+ },
+ "parentIdentifier": "9203534e-6816-e811-80d0-1402ec7222b5"
+ },
+ {
+ "baseType": "Text",
+ "customerDataID": 3,
+ "dataSourceID": 1,
+ "dataSourceName": {},
+ "dataType": "Text",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "9503534e-6816-e811-80d0-1402ec7222b5",
+ "definitionKey": "ContactKey",
+ "definitionName": {
+ "value": "Contact Key"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "fullyQualifiedName": "Contact.Contact Key",
+ "isHidden": false,
+ "isIdentityValue": false,
+ "isNullable": false,
+ "isPrimaryKey": false,
+ "isReadOnly": true,
+ "isSystemDefined": true,
+ "isUpdateable": false,
+ "length": -1,
+ "parentDefinition": {
+ "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "definitionKey": "Contact",
+ "definitionName": {
+ "value": "Contact"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "SubscriberKey",
+ "valueDefinitionID": "9503534e-6816-e811-80d0-1402ec7222b5",
+ "valueDefinitionKey": "ContactKey",
+ "name": "Contact Key",
+ "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "setDefinitionKey": "Contact",
+ "setDefinitionName": {
+ "value": "Contact"
+ },
+ "parentIdentifier": "9203534e-6816-e811-80d0-1402ec7222b5"
+ },
+ {
+ "baseType": "Numeric",
+ "customerDataID": 2,
+ "dataSourceID": 1,
+ "dataSourceName": {},
+ "dataType": "Number",
+ "description": "",
+ "localizedDescription": {
+ "value": ""
+ },
+ "definitionID": "9403534e-6816-e811-80d0-1402ec7222b5",
+ "definitionKey": "ContactID",
+ "definitionName": {
+ "value": "Contact ID"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ },
+ "fullyQualifiedName": "Contact.Contact ID",
+ "isHidden": false,
+ "isIdentityValue": false,
+ "isNullable": false,
+ "isPrimaryKey": true,
+ "isReadOnly": true,
+ "isSystemDefined": true,
+ "isUpdateable": false,
+ "parentDefinition": {
+ "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "definitionKey": "Contact",
+ "definitionName": {
+ "value": "Contact"
+ },
+ "connectingID": {
+ "identifierType": "FullyQualifiedName"
+ }
+ },
+ "parentType": "Set",
+ "storageName": "SubscriberID",
+ "valueDefinitionID": "9403534e-6816-e811-80d0-1402ec7222b5",
+ "valueDefinitionKey": "ContactID",
+ "name": "Contact ID",
+ "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "setDefinitionKey": "Contact",
+ "setDefinitionName": {
+ "value": "Contact"
+ },
+ "parentIdentifier": "9203534e-6816-e811-80d0-1402ec7222b5"
+ }
+ ],
+ "applicationID": "ce703ed3-e01f-4f5f-900d-76a95b363e29",
+ "applicationKey": "com.exacttarget.contacts",
+ "attributeCount": 0,
+ "canAddValues": false,
+ "canChangeValues": false,
+ "canModify": false,
+ "canRemove": false,
+ "createdBy": -1000,
+ "createDate": "2018-02-20T12:03:00",
+ "localizedDescription": {},
+ "fullyQualifiedName": "Contact",
+ "isCustomObjectBacked": false,
+ "isEvent": false,
+ "isHidden": false,
+ "isReadOnly": true,
+ "isRoot": false,
+ "isSendable": false,
+ "isSystemDefined": true,
+ "parentID": "00000000-0000-0000-0000-000000000000",
+ "relationshipCount": 1,
+ "storageObjectIDs": ["2ba72136-9f31-4a79-ab62-4ba5d19cd759"],
+ "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
+ "setDefinitionKey": "Contact",
+ "name": "Contact"
}
],
"responseContext": {
From c970fdf9ad1caee3dcb279974923d43da8951092 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 23 Aug 2023 13:47:00 +0200
Subject: [PATCH 46/70] #1088: remove additional fields from retrieve to
increase readability
---
.../definitions/AttributeSet.definition.js | 14 +-
.../attributeSet/retrieve-expected.json | 36 +--
.../schema/setDefinitions/get-response.json | 276 +-----------------
3 files changed, 18 insertions(+), 308 deletions(-)
diff --git a/lib/metadataTypes/definitions/AttributeSet.definition.js b/lib/metadataTypes/definitions/AttributeSet.definition.js
index 4c2dcbea8..30cc2e8e3 100644
--- a/lib/metadataTypes/definitions/AttributeSet.definition.js
+++ b/lib/metadataTypes/definitions/AttributeSet.definition.js
@@ -660,9 +660,10 @@ module.exports = {
template: null,
},
'valueDefinitions[].definitionID': {
+ // likely the main ID of the value definition. No use for simple checks on git though as long as we cannot update it
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].definitionKey': {
@@ -858,22 +859,31 @@ module.exports = {
retrieving: false,
template: null,
},
+ 'valueDefinitions[].storageFieldReferenceID': {
+ isCreateable: null,
+ isUpdateable: null,
+ retrieving: false,
+ template: null,
+ },
'valueDefinitions[].storageFieldReferenceID.type': {
+ // always "guid"
isCreateable: null,
isUpdateable: null,
retrieving: true,
template: null,
},
'valueDefinitions[].storageFieldReferenceID.value': {
+ // unknown GUID
isCreateable: null,
isUpdateable: null,
retrieving: true,
template: null,
},
'valueDefinitions[].storageName': {
+ // always equal valueDefinitions[].definitionKey, except for when that is CustomObjectKey - then this will be _CustomObjectKey (with an underscore)
isCreateable: null,
isUpdateable: null,
- retrieving: true,
+ retrieving: false,
template: null,
},
'valueDefinitions[].valueDefinitionID': {
diff --git a/test/resources/9999999/attributeSet/retrieve-expected.json b/test/resources/9999999/attributeSet/retrieve-expected.json
index c994c2dec..f24f33133 100644
--- a/test/resources/9999999/attributeSet/retrieve-expected.json
+++ b/test/resources/9999999/attributeSet/retrieve-expected.json
@@ -72,7 +72,6 @@
"valueDefinitions": [
{
"dataType": "LongNumber",
- "definitionID": "548b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "CustomObjectKey",
"description": "",
"isHidden": true,
@@ -82,12 +81,10 @@
"isReadOnly": true,
"isSystemDefined": true,
"isUpdateable": true,
- "name": "Custom Object Key",
- "storageName": "_CustomObjectKey"
+ "name": "Custom Object Key"
},
{
"dataType": "Text",
- "definitionID": "588b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "FirstName",
"description": "",
"isHidden": false,
@@ -98,16 +95,10 @@
"isSystemDefined": false,
"isUpdateable": true,
"length": 50,
- "name": "FirstName",
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "391bfc9e-ea85-4610-a24b-d8400a36cdfc"
- },
- "storageName": "FirstName"
+ "name": "FirstName"
},
{
"dataType": "Text",
- "definitionID": "578b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "LastName",
"description": "",
"isHidden": false,
@@ -118,16 +109,10 @@
"isSystemDefined": false,
"isUpdateable": true,
"length": 55,
- "name": "LastName",
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "3f80ba1f-f957-400f-88cb-a9303491026d"
- },
- "storageName": "LastName"
+ "name": "LastName"
},
{
"dataType": "EmailAddress",
- "definitionID": "568b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "EmailAddress",
"description": "",
"isHidden": false,
@@ -138,16 +123,10 @@
"isSystemDefined": false,
"isUpdateable": true,
"length": 254,
- "name": "EmailAddress",
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "41b9575b-da06-41ed-8551-f76868451a51"
- },
- "storageName": "EmailAddress"
+ "name": "EmailAddress"
},
{
"dataType": "Text",
- "definitionID": "558b787a-5238-ee11-b85a-48df37d1de8a",
"definitionKey": "ContactKey",
"description": "",
"isHidden": false,
@@ -158,12 +137,7 @@
"isSystemDefined": false,
"isUpdateable": true,
"length": 50,
- "name": "ContactKey",
- "storageFieldReferenceID": {
- "type": "guid",
- "value": "49d0db37-dff0-49d9-9d82-eb29b345f238"
- },
- "storageName": "ContactKey"
+ "name": "ContactKey"
}
]
}
diff --git a/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json b/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
index 2826a4f3b..aef3bea05 100644
--- a/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
+++ b/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json
@@ -19827,7 +19827,7 @@
"leftRelationshipReferenceType": "CustomerData",
"relationshipAttributes": [
{
- "leftAttributeID": "9503534e-6816-e811-80d0-1402ec7222b5",
+ "leftAttributeID": "9393dc39-31e2-e611-80cc-1402ec7222b4",
"leftConnectingID": {
"identifierType": "FullyQualifiedName"
},
@@ -20180,280 +20180,6 @@
"setDefinitionID": "528b787a-5238-ee11-b85a-48df37d1de8a",
"setDefinitionKey": "testExisting_dataExtensionShared",
"name": "testExisting_dataExtensionShared"
- },
- {
- "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "definitionKey": "Contact",
- "definitionName": {
- "value": "Contact"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "relationships": [
- {
- "canModify": false,
- "canRemove": false,
- "isHidden": false,
- "isSystemDefined": false,
- "isGroupToSetRelationship": true,
- "leftItem": {
- "cardinality": "One",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "identifier": "9103534e-6816-e811-80d0-1402ec7222b5",
- "relationshipType": "AttributeGroup"
- },
- "leftRelationshipIDs": [
- {
- "type": "int16",
- "value": "2"
- }
- ],
- "leftRelationshipReferenceType": "CustomerData",
- "relationshipAttributes": [
- {
- "leftAttributeID": "9403534e-6816-e811-80d0-1402ec7222b5",
- "leftConnectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "rightAttributeID": "9403534e-6816-e811-80d0-1402ec7222b5",
- "rightConnectingID": {
- "identifierType": "FullyQualifiedName"
- }
- }
- ],
- "relationshipID": "9a03534e-6816-e811-80d0-1402ec7222b5",
- "rightItem": {
- "cardinality": "One",
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "identifier": "9203534e-6816-e811-80d0-1402ec7222b5",
- "relationshipType": "AttributeSet"
- }
- }
- ],
- "valueDefinitions": [
- {
- "baseType": "Numeric",
- "customerDataID": 9,
- "dataSourceID": 1,
- "dataSourceName": {},
- "dataType": "Byte",
- "description": "",
- "localizedDescription": {
- "value": ""
- },
- "definitionID": "660eea87-ed21-ee11-b861-48df37d1dc79",
- "definitionKey": "Status",
- "definitionName": {
- "value": "Status"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "fullyQualifiedName": "Contact.Status",
- "isHidden": true,
- "isIdentityValue": false,
- "isNullable": true,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "parentDefinition": {
- "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "definitionKey": "Contact",
- "definitionName": {
- "value": "Contact"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- }
- },
- "parentType": "Set",
- "storageName": "Status",
- "valueDefinitionID": "660eea87-ed21-ee11-b861-48df37d1dc79",
- "valueDefinitionKey": "Status",
- "name": "Status",
- "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "setDefinitionKey": "Contact",
- "setDefinitionName": {
- "value": "Contact"
- },
- "parentIdentifier": "9203534e-6816-e811-80d0-1402ec7222b5"
- },
- {
- "baseType": "Numeric",
- "customerDataID": 1,
- "dataSourceID": 1,
- "dataSourceName": {},
- "dataType": "Number",
- "description": "",
- "localizedDescription": {
- "value": ""
- },
- "definitionID": "9303534e-6816-e811-80d0-1402ec7222b5",
- "definitionKey": "BusinessUnitID",
- "definitionName": {
- "value": "Business Unit ID"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "fullyQualifiedName": "Contact.Business Unit ID",
- "isHidden": true,
- "isIdentityValue": false,
- "isNullable": false,
- "isPrimaryKey": true,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "parentDefinition": {
- "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "definitionKey": "Contact",
- "definitionName": {
- "value": "Contact"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- }
- },
- "parentType": "Set",
- "storageName": "ClientID",
- "valueDefinitionID": "9303534e-6816-e811-80d0-1402ec7222b5",
- "valueDefinitionKey": "BusinessUnitID",
- "name": "Business Unit ID",
- "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "setDefinitionKey": "Contact",
- "setDefinitionName": {
- "value": "Contact"
- },
- "parentIdentifier": "9203534e-6816-e811-80d0-1402ec7222b5"
- },
- {
- "baseType": "Text",
- "customerDataID": 3,
- "dataSourceID": 1,
- "dataSourceName": {},
- "dataType": "Text",
- "description": "",
- "localizedDescription": {
- "value": ""
- },
- "definitionID": "9503534e-6816-e811-80d0-1402ec7222b5",
- "definitionKey": "ContactKey",
- "definitionName": {
- "value": "Contact Key"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "fullyQualifiedName": "Contact.Contact Key",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": false,
- "isPrimaryKey": false,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "length": -1,
- "parentDefinition": {
- "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "definitionKey": "Contact",
- "definitionName": {
- "value": "Contact"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- }
- },
- "parentType": "Set",
- "storageName": "SubscriberKey",
- "valueDefinitionID": "9503534e-6816-e811-80d0-1402ec7222b5",
- "valueDefinitionKey": "ContactKey",
- "name": "Contact Key",
- "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "setDefinitionKey": "Contact",
- "setDefinitionName": {
- "value": "Contact"
- },
- "parentIdentifier": "9203534e-6816-e811-80d0-1402ec7222b5"
- },
- {
- "baseType": "Numeric",
- "customerDataID": 2,
- "dataSourceID": 1,
- "dataSourceName": {},
- "dataType": "Number",
- "description": "",
- "localizedDescription": {
- "value": ""
- },
- "definitionID": "9403534e-6816-e811-80d0-1402ec7222b5",
- "definitionKey": "ContactID",
- "definitionName": {
- "value": "Contact ID"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- },
- "fullyQualifiedName": "Contact.Contact ID",
- "isHidden": false,
- "isIdentityValue": false,
- "isNullable": false,
- "isPrimaryKey": true,
- "isReadOnly": true,
- "isSystemDefined": true,
- "isUpdateable": false,
- "parentDefinition": {
- "definitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "definitionKey": "Contact",
- "definitionName": {
- "value": "Contact"
- },
- "connectingID": {
- "identifierType": "FullyQualifiedName"
- }
- },
- "parentType": "Set",
- "storageName": "SubscriberID",
- "valueDefinitionID": "9403534e-6816-e811-80d0-1402ec7222b5",
- "valueDefinitionKey": "ContactID",
- "name": "Contact ID",
- "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "setDefinitionKey": "Contact",
- "setDefinitionName": {
- "value": "Contact"
- },
- "parentIdentifier": "9203534e-6816-e811-80d0-1402ec7222b5"
- }
- ],
- "applicationID": "ce703ed3-e01f-4f5f-900d-76a95b363e29",
- "applicationKey": "com.exacttarget.contacts",
- "attributeCount": 0,
- "canAddValues": false,
- "canChangeValues": false,
- "canModify": false,
- "canRemove": false,
- "createdBy": -1000,
- "createDate": "2018-02-20T12:03:00",
- "localizedDescription": {},
- "fullyQualifiedName": "Contact",
- "isCustomObjectBacked": false,
- "isEvent": false,
- "isHidden": false,
- "isReadOnly": true,
- "isRoot": false,
- "isSendable": false,
- "isSystemDefined": true,
- "parentID": "00000000-0000-0000-0000-000000000000",
- "relationshipCount": 1,
- "storageObjectIDs": ["2ba72136-9f31-4a79-ab62-4ba5d19cd759"],
- "setDefinitionID": "9203534e-6816-e811-80d0-1402ec7222b5",
- "setDefinitionKey": "Contact",
- "name": "Contact"
}
],
"responseContext": {
From bef0105af07326a47f4f7a72799062c69eeb4bce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Wed, 23 Aug 2023 14:08:28 +0200
Subject: [PATCH 47/70] #1090: make attributeGroup and attributeSet be
retrieved by default
---
lib/metadataTypes/definitions/AttributeGroup.definition.js | 4 ++--
lib/metadataTypes/definitions/AttributeSet.definition.js | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/metadataTypes/definitions/AttributeGroup.definition.js b/lib/metadataTypes/definitions/AttributeGroup.definition.js
index 2dc24a507..0138541b5 100644
--- a/lib/metadataTypes/definitions/AttributeGroup.definition.js
+++ b/lib/metadataTypes/definitions/AttributeGroup.definition.js
@@ -8,8 +8,8 @@ module.exports = {
nameField: 'definitionName.value',
restPagination: false, // Hub API does not support pagination and returns everything instead
type: 'attributeGroup',
- typeDescription: 'BETA: Groupings of Set Definitions (Data Extensions) in Data Designer.',
- typeRetrieveByDefault: false,
+ typeDescription: 'Groupings of Attribute Sets (Data Extensions) in Data Designer.',
+ typeRetrieveByDefault: true,
typeName: 'Data Designer Attribute Groups',
fields: {
applicationID: {
diff --git a/lib/metadataTypes/definitions/AttributeSet.definition.js b/lib/metadataTypes/definitions/AttributeSet.definition.js
index 30cc2e8e3..b771421c5 100644
--- a/lib/metadataTypes/definitions/AttributeSet.definition.js
+++ b/lib/metadataTypes/definitions/AttributeSet.definition.js
@@ -22,9 +22,9 @@ module.exports = {
lastmodNameField: null,
restPagination: false, // Hub API does not support pagination and returns everything instead
type: 'attributeSet',
- typeDescription: 'BETA: Data Extensions linked to Attribute Groups in Data Designer.',
- typeRetrieveByDefault: false,
- typeName: 'Data Designer Set Definitions',
+ typeDescription: 'Data Extensions linked together in Attribute Groups in Data Designer.',
+ typeRetrieveByDefault: true,
+ typeName: 'Data Designer Attribute Sets',
fields: {
applicationID: {
isCreateable: null,
From 87dffd61e8dada3f770cb481e0133e4e1e1062ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 24 Aug 2023 14:10:39 +0200
Subject: [PATCH 48/70] #325: added tests for type verification
---
docs/dist/documentation.md | 13 +-
lib/metadataTypes/MetadataType.js | 14 +-
lib/metadataTypes/Verification.js | 6 +-
.../definitions/Verification.definition.js | 9 +-
...a488-20eb-4ba0-b0b9.verification-meta.json | 11 ++
...a488-20eb-4ba0-b0b9.verification-meta.json | 11 ++
.../get-response.json | 7 +
.../v1/dataverifications/post-response.json | 12 ++
.../delete-response.json | 0
.../get-response.json | 12 ++
.../patch-response.json | 12 ++
.../9999999/verification/build-expected.json | 11 ++
.../9999999/verification/get-expected.json | 11 ++
.../9999999/verification/patch-expected.json | 11 ++
.../9999999/verification/post-expected.json | 11 ++
.../verification/template-expected.json | 11 ++
test/type.verification.test.js | 171 ++++++++++++++++++
17 files changed, 322 insertions(+), 11 deletions(-)
create mode 100644 test/mockRoot/deploy/testInstance/testBU/verification/testExisting_39f6a488-20eb-4ba0-b0b9.verification-meta.json
create mode 100644 test/mockRoot/deploy/testInstance/testBU/verification/testNew_39f6a488-20eb-4ba0-b0b9.verification-meta.json
create mode 100644 test/resources/9999999/automation/v1/dataverifications/post-response.json
create mode 100644 test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/delete-response.json
create mode 100644 test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/get-response.json
create mode 100644 test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/patch-response.json
create mode 100644 test/resources/9999999/verification/build-expected.json
create mode 100644 test/resources/9999999/verification/get-expected.json
create mode 100644 test/resources/9999999/verification/patch-expected.json
create mode 100644 test/resources/9999999/verification/post-expected.json
create mode 100644 test/resources/9999999/verification/template-expected.json
create mode 100644 test/type.verification.test.js
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 404c2f588..1bffd85d8 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -3431,7 +3431,7 @@ Provides default functionality that can be overwritten by child metadata type cl
* [.getSOAPErrorMsg(ex)](#MetadataType.getSOAPErrorMsg) ⇒ string
* [.retrieveSOAP(retrieveDir, [requestParams], [singleRetrieve], [additionalFields])](#MetadataType.retrieveSOAP) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.retrieveREST(retrieveDir, uri, [templateVariables], [singleRetrieve])](#MetadataType.retrieveREST) ⇒ Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
- * [.retrieveRESTcollection(urlArray, [concurrentRequests])](#MetadataType.retrieveRESTcollection) ⇒ Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
+ * [.retrieveRESTcollection(urlArray, [concurrentRequests], [logAmountOfUrls])](#MetadataType.retrieveRESTcollection) ⇒ Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
* [.handleRESTErrors(ex, id)](#MetadataType.handleRESTErrors) ⇒ null
* [.executeREST(uri, key)](#MetadataType.executeREST) ⇒ Promise.<{key:string, response:string}>
* [.executeSOAP([metadataEntry])](#MetadataType.executeSOAP) ⇒ Promise.<{key:string, response:object}>
@@ -3913,14 +3913,15 @@ Retrieves Metadata for Rest Types
-### MetadataType.retrieveRESTcollection(urlArray, [concurrentRequests]) ⇒ Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
+### MetadataType.retrieveRESTcollection(urlArray, [concurrentRequests], [logAmountOfUrls]) ⇒ Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
**Kind**: static method of [MetadataType
](#MetadataType)
**Returns**: Promise.<{metadata: (TYPE.MetadataTypeMap\|TYPE.MetadataTypeItem), type: string}>
- Promise of item map (single item for templated result)
-| Param | Type | Description |
-| --- | --- | --- |
-| urlArray | Array.<object>
| {uri: string, id: string} combo of URL and ID/key of metadata |
-| [concurrentRequests] | number
| optionally set a different amount of concurrent requests |
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| urlArray | Array.<object>
| | {uri: string, id: string} combo of URL and ID/key of metadata |
+| [concurrentRequests] | number
| 10
| optionally set a different amount of concurrent requests |
+| [logAmountOfUrls] | boolean
| true
| if true, prints an info message about to-be loaded amount of metadata |
diff --git a/lib/metadataTypes/MetadataType.js b/lib/metadataTypes/MetadataType.js
index 9b71aac6e..5db7f9a1a 100644
--- a/lib/metadataTypes/MetadataType.js
+++ b/lib/metadataTypes/MetadataType.js
@@ -1094,10 +1094,20 @@ class MetadataType {
*
* @param {object[]} urlArray {uri: string, id: string} combo of URL and ID/key of metadata
* @param {number} [concurrentRequests] optionally set a different amount of concurrent requests
+ * @param {boolean} [logAmountOfUrls] if true, prints an info message about to-be loaded amount of metadata
* @returns {Promise.<{metadata: (TYPE.MetadataTypeMap | TYPE.MetadataTypeItem), type: string}>} Promise of item map (single item for templated result)
*/
- static async retrieveRESTcollection(urlArray, concurrentRequests) {
- const rateLimit = pLimit(concurrentRequests || 10);
+ static async retrieveRESTcollection(urlArray, concurrentRequests = 10, logAmountOfUrls = true) {
+ if (logAmountOfUrls) {
+ Util.logger.info(
+ Util.getGrayMsg(
+ ` - ${urlArray?.length} ${this.definition.type}${
+ urlArray?.length === 1 ? '' : 's'
+ } found. Retrieving details...`
+ )
+ );
+ }
+ const rateLimit = pLimit(concurrentRequests);
const metadataArr = urlArray.length
? await Promise.all(
diff --git a/lib/metadataTypes/Verification.js b/lib/metadataTypes/Verification.js
index c4a75069a..891b9382f 100644
--- a/lib/metadataTypes/Verification.js
+++ b/lib/metadataTypes/Verification.js
@@ -69,7 +69,9 @@ class Verification extends MetadataType {
const results = {};
if (paramArr.length) {
const response = await this.retrieveRESTcollection(
- paramArr.map((id) => ({ id, uri: '/automation/v1/dataverifications/' + id }))
+ paramArr.map((id) => ({ id, uri: '/automation/v1/dataverifications/' + id })),
+ undefined,
+ !key
);
if (response?.metadata) {
Object.assign(results, response.metadata);
@@ -160,7 +162,7 @@ class Verification extends MetadataType {
static update(metadata) {
return super.updateREST(
metadata,
- '/automation/v1/dataverifications/' + metadata.verificationDefinitionId
+ '/automation/v1/dataverifications/' + metadata.dataVerificationDefinitionId
);
}
diff --git a/lib/metadataTypes/definitions/Verification.definition.js b/lib/metadataTypes/definitions/Verification.definition.js
index 468fc9bc4..25e63ac5d 100644
--- a/lib/metadataTypes/definitions/Verification.definition.js
+++ b/lib/metadataTypes/definitions/Verification.definition.js
@@ -18,9 +18,10 @@ module.exports = {
typeName: 'Automation: Data Verification Activity',
fields: {
createdBy: {
+ // User ID
isCreateable: false,
isUpdateable: false,
- retrieving: true,
+ retrieving: false,
template: false,
},
dataVerificationDefinitionId: {
@@ -77,5 +78,11 @@ module.exports = {
retrieving: true,
template: true,
},
+ r__dataExtension_CustomerKey: {
+ isCreateable: false,
+ isUpdateable: false,
+ retrieving: true,
+ template: true,
+ },
},
};
diff --git a/test/mockRoot/deploy/testInstance/testBU/verification/testExisting_39f6a488-20eb-4ba0-b0b9.verification-meta.json b/test/mockRoot/deploy/testInstance/testBU/verification/testExisting_39f6a488-20eb-4ba0-b0b9.verification-meta.json
new file mode 100644
index 000000000..dc8d975d2
--- /dev/null
+++ b/test/mockRoot/deploy/testInstance/testBU/verification/testExisting_39f6a488-20eb-4ba0-b0b9.verification-meta.json
@@ -0,0 +1,11 @@
+{
+ "dataVerificationDefinitionId": "testExisting_39f6a488-20eb-4ba0-b0b9",
+ "notificationEmailAddress": "test@accenture.com",
+ "notificationEmailMessage": "",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtension",
+ "shouldEmailOnFailure": true,
+ "shouldStopOnFailure": true,
+ "value1": 1,
+ "value2": 0,
+ "verificationType": "IsEqualTo"
+}
diff --git a/test/mockRoot/deploy/testInstance/testBU/verification/testNew_39f6a488-20eb-4ba0-b0b9.verification-meta.json b/test/mockRoot/deploy/testInstance/testBU/verification/testNew_39f6a488-20eb-4ba0-b0b9.verification-meta.json
new file mode 100644
index 000000000..ee5c6ed27
--- /dev/null
+++ b/test/mockRoot/deploy/testInstance/testBU/verification/testNew_39f6a488-20eb-4ba0-b0b9.verification-meta.json
@@ -0,0 +1,11 @@
+{
+ "dataVerificationDefinitionId": "testNew_39f6a488-20eb-4ba0-b0b9",
+ "notificationEmailAddress": "",
+ "notificationEmailMessage": "",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtension",
+ "shouldEmailOnFailure": false,
+ "shouldStopOnFailure": false,
+ "value1": 2,
+ "value2": 0,
+ "verificationType": "IsEqualTo"
+}
diff --git a/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json b/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json
index 5d86c87b2..3c982a924 100644
--- a/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json
+++ b/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json
@@ -78,6 +78,13 @@
"activityObjectId": "39f6a488-20eb-4ba0-b0b9-023725b574e4",
"objectTypeId": 423,
"displayOrder": 6
+ },
+ {
+ "id": "f3774dc2-a271-4a44-8cbe-f630a6d6545e",
+ "name": "testExisting_dataExtension",
+ "activityObjectId": "testExisting_39f6a488-20eb-4ba0-b0b9",
+ "objectTypeId": 1000,
+ "displayOrder": 7
}
]
}
diff --git a/test/resources/9999999/automation/v1/dataverifications/post-response.json b/test/resources/9999999/automation/v1/dataverifications/post-response.json
new file mode 100644
index 000000000..96d88a20e
--- /dev/null
+++ b/test/resources/9999999/automation/v1/dataverifications/post-response.json
@@ -0,0 +1,12 @@
+{
+ "dataVerificationDefinitionId": "testNew_RANDOM_NEW_GUID",
+ "targetObjectId": "21711373-72c1-ec11-b83b-48df37d1deb7",
+ "verificationType": "IsEqualTo",
+ "value1": 2,
+ "value2": 0,
+ "shouldStopOnFailure": false,
+ "shouldEmailOnFailure": false,
+ "notificationEmailAddress": "",
+ "notificationEmailMessage": "",
+ "createdBy": 700301950
+}
diff --git a/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/delete-response.json b/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/delete-response.json
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/get-response.json b/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/get-response.json
new file mode 100644
index 000000000..6b6d4101e
--- /dev/null
+++ b/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/get-response.json
@@ -0,0 +1,12 @@
+{
+ "dataVerificationDefinitionId": "testExisting_39f6a488-20eb-4ba0-b0b9",
+ "targetObjectId": "21711373-72c1-ec11-b83b-48df37d1deb7",
+ "verificationType": "IsEqualTo",
+ "value1": 1,
+ "value2": 0,
+ "shouldStopOnFailure": true,
+ "shouldEmailOnFailure": false,
+ "notificationEmailAddress": "",
+ "notificationEmailMessage": "",
+ "createdBy": 700301950
+}
diff --git a/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/patch-response.json b/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/patch-response.json
new file mode 100644
index 000000000..5d7c8d336
--- /dev/null
+++ b/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/patch-response.json
@@ -0,0 +1,12 @@
+{
+ "dataVerificationDefinitionId": "testExisting_39f6a488-20eb-4ba0-b0b9",
+ "targetObjectId": "21711373-72c1-ec11-b83b-48df37d1deb7",
+ "verificationType": "IsEqualTo",
+ "value1": 1,
+ "value2": 0,
+ "shouldStopOnFailure": true,
+ "shouldEmailOnFailure": true,
+ "notificationEmailAddress": "test@accenture.com",
+ "notificationEmailMessage": "",
+ "createdBy": 700301950
+}
diff --git a/test/resources/9999999/verification/build-expected.json b/test/resources/9999999/verification/build-expected.json
new file mode 100644
index 000000000..f717cc626
--- /dev/null
+++ b/test/resources/9999999/verification/build-expected.json
@@ -0,0 +1,11 @@
+{
+ "dataVerificationDefinitionId": "testTemplated_39f6a488-20eb-4ba0-b0b9",
+ "notificationEmailAddress": "",
+ "notificationEmailMessage": "",
+ "r__dataExtension_CustomerKey": "testTemplated_dataExtension",
+ "shouldEmailOnFailure": false,
+ "shouldStopOnFailure": true,
+ "value1": 1,
+ "value2": 0,
+ "verificationType": "IsEqualTo"
+}
diff --git a/test/resources/9999999/verification/get-expected.json b/test/resources/9999999/verification/get-expected.json
new file mode 100644
index 000000000..1f9c1825b
--- /dev/null
+++ b/test/resources/9999999/verification/get-expected.json
@@ -0,0 +1,11 @@
+{
+ "dataVerificationDefinitionId": "testExisting_39f6a488-20eb-4ba0-b0b9",
+ "notificationEmailAddress": "",
+ "notificationEmailMessage": "",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtension",
+ "shouldEmailOnFailure": false,
+ "shouldStopOnFailure": true,
+ "value1": 1,
+ "value2": 0,
+ "verificationType": "IsEqualTo"
+}
diff --git a/test/resources/9999999/verification/patch-expected.json b/test/resources/9999999/verification/patch-expected.json
new file mode 100644
index 000000000..dc8d975d2
--- /dev/null
+++ b/test/resources/9999999/verification/patch-expected.json
@@ -0,0 +1,11 @@
+{
+ "dataVerificationDefinitionId": "testExisting_39f6a488-20eb-4ba0-b0b9",
+ "notificationEmailAddress": "test@accenture.com",
+ "notificationEmailMessage": "",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtension",
+ "shouldEmailOnFailure": true,
+ "shouldStopOnFailure": true,
+ "value1": 1,
+ "value2": 0,
+ "verificationType": "IsEqualTo"
+}
diff --git a/test/resources/9999999/verification/post-expected.json b/test/resources/9999999/verification/post-expected.json
new file mode 100644
index 000000000..b06a77b76
--- /dev/null
+++ b/test/resources/9999999/verification/post-expected.json
@@ -0,0 +1,11 @@
+{
+ "dataVerificationDefinitionId": "testNew_RANDOM_NEW_GUID",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtension",
+ "verificationType": "IsEqualTo",
+ "value1": 2,
+ "value2": 0,
+ "shouldStopOnFailure": false,
+ "shouldEmailOnFailure": false,
+ "notificationEmailAddress": "",
+ "notificationEmailMessage": ""
+}
diff --git a/test/resources/9999999/verification/template-expected.json b/test/resources/9999999/verification/template-expected.json
new file mode 100644
index 000000000..04296b7ea
--- /dev/null
+++ b/test/resources/9999999/verification/template-expected.json
@@ -0,0 +1,11 @@
+{
+ "dataVerificationDefinitionId": "{{{prefix}}}39f6a488-20eb-4ba0-b0b9",
+ "notificationEmailAddress": "",
+ "notificationEmailMessage": "",
+ "r__dataExtension_CustomerKey": "{{{prefix}}}dataExtension",
+ "shouldEmailOnFailure": false,
+ "shouldStopOnFailure": true,
+ "value1": 1,
+ "value2": 0,
+ "verificationType": "IsEqualTo"
+}
diff --git a/test/type.verification.test.js b/test/type.verification.test.js
new file mode 100644
index 000000000..993f26095
--- /dev/null
+++ b/test/type.verification.test.js
@@ -0,0 +1,171 @@
+const chai = require('chai');
+const chaiFiles = require('chai-files');
+const assert = chai.assert;
+chai.use(chaiFiles);
+const cache = require('../lib/util/cache');
+const testUtils = require('./utils');
+const handler = require('../lib/index');
+
+describe('type: verification', () => {
+ beforeEach(() => {
+ testUtils.mockSetup();
+ });
+ afterEach(() => {
+ testUtils.mockReset();
+ });
+
+ describe('Retrieve ================', () => {
+ it('Should retrieve a verification', async () => {
+ // WHEN
+ const retrieved = await handler.retrieve('testInstance/testBU', ['verification']);
+ // THEN
+ assert.equal(process.exitCode, false, 'retrieve should not have thrown an error');
+ // get results from cache
+ const result = cache.getCache();
+ assert.equal(
+ result.verification ? Object.keys(result.verification).length : 0,
+ 1,
+ 'only one verification expected'
+ );
+ assert.equal(
+ retrieved['testInstance/testBU']?.verification
+ ? Object.keys(retrieved['testInstance/testBU']?.verification).length
+ : 0,
+ 1,
+ 'one verifications to be retrieved'
+ );
+
+ assert.deepEqual(
+ await testUtils.getActualJson(
+ 'testExisting_39f6a488-20eb-4ba0-b0b9',
+ 'verification'
+ ),
+ await testUtils.getExpectedJson('9999999', 'verification', 'get'),
+ 'returned JSON was not equal expected'
+ );
+ assert.equal(
+ testUtils.getAPIHistoryLength(),
+ 9,
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+ );
+ return;
+ });
+ });
+ describe('Deploy ================', () => {
+ beforeEach(() => {
+ testUtils.mockSetup(true);
+ });
+ it('Should create & upsert a verification', async () => {
+ // WHEN
+
+ const deployed = await handler.deploy('testInstance/testBU', ['verification']);
+ // THEN
+ assert.equal(process.exitCode, false, 'deploy should not have thrown an error');
+ // get results from cache
+ const result = cache.getCache();
+ assert.equal(
+ result.verification ? Object.keys(result.verification).length : 0,
+ 2,
+ 'two verifications expected'
+ );
+ assert.equal(
+ deployed['testInstance/testBU']?.verification
+ ? Object.keys(deployed['testInstance/testBU']?.verification).length
+ : 0,
+ 2,
+ 'two verifications to be deployed'
+ );
+ // confirm created item
+ assert.deepEqual(
+ await testUtils.getActualJson('testNew_RANDOM_NEW_GUID', 'verification'),
+ await testUtils.getExpectedJson('9999999', 'verification', 'post'),
+ 'returned new-JSON was not equal expected for insert verification'
+ );
+ // confirm updated item
+ assert.deepEqual(
+ await testUtils.getActualJson(
+ 'testExisting_39f6a488-20eb-4ba0-b0b9',
+ 'verification'
+ ),
+ await testUtils.getExpectedJson('9999999', 'verification', 'patch'),
+ 'returned existing-JSON was not equal expected for update verification'
+ );
+ // check number of API calls
+ assert.equal(
+ testUtils.getAPIHistoryLength(),
+ 11,
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+ );
+ return;
+ });
+ });
+ describe('Templating ================', () => {
+ it('Should create a verification template via buildTemplate and build it', async () => {
+ // download first before we test buildTemplate
+ await handler.retrieve('testInstance/testBU', ['verification']);
+ // buildTemplate
+ const result = await handler.buildTemplate(
+ 'testInstance/testBU',
+ 'verification',
+ ['testExisting_39f6a488-20eb-4ba0-b0b9'],
+ 'testSourceMarket'
+ );
+ assert.equal(process.exitCode, false, 'buildTemplate should not have thrown an error');
+ assert.equal(
+ result.verification ? Object.keys(result.verification).length : 0,
+ 1,
+ 'only one verification expected'
+ );
+ assert.deepEqual(
+ await testUtils.getActualTemplateJson(
+ 'testExisting_39f6a488-20eb-4ba0-b0b9',
+ 'verification'
+ ),
+ await testUtils.getExpectedJson('9999999', 'verification', 'template'),
+ 'returned template JSON was not equal expected'
+ );
+ // buildDefinition
+ await handler.buildDefinition(
+ 'testInstance/testBU',
+ 'verification',
+ 'testExisting_39f6a488-20eb-4ba0-b0b9',
+ 'testTargetMarket'
+ );
+ assert.equal(
+ process.exitCode,
+ false,
+ 'buildDefinition should not have thrown an error'
+ );
+ assert.deepEqual(
+ await testUtils.getActualDeployJson(
+ 'testTemplated_39f6a488-20eb-4ba0-b0b9',
+ 'verification'
+ ),
+ await testUtils.getExpectedJson('9999999', 'verification', 'build'),
+ 'returned deployment JSON was not equal expected'
+ );
+ assert.equal(
+ testUtils.getAPIHistoryLength(),
+ 9,
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
+ );
+ return;
+ });
+ });
+ describe('Delete ================', () => {
+ it('Should delete the item', async () => {
+ // WHEN
+ const isDeleted = await handler.deleteByKey('testInstance/testBU', 'verification', [
+ 'testExisting_39f6a488-20eb-4ba0-b0b9',
+ ]);
+ // THEN
+ assert.equal(
+ process.exitCode,
+ 0,
+ 'deleteByKey should have thrown an error due to lack of support'
+ );
+ assert.equal(isDeleted, true, 'deleteByKey should have returned true for success');
+ return;
+ });
+ });
+});
From 0d437e94c5346764996ed9d1cbc455140d1b26c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 24 Aug 2023 14:24:29 +0200
Subject: [PATCH 49/70] #325: fix retrieve test for automation
---
test/resources/9999999/automation/retrieve-expected.json | 4 ++++
.../automation/retrieve-testExisting_automation-expected.md | 1 +
test/type.automation.test.js | 3 +--
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/test/resources/9999999/automation/retrieve-expected.json b/test/resources/9999999/automation/retrieve-expected.json
index f4771678a..a598c8aff 100644
--- a/test/resources/9999999/automation/retrieve-expected.json
+++ b/test/resources/9999999/automation/retrieve-expected.json
@@ -36,6 +36,10 @@
{
"name": "testExisting_script",
"r__type": "script"
+ },
+ {
+ "name": "testExisting_39f6a488-20eb-4ba0-b0b9",
+ "r__type": "verification"
}
],
"name": ""
diff --git a/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md b/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md
index 6c22b1c53..161e31040 100644
--- a/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md
+++ b/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md
@@ -28,3 +28,4 @@
| _1.4: importFile_ testExisting_importFile |
| _1.5: query_ testExisting_query |
| _1.6: script_ testExisting_script |
+| _1.7: verification_ testExisting_39f6a488-20eb-4ba0-b0b9 |
diff --git a/test/type.automation.test.js b/test/type.automation.test.js
index 3caf3b474..921b39429 100644
--- a/test/type.automation.test.js
+++ b/test/type.automation.test.js
@@ -47,10 +47,9 @@ describe('type: automation', () => {
)
)
);
-
assert.equal(
testUtils.getAPIHistoryLength(),
- 17,
+ 18,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
From 6cee703640654d279ddb922d413c0a44fa292a28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 24 Aug 2023 14:26:17 +0200
Subject: [PATCH 50/70] #325: move log msg into generic method
---
lib/metadataTypes/Automation.js | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/lib/metadataTypes/Automation.js b/lib/metadataTypes/Automation.js
index 61926367d..f0ee48014 100644
--- a/lib/metadataTypes/Automation.js
+++ b/lib/metadataTypes/Automation.js
@@ -46,16 +46,6 @@ class Automation extends MetadataType {
['ObjectID'],
requestParams
);
- if (results.Results?.length && !key) {
- // empty results will come back without "Results" defined
- Util.logger.info(
- Util.getGrayMsg(
- ` - ${results.Results?.length} automation${
- results.Results?.length === 1 ? '' : 's'
- } found. Retrieving details...`
- )
- );
- }
// the API seems to handle 50 concurrent requests nicely
const response = results?.Results?.length
? await this.retrieveRESTcollection(
@@ -63,7 +53,8 @@ class Automation extends MetadataType {
id: item.ObjectID,
uri: '/automation/v1/automations/' + item.ObjectID,
})),
- 50
+ 50,
+ !key
)
: null;
metadataMap = response?.metadata || {};
From 4ea27792a0f4b8a304ab0cd3245cd5ba5137b5f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 24 Aug 2023 14:28:36 +0200
Subject: [PATCH 51/70] #325: improve test api logs
---
test/utils.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/test/utils.js b/test/utils.js
index 3e7a5a070..e54c41c2c 100644
--- a/test/utils.js
+++ b/test/utils.js
@@ -208,7 +208,13 @@ exports.getAPIHistory = () => apimock.history;
function getAPIHistoryDebug() {
const historyArr = Object.values(apimock.history)
.flat()
- .map((item) => ({ url: item.url, data: item.data }));
+ .map((item) => {
+ const log = { method: item.method, url: item.url };
+ if (item.data) {
+ log.body = item.data;
+ }
+ return log;
+ });
return historyArr;
}
exports.getAPIHistoryDebug = getAPIHistoryDebug;
From 1099ed4fb0a03c1dcad8a8419111b374f3dddff6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 24 Aug 2023 16:11:10 +0200
Subject: [PATCH 52/70] #325: fix caching logic for automations together with
verifications
---
lib/metadataTypes/Automation.js | 40 ++++++++++++++++++++-------------
1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/lib/metadataTypes/Automation.js b/lib/metadataTypes/Automation.js
index f0ee48014..992ca8ed4 100644
--- a/lib/metadataTypes/Automation.js
+++ b/lib/metadataTypes/Automation.js
@@ -26,7 +26,11 @@ class Automation extends MetadataType {
*/
static async retrieve(retrieveDir, _, __, key) {
let metadataMap;
- if (!key && this._cachedMetadataMap) {
+ if (key && this._cachedMetadataMap?.[key]) {
+ metadataMap = {};
+ metadataMap[key] = this._cachedMetadataMap[key];
+ delete this._cachedMetadataMap;
+ } else if (!key && this._cachedMetadataMap) {
metadataMap = this._cachedMetadataMap;
delete this._cachedMetadataMap;
} else {
@@ -229,12 +233,18 @@ class Automation extends MetadataType {
* @returns {Promise.} Promise of metadata
*/
static async retrieveForCache() {
- // get automations for cache
- const results = await this.client.soap.retrieveBulk('Program', [
- 'ObjectID',
- 'CustomerKey',
- 'Name',
- ]);
+ let results = {};
+ if (this._cachedMetadataMap) {
+ results.Results = Object.values(this._cachedMetadataMap);
+ delete this._cachedMetadataMap;
+ } else {
+ // get automations for cache
+ results = await this.client.soap.retrieveBulk('Program', [
+ 'ObjectID',
+ 'CustomerKey',
+ 'Name',
+ ]);
+ }
const resultsConverted = {};
if (Array.isArray(results?.Results)) {
// get encodedAutomationID to retrieve notification information
@@ -251,16 +261,16 @@ class Automation extends MetadataType {
// merge encodedAutomationID into results
for (const m of results.Results) {
- resultsConverted[m.CustomerKey] = {
- id: m.ObjectID,
- key: m.CustomerKey,
- name: m.Name,
- programId: automationsLegacy.metadata[m.CustomerKey]?.id,
- status: automationsLegacy.metadata[m.CustomerKey]?.status,
+ const key = m.CustomerKey || m.key;
+ resultsConverted[key] = {
+ id: m.ObjectID || m.id,
+ key: key,
+ name: m.Name || m.name,
+ programId: automationsLegacy.metadata[key]?.id,
+ status: automationsLegacy.metadata[key]?.status,
};
}
}
-
return { metadata: resultsConverted, type: this.definition.type };
}
@@ -362,7 +372,7 @@ class Automation extends MetadataType {
* @param {TYPE.AutomationItem} metadata a single automation
* @returns {TYPE.AutomationItem | void} parsed item
*/
- static async postRetrieveTasks(metadata) {
+ static postRetrieveTasks(metadata) {
// folder
this.setFolderPath(metadata);
// automations are often skipped due to lack of support.
From 733b20161ebc2d5177e436c5ec2c30e1d20b993d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 24 Aug 2023 16:14:20 +0200
Subject: [PATCH 53/70] #325: fix automation tests after adding type
verification
---
.../9999999/automation/build-expected.json | 4 +++
.../9999999/automation/template-expected.json | 4 +++
.../automation/definition/get-response.json | 2 +-
test/type.automation.test.js | 25 ++++++++++---------
test/type.query.test.js | 4 +--
5 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/test/resources/9999999/automation/build-expected.json b/test/resources/9999999/automation/build-expected.json
index 87301aa55..d0e111d1e 100644
--- a/test/resources/9999999/automation/build-expected.json
+++ b/test/resources/9999999/automation/build-expected.json
@@ -36,6 +36,10 @@
{
"name": "testTemplated_script",
"r__type": "script"
+ },
+ {
+ "name": "testTemplated_39f6a488-20eb-4ba0-b0b9",
+ "r__type": "verification"
}
],
"name": ""
diff --git a/test/resources/9999999/automation/template-expected.json b/test/resources/9999999/automation/template-expected.json
index 32a6bcbc5..9e3db99fc 100644
--- a/test/resources/9999999/automation/template-expected.json
+++ b/test/resources/9999999/automation/template-expected.json
@@ -36,6 +36,10 @@
{
"name": "{{{prefix}}}script",
"r__type": "script"
+ },
+ {
+ "name": "{{{prefix}}}39f6a488-20eb-4ba0-b0b9",
+ "r__type": "verification"
}
],
"name": ""
diff --git a/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json b/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json
index bbf38898d..124f8fb90 100644
--- a/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json
+++ b/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json
@@ -10,7 +10,7 @@
"name": "testExisting_automation",
"description": "bla bla",
"clientId": 9999999,
- "status": "Building",
+ "status": "Scheduled",
"createdBy": {
"id": "NzE3MzUzNDA1OjQ6MA",
"name": "Tom Tester",
diff --git a/test/type.automation.test.js b/test/type.automation.test.js
index 921b39429..365c6c323 100644
--- a/test/type.automation.test.js
+++ b/test/type.automation.test.js
@@ -119,7 +119,7 @@ describe('type: automation', () => {
assert.equal(
testUtils.getAPIHistoryLength(),
- 16,
+ 21,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -188,7 +188,7 @@ describe('type: automation', () => {
assert.equal(
testUtils.getAPIHistoryLength(),
- 24,
+ 29,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -256,7 +256,7 @@ describe('type: automation', () => {
assert.equal(
testUtils.getAPIHistoryLength(),
- 20,
+ 25,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -288,10 +288,11 @@ describe('type: automation', () => {
1,
'one automation expected'
);
+ testUtils.logAPIHistoryDebug();
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 14,
+ 18,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -335,7 +336,7 @@ describe('type: automation', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 29,
+ 40,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -379,7 +380,7 @@ describe('type: automation', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 31,
+ 42,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -423,7 +424,7 @@ describe('type: automation', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 32,
+ 43,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -463,7 +464,7 @@ describe('type: automation', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 26,
+ 35,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -504,7 +505,7 @@ describe('type: automation', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 30,
+ 41,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -545,7 +546,7 @@ describe('type: automation', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 32,
+ 43,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -596,7 +597,7 @@ describe('type: automation', () => {
);
assert.equal(
testUtils.getAPIHistoryLength(),
- 14,
+ 20,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -643,7 +644,7 @@ describe('type: automation', () => {
);
assert.equal(
testUtils.getAPIHistoryLength(),
- 17,
+ 18,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
diff --git a/test/type.query.test.js b/test/type.query.test.js
index 01c3dd7c2..73ae86d21 100644
--- a/test/type.query.test.js
+++ b/test/type.query.test.js
@@ -458,7 +458,7 @@ describe('type: query', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 36,
+ 34,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -498,7 +498,7 @@ describe('type: query', () => {
// check number of API calls
assert.equal(
testUtils.getAPIHistoryLength(),
- 38,
+ 36,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
From 5e0f00ece322c0e368f7729081d69fc58a1d1e6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 25 Aug 2023 10:08:15 +0200
Subject: [PATCH 54/70] #325: consolidate / fix tests for deleteByKey across
types
---
test/type.automation.test.js | 4 ++--
test/type.dataExtension.test.js | 8 ++++----
test/type.dataExtract.test.js | 7 ++++++-
test/type.fileTransfer.test.js | 7 ++++++-
test/type.importFile.test.js | 7 ++++++-
test/type.mobileKeyword.test.js | 4 ++--
test/type.mobileMessage.test.js | 4 ++--
test/type.query.test.js | 4 ++--
test/type.triggeredSend.test.js | 4 ++--
test/type.verification.test.js | 8 +++++---
10 files changed, 37 insertions(+), 20 deletions(-)
diff --git a/test/type.automation.test.js b/test/type.automation.test.js
index 365c6c323..4a1acb0b7 100644
--- a/test/type.automation.test.js
+++ b/test/type.automation.test.js
@@ -653,7 +653,7 @@ describe('type: automation', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'automation',
'testExisting_automation'
@@ -661,7 +661,7 @@ describe('type: automation', () => {
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- assert.equal(result, true, 'should have deleted the item');
+ assert.equal(isDeleted, true, 'should have deleted the item');
return;
});
});
diff --git a/test/type.dataExtension.test.js b/test/type.dataExtension.test.js
index 15dae6984..b77ef9cbf 100644
--- a/test/type.dataExtension.test.js
+++ b/test/type.dataExtension.test.js
@@ -343,7 +343,7 @@ describe('type: dataExtension', () => {
describe('Delete ================', () => {
it('Should delete the dataExtension', async () => {
// WHEN
- const result = await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'dataExtension',
'testExisting_dataExtension'
@@ -351,12 +351,12 @@ describe('type: dataExtension', () => {
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- assert.equal(result, true, 'should have deleted the item');
+ assert.equal(isDeleted, true, 'should have deleted the item');
return;
});
it('Should delete the dataExtensionField', async () => {
// WHEN
- const result = await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'dataExtensionField',
'testExisting_dataExtension.LastName'
@@ -364,7 +364,7 @@ describe('type: dataExtension', () => {
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- assert.equal(result, true, 'should have deleted the item');
+ assert.equal(isDeleted, true, 'should have deleted the item');
return;
});
});
diff --git a/test/type.dataExtract.test.js b/test/type.dataExtract.test.js
index 0f55f5c8e..d0434c9a8 100644
--- a/test/type.dataExtract.test.js
+++ b/test/type.dataExtract.test.js
@@ -172,7 +172,7 @@ describe('type: dataExtract', () => {
describe('Delete ================', () => {
it('Should NOT delete the item', async () => {
// WHEN
- await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'dataExtract',
'testExisting_fileTranfer'
@@ -183,6 +183,11 @@ describe('type: dataExtract', () => {
1,
'deleteByKey should have thrown an error due to lack of support'
);
+ assert.equal(
+ isDeleted,
+ false,
+ 'deleteByKey should have returned false due to lack of support'
+ );
return;
});
});
diff --git a/test/type.fileTransfer.test.js b/test/type.fileTransfer.test.js
index 9424c893e..660866f96 100644
--- a/test/type.fileTransfer.test.js
+++ b/test/type.fileTransfer.test.js
@@ -170,7 +170,7 @@ describe('type: fileTransfer', () => {
describe('Delete ================', () => {
it('Should NOT delete the item', async () => {
// WHEN
- await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'fileTransfer',
'testExisting_fileTranfer'
@@ -181,6 +181,11 @@ describe('type: fileTransfer', () => {
1,
'deleteByKey should have thrown an error due to lack of support'
);
+ assert.equal(
+ isDeleted,
+ false,
+ 'deleteByKey should have returned false due to lack of support'
+ );
return;
});
});
diff --git a/test/type.importFile.test.js b/test/type.importFile.test.js
index 7b4bc1c3b..cf8c283dd 100644
--- a/test/type.importFile.test.js
+++ b/test/type.importFile.test.js
@@ -171,7 +171,7 @@ describe('type: importFile', () => {
describe('Delete ================', () => {
it('Should NOT delete the item', async () => {
// WHEN
- await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'importFile',
'testExisting_fileTranfer'
@@ -182,6 +182,11 @@ describe('type: importFile', () => {
1,
'deleteByKey should have thrown an error due to lack of support'
);
+ assert.equal(
+ isDeleted,
+ false,
+ 'deleteByKey should have returned false due to lack of support'
+ );
return;
});
});
diff --git a/test/type.mobileKeyword.test.js b/test/type.mobileKeyword.test.js
index 83d49810d..84f1c8fa8 100644
--- a/test/type.mobileKeyword.test.js
+++ b/test/type.mobileKeyword.test.js
@@ -245,7 +245,7 @@ describe('type: mobileKeyword', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'mobileKeyword',
'4912312345678.TESTEXISTING_KEYWORD'
@@ -253,7 +253,7 @@ describe('type: mobileKeyword', () => {
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- assert.equal(result, true, 'should have deleted the item');
+ assert.equal(isDeleted, true, 'should have deleted the item');
return;
});
});
diff --git a/test/type.mobileMessage.test.js b/test/type.mobileMessage.test.js
index 4562434ee..d80413213 100644
--- a/test/type.mobileMessage.test.js
+++ b/test/type.mobileMessage.test.js
@@ -163,7 +163,7 @@ describe('type: mobileMessage', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'mobileMessage',
'NTIzOjc4OjA'
@@ -171,7 +171,7 @@ describe('type: mobileMessage', () => {
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- assert.equal(result, true, 'should have deleted the item');
+ assert.equal(isDeleted, true, 'should have deleted the item');
return;
});
});
diff --git a/test/type.query.test.js b/test/type.query.test.js
index 73ae86d21..f2f24f53b 100644
--- a/test/type.query.test.js
+++ b/test/type.query.test.js
@@ -656,7 +656,7 @@ describe('type: query', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'query',
'testExisting_query'
@@ -664,7 +664,7 @@ describe('type: query', () => {
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- assert.equal(result, true, 'should have deleted the item');
+ assert.equal(isDeleted, true, 'should have deleted the item');
return;
});
});
diff --git a/test/type.triggeredSend.test.js b/test/type.triggeredSend.test.js
index a4fd91b4e..a923f1348 100644
--- a/test/type.triggeredSend.test.js
+++ b/test/type.triggeredSend.test.js
@@ -130,7 +130,7 @@ describe('type: triggeredSend', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const result = await handler.deleteByKey(
+ const isDeleted = await handler.deleteByKey(
'testInstance/testBU',
'triggeredSend',
'testExisting_triggeredSend'
@@ -138,7 +138,7 @@ describe('type: triggeredSend', () => {
// THEN
assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- assert.equal(result, true, 'should have deleted the item');
+ assert.equal(isDeleted, true, 'should have deleted the item');
return;
});
});
diff --git a/test/type.verification.test.js b/test/type.verification.test.js
index 993f26095..4514f3f04 100644
--- a/test/type.verification.test.js
+++ b/test/type.verification.test.js
@@ -155,9 +155,11 @@ describe('type: verification', () => {
describe('Delete ================', () => {
it('Should delete the item', async () => {
// WHEN
- const isDeleted = await handler.deleteByKey('testInstance/testBU', 'verification', [
- 'testExisting_39f6a488-20eb-4ba0-b0b9',
- ]);
+ const isDeleted = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'verification',
+ 'testExisting_39f6a488-20eb-4ba0-b0b9'
+ );
// THEN
assert.equal(
process.exitCode,
From 78c0908ea3833dbe9d625ae34f1c5e3aae8c2949 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 25 Aug 2023 10:40:09 +0200
Subject: [PATCH 55/70] #847: add test for delete journey
---
lib/metadataTypes/Journey.js | 9 +++-
.../delete-response.json | 1 +
test/type.journey.test.js | 49 ++++++++++++++-----
3 files changed, 47 insertions(+), 12 deletions(-)
create mode 100644 test/resources/9999999/interaction/v1/interactions/233d4413-922c-4568-85a5-e5cc77efc3be/delete-response.json
diff --git a/lib/metadataTypes/Journey.js b/lib/metadataTypes/Journey.js
index 1719dfe47..b2ea341b2 100644
--- a/lib/metadataTypes/Journey.js
+++ b/lib/metadataTypes/Journey.js
@@ -191,14 +191,21 @@ class Journey extends MetadataType {
);
const results = this.parseResponseBody(response, key);
singleKey = results[key].id;
+ if (version && version > results[key].version) {
+ Util.logger.error(
+ `The chosen version (${version}) is higher than the latest known version (${results[key].version}). Please choose a lower version.`
+ );
+ return false;
+ }
Util.logger.debug(`Deleting interaction ${key} via its ID ${singleKey}`);
}
if (!/^\d+$/.test(version)) {
- throw new TypeError(
+ Util.logger.error(
'Version is required for deleting interactions to avoid accidental deletion of the wrong item. Please append it at the end of the key or id, separated by forward-slash. Example for deleting version 4: ' +
key +
'/4'
);
+ return false;
}
Util.logger.warn(
`Deleting Journeys via this command breaks following retrieve-by-key/id requests until you've deployed/created a new draft version! You can get still get the latest available version of your journey by retrieving all interactions on this BU.`
diff --git a/test/resources/9999999/interaction/v1/interactions/233d4413-922c-4568-85a5-e5cc77efc3be/delete-response.json b/test/resources/9999999/interaction/v1/interactions/233d4413-922c-4568-85a5-e5cc77efc3be/delete-response.json
new file mode 100644
index 000000000..db5917a02
--- /dev/null
+++ b/test/resources/9999999/interaction/v1/interactions/233d4413-922c-4568-85a5-e5cc77efc3be/delete-response.json
@@ -0,0 +1 @@
+233d4413-922c-4568-85a5-e5cc77efc3be
\ No newline at end of file
diff --git a/test/type.journey.test.js b/test/type.journey.test.js
index 6003f511f..60a3a3fa5 100644
--- a/test/type.journey.test.js
+++ b/test/type.journey.test.js
@@ -141,17 +141,44 @@ describe('type: journey', () => {
});
});
describe('Delete ================', () => {
- // TODO: add this test
- it('Should delete the item'); // , async () => {
- // // WHEN
- // const result = await handler.deleteByKey('testInstance/testBU', 'mobileKeyword', [
- // 'testExisting_keyword',
- // ]);
- // // THEN
- // assert.equal(process.exitCode, false, 'delete should not have thrown an error');
+ it('Should NOT delete the item due to missing version', async () => {
+ // WHEN
+ const isDeleted = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'journey',
+ 'testExisting_interaction'
+ );
+ // THEN
+ assert.equal(process.exitCode, true, 'delete should have thrown an error');
- // assert.equal(result, true, 'should have deleted the item');
- // return;
- // });
+ assert.equal(isDeleted, false, 'should not have deleted the item');
+ return;
+ });
+ it('Should NOT delete the item due to unknown version', async () => {
+ // WHEN
+ const isDeleted = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'journey',
+ 'testExisting_interaction/2'
+ );
+ // THEN
+ assert.equal(process.exitCode, true, 'delete should have thrown an error');
+
+ assert.equal(isDeleted, false, 'should not have deleted the item');
+ return;
+ });
+ it('Should delete the item with version', async () => {
+ // WHEN
+ const isDeleted = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'journey',
+ 'testExisting_interaction/1'
+ );
+ // THEN
+ assert.equal(process.exitCode, false, 'delete should not have thrown an error');
+
+ assert.equal(isDeleted, true, 'should have deleted the item');
+ return;
+ });
});
});
From fe53e9c6cea5e58deb33e14f375654024009bef0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 25 Aug 2023 14:16:23 +0200
Subject: [PATCH 56/70] #926: fix transactionalEmail create and delete logic to
deal with the connected journey; rename fields to match r__ pattern
---
docs/dist/documentation.md | 42 ++++++-
lib/metadataTypes/TransactionalEmail.js | 111 +++++++++++++++---
lib/metadataTypes/TransactionalMessage.js | 5 +-
.../TransactionalEmail.definition.js | 20 +++-
...isting_temail.transactionalEmail-meta.json | 7 +-
...estNew_temail.transactionalEmail-meta.json | 7 +-
.../v1/email/definitions/post-response.json | 2 +-
.../testExisting_temail/delete-response.json | 6 +
.../transactionalEmail/build-expected.json | 10 +-
.../transactionalEmail/get-expected.json | 10 +-
.../transactionalEmail/patch-expected.json | 10 +-
.../transactionalEmail/post-expected.json | 10 +-
.../transactionalEmail/template-expected.json | 10 +-
test/type.transactionalEmail.test.js | 23 ++--
14 files changed, 193 insertions(+), 80 deletions(-)
create mode 100644 test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/delete-response.json
diff --git a/docs/dist/documentation.md b/docs/dist/documentation.md
index 1bffd85d8..4b89a1cf6 100644
--- a/docs/dist/documentation.md
+++ b/docs/dist/documentation.md
@@ -5454,7 +5454,10 @@ TransactionalEmail MetadataType
* [TransactionalEmail](#TransactionalEmail) ⇐ [TransactionalMessage
](#TransactionalMessage)
* [.update(metadata)](#TransactionalEmail.update) ⇒ Promise
* [.preDeployTasks(metadata)](#TransactionalEmail.preDeployTasks) ⇒ TYPE.MetadataTypeItem
+ * [.postCreateTasks(_, apiResponse)](#TransactionalEmail.postCreateTasks) ⇒ void
+ * [.postDeployTasks()](#TransactionalEmail.postDeployTasks) ⇒ void
* [.postRetrieveTasks(metadata)](#TransactionalEmail.postRetrieveTasks) ⇒ TYPE.MetadataTypeItem
+ * [.deleteByKey(key)](#TransactionalEmail.deleteByKey) ⇒ Promise.<boolean>
@@ -5480,6 +5483,24 @@ prepares for deployment
| --- | --- | --- |
| metadata | TYPE.MetadataTypeItem
| a single item |
+
+
+### TransactionalEmail.postCreateTasks(_, apiResponse) ⇒ void
+helper for [TransactionalEmail.createREST](TransactionalEmail.createREST)
+
+**Kind**: static method of [TransactionalEmail
](#TransactionalEmail)
+
+| Param | Type | Description |
+| --- | --- | --- |
+| _ | TYPE.MetadataTypeItem
| not used |
+| apiResponse | object
| varies depending on the API call |
+
+
+
+### TransactionalEmail.postDeployTasks() ⇒ void
+Gets executed after deployment of metadata type
+
+**Kind**: static method of [TransactionalEmail
](#TransactionalEmail)
### TransactionalEmail.postRetrieveTasks(metadata) ⇒ TYPE.MetadataTypeItem
@@ -5492,6 +5513,18 @@ manages post retrieve steps
| --- | --- | --- |
| metadata | TYPE.MetadataTypeItem
| a single item |
+
+
+### TransactionalEmail.deleteByKey(key) ⇒ Promise.<boolean>
+Delete a metadata item from the specified business unit
+
+**Kind**: static method of [TransactionalEmail
](#TransactionalEmail)
+**Returns**: Promise.<boolean>
- deletion success status
+
+| Param | Type | Description |
+| --- | --- | --- |
+| key | string
| Identifier of item |
+
## TransactionalMessage ⇐ [MetadataType
](#MetadataType)
@@ -5502,7 +5535,7 @@ TransactionalMessage MetadataType
* [TransactionalMessage](#TransactionalMessage) ⇐ [MetadataType
](#MetadataType)
* [.retrieve(retrieveDir, [_], [__], [key])](#TransactionalMessage.retrieve) ⇒ Promise.<TYPE.MetadataTypeMapObj>
- * [.retrieveForCache()](#TransactionalMessage.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
+ * [.retrieveForCache([key])](#TransactionalMessage.retrieveForCache) ⇒ Promise.<TYPE.MetadataTypeMapObj>
* [.update(metadata)](#TransactionalMessage.update) ⇒ Promise
* [.create(metadata)](#TransactionalMessage.create) ⇒ Promise
* [.deleteByKey(key)](#TransactionalMessage.deleteByKey) ⇒ Promise.<boolean>
@@ -5524,11 +5557,16 @@ Retrieves Metadata
-### TransactionalMessage.retrieveForCache() ⇒ Promise.<TYPE.MetadataTypeMapObj>
+### TransactionalMessage.retrieveForCache([key]) ⇒ Promise.<TYPE.MetadataTypeMapObj>
Retrieves event definition metadata for caching
**Kind**: static method of [TransactionalMessage
](#TransactionalMessage)
**Returns**: Promise.<TYPE.MetadataTypeMapObj>
- Promise of metadata
+
+| Param | Type | Description |
+| --- | --- | --- |
+| [key] | string
| customer key of single item to cache |
+
### TransactionalMessage.update(metadata) ⇒ Promise
diff --git a/lib/metadataTypes/TransactionalEmail.js b/lib/metadataTypes/TransactionalEmail.js
index 560bfdc61..c17b91410 100644
--- a/lib/metadataTypes/TransactionalEmail.js
+++ b/lib/metadataTypes/TransactionalEmail.js
@@ -40,21 +40,24 @@ class TransactionalEmail extends TransactionalMessage {
*/
static async preDeployTasks(metadata) {
// asset
- if (metadata.content?.customerKey) {
+ if (metadata.r__asset_customerKey) {
// we merely want to be able to show an error if it does not exist
- cache.searchForField(
- 'asset',
- metadata.content.customerKey,
- 'customerKey',
- 'customerKey'
- );
+ metadata.content = {
+ customerKey: cache.searchForField(
+ 'asset',
+ metadata.r__asset_customerKey,
+ 'customerKey',
+ 'customerKey'
+ ),
+ };
+ delete metadata.r__asset_customerKey;
}
// subscriptions: dataExtension
- if (metadata.subscriptions?.dataExtension) {
+ if (metadata.subscriptions?.r__dataExtension_CustomerKey) {
// we merely want to be able to show an error if it does not exist
- cache.searchForField(
+ metadata.subscriptions.dataExtension = cache.searchForField(
'dataExtension',
- metadata.subscriptions.dataExtension,
+ metadata.subscriptions.r__dataExtension_CustomerKey,
'CustomerKey',
'CustomerKey'
);
@@ -69,15 +72,49 @@ class TransactionalEmail extends TransactionalMessage {
}
// journey
- if (metadata.journey?.interactionKey) {
- // ! update & create enpoints dont accept journey.interactionKey. They only allow to create a new journey
- metadata.options ||= {};
- metadata.options.createJourney = true; // only send this during create or else we might end up with an unexpected outcome
- delete metadata.journey.interactionKey;
- }
+ // ! update & create enpoints dont accept journey.interactionKey. They only allow to create a new journey
+ metadata.options ||= {};
+ metadata.options.createJourney = true; // only send this during create or else we might end up with an unexpected outcome
return metadata;
}
+ /**
+ * helper for {@link TransactionalEmail.createREST}
+ *
+ * @param {TYPE.MetadataTypeItem} _ not used
+ * @param {object} apiResponse varies depending on the API call
+ * @returns {void}
+ */
+ static async postCreateTasks(_, apiResponse) {
+ if (apiResponse.journey?.interactionKey) {
+ Util.logger.warn(
+ ` - created journey: ${apiResponse.journey.interactionKey} (auto-created when ${this.definition.type} ${apiResponse.definitionKey} was created)`
+ );
+ // when we create new transactionalEmails, we should also download the new journey that was created with it
+ this._createdJourneyKeys ||= [];
+ this._createdJourneyKeys.push(apiResponse.journey?.interactionKey);
+
+ // do what postRetrieveTasks won't be able to do without spending lots of time on caching
+ apiResponse.r__journey_key = apiResponse.journey.interactionKey;
+ delete apiResponse.journey;
+ }
+ }
+ /**
+ * Gets executed after deployment of metadata type
+ *
+ * @returns {void}
+ */
+ static postDeployTasks() {
+ if (this._createdJourneyKeys?.length) {
+ Util.logger.warn(
+ `Please download related journeys via: mcdev r ${this.buObject.credential}/${
+ this.buObject.businessUnit
+ } journey "${this._createdJourneyKeys.join(',')}"`
+ );
+ }
+ delete this._createdJourneyKeys;
+ }
+
/**
* manages post retrieve steps
*
@@ -87,6 +124,7 @@ class TransactionalEmail extends TransactionalMessage {
static postRetrieveTasks(metadata) {
// asset
if (metadata.content?.customerKey) {
+ metadata.r__asset_customerKey = metadata.content.customerKey;
try {
// we merely want to be able to show an error if it does not exist
cache.searchForField(
@@ -102,17 +140,20 @@ class TransactionalEmail extends TransactionalMessage {
}): ${ex.message}.`
);
}
+ delete metadata.content;
}
+
// subscriptions: dataExtension
if (metadata.subscriptions?.dataExtension) {
try {
// we merely want to be able to show a warning if it does not exist
- cache.searchForField(
+ metadata.subscriptions.r__dataExtension_CustomerKey = cache.searchForField(
'dataExtension',
metadata.subscriptions.dataExtension,
'CustomerKey',
'CustomerKey'
);
+ delete metadata.subscriptions.dataExtension;
} catch (ex) {
Util.logger.warn(
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
@@ -140,9 +181,15 @@ class TransactionalEmail extends TransactionalMessage {
}
// journey
if (metadata.journey?.interactionKey) {
+ metadata.r__journey_key = metadata.journey.interactionKey;
try {
// we merely want to be able to show a warning if it does not exist
- cache.searchForField('journey', metadata.journey.interactionKey, 'key', 'key');
+ metadata.r__journey_key = cache.searchForField(
+ 'journey',
+ metadata.journey.interactionKey,
+ 'key',
+ 'key'
+ );
} catch (ex) {
Util.logger.warn(
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
@@ -150,10 +197,38 @@ class TransactionalEmail extends TransactionalMessage {
}): ${ex.message}.`
);
}
+ delete metadata.journey;
}
return metadata;
}
+ /**
+ * Delete a metadata item from the specified business unit
+ *
+ * @param {string} key Identifier of item
+ * @returns {Promise.} deletion success status
+ */
+ static async deleteByKey(key) {
+ const metadataMapObj = await this.retrieveForCache(key);
+ const journeyKey = metadataMapObj?.metadata?.[key]?.journey?.interactionKey;
+
+ const isDeleted = await super.deleteByKeyREST(
+ '/messaging/v1/' + this.subType + '/definitions/' + key,
+ key,
+ false
+ );
+ if (isDeleted && journeyKey) {
+ const Journey = require('./Journey');
+ Util.logger.info(
+ ` - deleted ${Journey.definition.type}: ${journeyKey} (SFMC auto-deletes the related journey of ${this.definition.type} ${key})`
+ );
+ Journey.buObject = this.buObject;
+ Journey.properties = this.properties;
+ Journey.client = this.client;
+ Journey.postDeleteTasks(journeyKey);
+ }
+ return isDeleted;
+ }
}
// Assign definition to static attributes
diff --git a/lib/metadataTypes/TransactionalMessage.js b/lib/metadataTypes/TransactionalMessage.js
index 58587d7db..212967687 100644
--- a/lib/metadataTypes/TransactionalMessage.js
+++ b/lib/metadataTypes/TransactionalMessage.js
@@ -67,13 +67,14 @@ class TransactionalMessage extends MetadataType {
/**
* Retrieves event definition metadata for caching
*
+ * @param {string} [key] customer key of single item to cache
* @returns {Promise.} Promise of metadata
*/
- static retrieveForCache() {
+ static retrieveForCache(key) {
// the call to /messaging/v1/email/definitions/ does not return definitionId
// definitionId is required for resolving dependencies on interactions.
// we should therefore use the already defined retrieve method
- return this.retrieve();
+ return this.retrieve(undefined, undefined, undefined, key);
}
/**
* Updates a single item
diff --git a/lib/metadataTypes/definitions/TransactionalEmail.definition.js b/lib/metadataTypes/definitions/TransactionalEmail.definition.js
index 1901433f0..be417d221 100644
--- a/lib/metadataTypes/definitions/TransactionalEmail.definition.js
+++ b/lib/metadataTypes/definitions/TransactionalEmail.definition.js
@@ -83,6 +83,12 @@ module.exports = {
retrieving: true,
template: true,
},
+ 'subscriptions.r__dataExtension_CustomerKey': {
+ isCreateable: false,
+ isUpdateable: false,
+ retrieving: true,
+ template: true,
+ },
'subscriptions.list': {
isCreateable: true,
isUpdateable: true,
@@ -127,7 +133,7 @@ module.exports = {
},
'options.createJourney': {
isCreateable: true,
- isUpdateable: true,
+ isUpdateable: false,
retrieving: false,
template: false,
},
@@ -143,5 +149,17 @@ module.exports = {
retrieving: true,
template: true,
},
+ r__asset_customerKey: {
+ isCreateable: false,
+ isUpdateable: false,
+ retrieving: true,
+ template: true,
+ },
+ r__journey_key: {
+ isCreateable: false,
+ isUpdateable: false,
+ retrieving: true,
+ template: true,
+ },
},
};
diff --git a/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json b/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json
index d402194ac..777a3cc15 100644
--- a/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json
+++ b/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json
@@ -6,9 +6,6 @@
"status": "Active",
"createdDate": "2020-09-10T03:29:00",
"modifiedDate": "2020-09-10T03:29:00",
- "content": {
- "customerKey": "testExisting_asset_message"
- },
"subscriptions": {
"dataExtension": "testExisting_dataExtension",
"autoAddSubscriber": true,
@@ -17,5 +14,7 @@
},
"options": {
"trackLinks": true
- }
+ },
+ "r__journey_key": "testExisting_interaction",
+ "r__asset_customerKey": "testExisting_asset_message"
}
diff --git a/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json b/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json
index 64b780e9b..197e9f902 100644
--- a/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json
+++ b/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json
@@ -6,9 +6,6 @@
"status": "Active",
"createdDate": "2020-09-10T03:29:00",
"modifiedDate": "2020-09-10T03:29:00",
- "content": {
- "customerKey": "testExisting_asset_message"
- },
"subscriptions": {
"dataExtension": "testExisting_dataExtension",
"autoAddSubscriber": true,
@@ -18,7 +15,5 @@
"options": {
"trackLinks": true
},
- "journey": {
- "interactionKey": "testExisting_interaction"
- }
+ "r__asset_customerKey": "testExisting_asset_message"
}
diff --git a/test/resources/9999999/messaging/v1/email/definitions/post-response.json b/test/resources/9999999/messaging/v1/email/definitions/post-response.json
index 0278ba775..080bde8b5 100644
--- a/test/resources/9999999/messaging/v1/email/definitions/post-response.json
+++ b/test/resources/9999999/messaging/v1/email/definitions/post-response.json
@@ -15,5 +15,5 @@
"updateSubscriber": true
},
"options": { "trackLinks": true },
- "journey": { "interactionKey": "testExisting_interaction" }
+ "journey": { "interactionKey": "testNew_RANDOM_interaction" }
}
diff --git a/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/delete-response.json b/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/delete-response.json
new file mode 100644
index 000000000..37a29e379
--- /dev/null
+++ b/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/delete-response.json
@@ -0,0 +1,6 @@
+{
+ "requestId": "b6ad9f29-1ea4-486d-b826-e3dda072bbcd",
+ "message": "Success",
+ "deletedDefinitionKey": "1b24da84-7e55-47cb-a190-585a3b49da20",
+ "journey": {}
+}
diff --git a/test/resources/9999999/transactionalEmail/build-expected.json b/test/resources/9999999/transactionalEmail/build-expected.json
index f9417a65c..bbc27cc4a 100644
--- a/test/resources/9999999/transactionalEmail/build-expected.json
+++ b/test/resources/9999999/transactionalEmail/build-expected.json
@@ -4,11 +4,8 @@
"description": "foobar",
"classification": "Default Transactional",
"status": "Active",
- "content": {
- "customerKey": "testTemplated_asset_message"
- },
"subscriptions": {
- "dataExtension": "testTemplated_dataExtension",
+ "r__dataExtension_CustomerKey": "testTemplated_dataExtension",
"autoAddSubscriber": true,
"updateSubscriber": true,
"r__list_PathName": "my subscribers/All Subscribers"
@@ -16,7 +13,6 @@
"options": {
"trackLinks": true
},
- "journey": {
- "interactionKey": "testTemplated_interaction"
- }
+ "r__asset_customerKey": "testTemplated_asset_message",
+ "r__journey_key": "testTemplated_interaction"
}
diff --git a/test/resources/9999999/transactionalEmail/get-expected.json b/test/resources/9999999/transactionalEmail/get-expected.json
index 2bb3340b2..4cfc61fa2 100644
--- a/test/resources/9999999/transactionalEmail/get-expected.json
+++ b/test/resources/9999999/transactionalEmail/get-expected.json
@@ -6,11 +6,8 @@
"status": "Active",
"createdDate": "2020-09-10T03:29:00",
"modifiedDate": "2020-09-10T03:29:00",
- "content": {
- "customerKey": "testExisting_asset_message"
- },
"subscriptions": {
- "dataExtension": "testExisting_dataExtension",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtension",
"autoAddSubscriber": true,
"updateSubscriber": true,
"r__list_PathName": "my subscribers/All Subscribers"
@@ -18,7 +15,6 @@
"options": {
"trackLinks": true
},
- "journey": {
- "interactionKey": "testExisting_interaction"
- }
+ "r__asset_customerKey": "testExisting_asset_message",
+ "r__journey_key": "testExisting_interaction"
}
diff --git a/test/resources/9999999/transactionalEmail/patch-expected.json b/test/resources/9999999/transactionalEmail/patch-expected.json
index 8028dfeb8..18fb2d317 100644
--- a/test/resources/9999999/transactionalEmail/patch-expected.json
+++ b/test/resources/9999999/transactionalEmail/patch-expected.json
@@ -6,11 +6,8 @@
"status": "Active",
"createdDate": "2020-09-10T03:29:00",
"modifiedDate": "2020-09-10T03:29:00",
- "content": {
- "customerKey": "testExisting_asset_message"
- },
"subscriptions": {
- "dataExtension": "testExisting_dataExtension",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtension",
"autoAddSubscriber": true,
"updateSubscriber": true,
"r__list_PathName": "my subscribers/All Subscribers"
@@ -18,7 +15,6 @@
"options": {
"trackLinks": true
},
- "journey": {
- "interactionKey": "testExisting_interaction"
- }
+ "r__asset_customerKey": "testExisting_asset_message",
+ "r__journey_key": "testExisting_interaction"
}
diff --git a/test/resources/9999999/transactionalEmail/post-expected.json b/test/resources/9999999/transactionalEmail/post-expected.json
index e806ee1e3..e6070aa31 100644
--- a/test/resources/9999999/transactionalEmail/post-expected.json
+++ b/test/resources/9999999/transactionalEmail/post-expected.json
@@ -6,11 +6,8 @@
"status": "Active",
"createdDate": "2022-12-06T06:08:00",
"modifiedDate": "2022-12-06T06:08:00",
- "content": {
- "customerKey": "testExisting_asset_message"
- },
"subscriptions": {
- "dataExtension": "testExisting_dataExtension",
+ "r__dataExtension_CustomerKey": "testExisting_dataExtension",
"autoAddSubscriber": true,
"updateSubscriber": true,
"r__list_PathName": "my subscribers/All Subscribers"
@@ -18,7 +15,6 @@
"options": {
"trackLinks": true
},
- "journey": {
- "interactionKey": "testExisting_interaction"
- }
+ "r__asset_customerKey": "testExisting_asset_message",
+ "r__journey_key": "testNew_RANDOM_interaction"
}
diff --git a/test/resources/9999999/transactionalEmail/template-expected.json b/test/resources/9999999/transactionalEmail/template-expected.json
index 26e75265a..b32da26a4 100644
--- a/test/resources/9999999/transactionalEmail/template-expected.json
+++ b/test/resources/9999999/transactionalEmail/template-expected.json
@@ -4,11 +4,8 @@
"description": "{{{description}}}",
"classification": "Default Transactional",
"status": "Active",
- "content": {
- "customerKey": "{{{prefix}}}asset_message"
- },
"subscriptions": {
- "dataExtension": "{{{prefix}}}dataExtension",
+ "r__dataExtension_CustomerKey": "{{{prefix}}}dataExtension",
"autoAddSubscriber": true,
"updateSubscriber": true,
"r__list_PathName": "my subscribers/All Subscribers"
@@ -16,7 +13,6 @@
"options": {
"trackLinks": true
},
- "journey": {
- "interactionKey": "{{{prefix}}}interaction"
- }
+ "r__asset_customerKey": "{{{prefix}}}asset_message",
+ "r__journey_key": "{{{prefix}}}interaction"
}
diff --git a/test/type.transactionalEmail.test.js b/test/type.transactionalEmail.test.js
index 6a22f9d5d..996095a36 100644
--- a/test/type.transactionalEmail.test.js
+++ b/test/type.transactionalEmail.test.js
@@ -142,17 +142,18 @@ describe('type: transactionalEmail', () => {
});
});
describe('Delete ================', () => {
- // TODO: add this test
- it('Should delete the item'); // , async () => {
- // // WHEN
- // const result = await handler.deleteByKey('testInstance/testBU', 'mobileKeyword', [
- // 'testExisting_keyword',
- // ]);
- // // THEN
- // assert.equal(process.exitCode, false, 'delete should not have thrown an error');
+ it('Should delete the item', async () => {
+ // WHEN
+ const isDeleted = await handler.deleteByKey(
+ 'testInstance/testBU',
+ 'transactionalEmail',
+ 'testExisting_temail'
+ );
+ // THEN
+ assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- // assert.equal(result, true, 'should have deleted the item');
- // return;
- // });
+ assert.equal(isDeleted, true, 'should have deleted the item');
+ return;
+ });
});
});
From 7c74e14dc266bb7d721e2fe6a5b5b4c634bfa5a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 25 Aug 2023 14:19:49 +0200
Subject: [PATCH 57/70] #0: refactoring
---
test/type.transactionalPush.test.js | 6 ++----
test/type.transactionalSMS.test.js | 6 ++----
2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/test/type.transactionalPush.test.js b/test/type.transactionalPush.test.js
index 4dcfb8a4f..16f8222ea 100644
--- a/test/type.transactionalPush.test.js
+++ b/test/type.transactionalPush.test.js
@@ -146,13 +146,11 @@ describe('type: transactionalPush', () => {
// TODO: add this test
it('Should delete the item'); // , async () => {
// // WHEN
- // const result = await handler.deleteByKey('testInstance/testBU', 'mobileKeyword', [
- // 'testExisting_keyword',
- // ]);
+ // const isDeleted = await handler.deleteByKey('testInstance/testBU', 'mobileKeyword', 'testExisting_keyword');
// // THEN
// assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- // assert.equal(result, true, 'should have deleted the item');
+ // assert.equal(isDeleted, true, 'should have deleted the item');
// return;
// });
});
diff --git a/test/type.transactionalSMS.test.js b/test/type.transactionalSMS.test.js
index ad083caf5..8e9d44dde 100644
--- a/test/type.transactionalSMS.test.js
+++ b/test/type.transactionalSMS.test.js
@@ -176,13 +176,11 @@ describe('type: transactionalSMS', () => {
// TODO: add this test
it('Should delete the item'); // , async () => {
// // WHEN
- // const result = await handler.deleteByKey('testInstance/testBU', 'mobileKeyword', [
- // 'testExisting_keyword',
- // ]);
+ // const isDeleted = await handler.deleteByKey('testInstance/testBU', 'mobileKeyword', 'testExisting_keyword');
// // THEN
// assert.equal(process.exitCode, false, 'delete should not have thrown an error');
- // assert.equal(result, true, 'should have deleted the item');
+ // assert.equal(isDeleted, true, 'should have deleted the item');
// return;
// });
});
From 34a44879ab6b0beb23e571e62196d3dd01b5e7a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 25 Aug 2023 14:49:40 +0200
Subject: [PATCH 58/70] #325: ensure r__dataExtension_CustomerKey is set even
if related dataExtension cannot be found
---
lib/metadataTypes/TransactionalEmail.js | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/metadataTypes/TransactionalEmail.js b/lib/metadataTypes/TransactionalEmail.js
index c17b91410..9592f1921 100644
--- a/lib/metadataTypes/TransactionalEmail.js
+++ b/lib/metadataTypes/TransactionalEmail.js
@@ -145,15 +145,16 @@ class TransactionalEmail extends TransactionalMessage {
// subscriptions: dataExtension
if (metadata.subscriptions?.dataExtension) {
+ metadata.subscriptions.r__dataExtension_CustomerKey =
+ metadata.subscriptions.dataExtension;
try {
// we merely want to be able to show a warning if it does not exist
- metadata.subscriptions.r__dataExtension_CustomerKey = cache.searchForField(
+ cache.searchForField(
'dataExtension',
metadata.subscriptions.dataExtension,
'CustomerKey',
'CustomerKey'
);
- delete metadata.subscriptions.dataExtension;
} catch (ex) {
Util.logger.warn(
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
@@ -161,6 +162,7 @@ class TransactionalEmail extends TransactionalMessage {
}): ${ex.message}.`
);
}
+ delete metadata.subscriptions.dataExtension;
}
// subscriptions: list
if (metadata.subscriptions?.list) {
From 37237b4c18c80af6c72641689f05d086c863c2af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Fri, 25 Aug 2023 15:50:34 +0200
Subject: [PATCH 59/70] #325: ensure generated verification keys get used
during joint deployment of automation and verification
---
lib/metadataTypes/Automation.js | 18 +++++++++++++++++
lib/metadataTypes/Verification.js | 9 +++++++++
.../testNew_automation.automation-meta.json | 4 ++++
.../9999999/automation/create-expected.json | 4 ++++
.../create-testNew_automation-expected.md | 1 +
.../v1/automations/post-response.json | 7 +++++++
test/type.automation.test.js | 20 +++++++++++--------
7 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/lib/metadataTypes/Automation.js b/lib/metadataTypes/Automation.js
index 992ca8ed4..a1b05b884 100644
--- a/lib/metadataTypes/Automation.js
+++ b/lib/metadataTypes/Automation.js
@@ -814,6 +814,7 @@ class Automation extends MetadataType {
delete metadata.schedule;
delete metadata.type;
let i = 0;
+ const buName = this.buObject.credential + '/' + this.buObject.businessUnit;
if (metadata.steps) {
for (const step of metadata.steps) {
let displayOrder = 0;
@@ -823,6 +824,23 @@ class Automation extends MetadataType {
activity.name &&
this.definition.dependencies.includes(activity.r__type)
) {
+ if (
+ activity.r__type === 'verification' &&
+ this.createdKeyMap?.[buName]?.verification?.[activity.name]
+ ) {
+ Util.logger.info(
+ Util.getGrayMsg(
+ ` - updated verification activity name from ${
+ activity.name
+ } to ${
+ this.createdKeyMap[buName].verification[activity.name]
+ }`
+ )
+ );
+ // map structure: cred/bu --> type --> old key --> new key
+ activity.name =
+ this.createdKeyMap[buName].verification[activity.name];
+ }
// automations can have empty placeholder for activities with only their type defined
activity.activityObjectId = cache.searchForField(
activity.r__type,
diff --git a/lib/metadataTypes/Verification.js b/lib/metadataTypes/Verification.js
index 891b9382f..93ce29fd0 100644
--- a/lib/metadataTypes/Verification.js
+++ b/lib/metadataTypes/Verification.js
@@ -151,6 +151,15 @@ class Verification extends MetadataType {
} automatically assigned during creation`
);
metadataEntry[this.definition.idField] = apiResponse?.[this.definition.idField];
+
+ // map structure: cred/bu --> type --> old key --> new key
+ const buName = this.buObject.credential + '/' + this.buObject.businessUnit;
+ Automation.createdKeyMap ||= {};
+ Automation.createdKeyMap[buName] ||= {};
+ Automation.createdKeyMap[buName][this.definition.type] ||= {};
+ Automation.createdKeyMap[buName][this.definition.type][
+ metadataEntryWithAllFields[this.definition.idField]
+ ] = metadataEntry[this.definition.idField];
}
/**
diff --git a/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json b/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json
index 715b69f27..e27ad3c97 100644
--- a/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json
+++ b/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json
@@ -36,6 +36,10 @@
{
"name": "testExisting_script",
"r__type": "script"
+ },
+ {
+ "name": "testNew_39f6a488-20eb-4ba0-b0b9",
+ "r__type": "verification"
}
],
"name": ""
diff --git a/test/resources/9999999/automation/create-expected.json b/test/resources/9999999/automation/create-expected.json
index 92ea826e1..794e0dff7 100644
--- a/test/resources/9999999/automation/create-expected.json
+++ b/test/resources/9999999/automation/create-expected.json
@@ -37,6 +37,10 @@
{
"name": "testExisting_script",
"r__type": "script"
+ },
+ {
+ "name": "testNew_RANDOM_NEW_GUID",
+ "r__type": "verification"
}
],
"name": ""
diff --git a/test/resources/9999999/automation/create-testNew_automation-expected.md b/test/resources/9999999/automation/create-testNew_automation-expected.md
index ce52ff454..d9a7fe86c 100644
--- a/test/resources/9999999/automation/create-testNew_automation-expected.md
+++ b/test/resources/9999999/automation/create-testNew_automation-expected.md
@@ -26,3 +26,4 @@
| _1.4: importFile_ testExisting_importFile |
| _1.5: query_ testExisting_query |
| _1.6: script_ testExisting_script |
+| _1.7: verification_ testNew_RANDOM_NEW_GUID |
diff --git a/test/resources/9999999/automation/v1/automations/post-response.json b/test/resources/9999999/automation/v1/automations/post-response.json
index ba11ebf1e..bacde7613 100644
--- a/test/resources/9999999/automation/v1/automations/post-response.json
+++ b/test/resources/9999999/automation/v1/automations/post-response.json
@@ -77,6 +77,13 @@
"activityObjectId": "39f6a488-20eb-4ba0-b0b9-023725b574e4",
"objectTypeId": 423,
"displayOrder": 6
+ },
+ {
+ "id": "f3774dc2-a271-4a44-8cbe-f630a6d6545e",
+ "name": "testExisting_dataExtension",
+ "activityObjectId": "testNew_RANDOM_NEW_GUID",
+ "objectTypeId": 1000,
+ "displayOrder": 7
}
],
"annotation": "",
diff --git a/test/type.automation.test.js b/test/type.automation.test.js
index 4a1acb0b7..b85ac4473 100644
--- a/test/type.automation.test.js
+++ b/test/type.automation.test.js
@@ -61,7 +61,11 @@ describe('type: automation', () => {
});
it('Should create & update a automation', async () => {
// WHEN
- const deployResult = await handler.deploy('testInstance/testBU', ['automation']);
+ const deployResult = await handler.deploy(
+ 'testInstance/testBU',
+ ['automation', 'verification'],
+ ['testExisting_automation', 'testNew_automation', 'testNew_39f6a488-20eb-4ba0-b0b9']
+ );
// THEN
assert.equal(process.exitCode, false, 'deploy should not have thrown an error');
@@ -119,7 +123,7 @@ describe('type: automation', () => {
assert.equal(
testUtils.getAPIHistoryLength(),
- 21,
+ 25,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -129,8 +133,8 @@ describe('type: automation', () => {
handler.setOptions({ schedule: true });
const deployed = await handler.deploy(
'testInstance/testBU',
- ['automation'],
- ['testExisting_automation', 'testNew_automation']
+ ['automation', 'verification'],
+ ['testExisting_automation', 'testNew_automation', 'testNew_39f6a488-20eb-4ba0-b0b9']
);
// THEN
assert.equal(
@@ -188,7 +192,7 @@ describe('type: automation', () => {
assert.equal(
testUtils.getAPIHistoryLength(),
- 29,
+ 33,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
@@ -198,8 +202,8 @@ describe('type: automation', () => {
handler.setOptions({ execute: true });
const deployed = await handler.deploy(
'testInstance/testBU',
- ['automation'],
- ['testExisting_automation', 'testNew_automation']
+ ['automation', 'verification'],
+ ['testExisting_automation', 'testNew_automation', 'testNew_39f6a488-20eb-4ba0-b0b9']
);
// THEN
assert.equal(
@@ -256,7 +260,7 @@ describe('type: automation', () => {
assert.equal(
testUtils.getAPIHistoryLength(),
- 25,
+ 29,
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
);
return;
From 5ac58b38bafc6fd0db496e1d349a5bfb0c41c0c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Mon, 28 Aug 2023 09:49:41 +0200
Subject: [PATCH 60/70] #325: type verification renamed
---
lib/metadataTypes/definitions/Verification.definition.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/metadataTypes/definitions/Verification.definition.js b/lib/metadataTypes/definitions/Verification.definition.js
index 25e63ac5d..cbcad30c9 100644
--- a/lib/metadataTypes/definitions/Verification.definition.js
+++ b/lib/metadataTypes/definitions/Verification.definition.js
@@ -15,7 +15,7 @@ module.exports = {
type: 'verification',
typeDescription: 'Check DataExtension for a row count',
typeRetrieveByDefault: true,
- typeName: 'Automation: Data Verification Activity',
+ typeName: 'Automation: Verification Activity',
fields: {
createdBy: {
// User ID
From 0faad87c87c77c4981bd2359fe16829a919bfc48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Mon, 28 Aug 2023 15:53:16 +0200
Subject: [PATCH 61/70] #1088: ensure multi-BU retrieves do not interact badly
with each other
---
lib/metadataTypes/AttributeSet.js | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/lib/metadataTypes/AttributeSet.js b/lib/metadataTypes/AttributeSet.js
index 575531ee7..0a782c18c 100644
--- a/lib/metadataTypes/AttributeSet.js
+++ b/lib/metadataTypes/AttributeSet.js
@@ -345,8 +345,11 @@ class AttributeSet extends MetadataType {
* @returns {object[]} all system value definitions
*/
static _getSystemValueDefinitions() {
- if (!this.systemValueDefinitions) {
- this.systemValueDefinitions = Object.values(cache.getCache()['attributeSet'])
+ this.systemValueDefinitions ||= {};
+ if (!this.systemValueDefinitions[this.buObject.mid]) {
+ this.systemValueDefinitions[this.buObject.mid] = Object.values(
+ cache.getCache()['attributeSet']
+ )
.flatMap((item) => {
if (item.isSystemDefined) {
return item.valueDefinitions;
@@ -354,7 +357,7 @@ class AttributeSet extends MetadataType {
})
.filter(Boolean);
}
- return this.systemValueDefinitions;
+ return this.systemValueDefinitions[this.buObject.mid];
}
}
From 7551affaafd7d31fbd8a356211cd529dfff91478 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Mon, 28 Aug 2023 15:55:44 +0200
Subject: [PATCH 62/70] #0: reduce chatter in log files
---
lib/metadataTypes/DataExtension.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 6e96f463b..07dfe3637 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -835,9 +835,9 @@ class DataExtension extends MetadataType {
this.buObject.eid
);
if (!folderTypesFromParent.includes(folderContentType)) {
- Util.logger.verbose(
- `removing ${metadataEntry} because r__folder_ContentType '${folderContentType}' identifies this DE as not being shared`
- );
+ // Util.logger.verbose(
+ // `removing ${metadataEntry} because r__folder_ContentType '${folderContentType}' identifies this DE as not being shared`
+ // );
delete metadataParentBu[metadataEntry];
}
} catch (ex) {
From 4422bb61017200b3473a446aaaa21c3e0b80303d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 28 Aug 2023 20:54:21 +0000
Subject: [PATCH 63/70] Bump eslint from 8.47.0 to 8.48.0
Bumps [eslint](https://github.com/eslint/eslint) from 8.47.0 to 8.48.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.47.0...v8.48.0)
---
updated-dependencies:
- dependency-name: eslint
dependency-type: direct:development
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
---
package-lock.json | 31 +++++++++++++++----------------
package.json | 2 +-
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f035492e1..5f99b6ef7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,7 +16,6 @@
"console.table": "0.10.0",
"deep-equal": "2.2.2",
"fs-extra": "11.1.0",
- "fsevents": "*",
"inquirer": "8.2.6",
"json-to-table": "4.2.1",
"mustache": "4.2.0",
@@ -39,7 +38,7 @@
"axios-mock-adapter": "1.21.5",
"chai": "4.3.7",
"chai-files": "1.4.0",
- "eslint": "8.47.0",
+ "eslint": "8.48.0",
"eslint-config-prettier": "9.0.0",
"eslint-config-ssjs": "1.1.11",
"eslint-plugin-jsdoc": "46.5.0",
@@ -600,9 +599,9 @@
"dev": true
},
"node_modules/@eslint/js": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz",
- "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz",
+ "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -3139,15 +3138,15 @@
}
},
"node_modules/eslint": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz",
- "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz",
+ "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2",
- "@eslint/js": "^8.47.0",
+ "@eslint/js": "8.48.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -10504,9 +10503,9 @@
}
},
"@eslint/js": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz",
- "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz",
+ "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==",
"dev": true
},
"@humanwhocodes/config-array": {
@@ -12437,15 +12436,15 @@
"dev": true
},
"eslint": {
- "version": "8.47.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz",
- "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==",
+ "version": "8.48.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz",
+ "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2",
- "@eslint/js": "^8.47.0",
+ "@eslint/js": "8.48.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
diff --git a/package.json b/package.json
index 94eb5c31e..124288652 100644
--- a/package.json
+++ b/package.json
@@ -84,7 +84,7 @@
"axios-mock-adapter": "1.21.5",
"chai": "4.3.7",
"chai-files": "1.4.0",
- "eslint": "8.47.0",
+ "eslint": "8.48.0",
"eslint-config-prettier": "9.0.0",
"eslint-config-ssjs": "1.1.11",
"eslint-plugin-jsdoc": "46.5.0",
From b2620a32453d883776c47e2f388337dd8fa22d04 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 29 Aug 2023 07:43:31 +0000
Subject: [PATCH 64/70] Bump chai from 4.3.7 to 4.3.8
Bumps [chai](https://github.com/chaijs/chai) from 4.3.7 to 4.3.8.
- [Release notes](https://github.com/chaijs/chai/releases)
- [Changelog](https://github.com/chaijs/chai/blob/4.x.x/History.md)
- [Commits](https://github.com/chaijs/chai/compare/v4.3.7...v4.3.8)
---
updated-dependencies:
- dependency-name: chai
dependency-type: direct:development
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
package-lock.json | 14 +++++++-------
package.json | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 5f99b6ef7..86e352906 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -36,7 +36,7 @@
"devDependencies": {
"assert": "2.0.0",
"axios-mock-adapter": "1.21.5",
- "chai": "4.3.7",
+ "chai": "4.3.8",
"chai-files": "1.4.0",
"eslint": "8.48.0",
"eslint-config-prettier": "9.0.0",
@@ -1896,9 +1896,9 @@
}
},
"node_modules/chai": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
- "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
+ "version": "4.3.8",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.8.tgz",
+ "integrity": "sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==",
"dev": true,
"dependencies": {
"assertion-error": "^1.1.0",
@@ -11465,9 +11465,9 @@
}
},
"chai": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
- "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
+ "version": "4.3.8",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.8.tgz",
+ "integrity": "sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==",
"dev": true,
"requires": {
"assertion-error": "^1.1.0",
diff --git a/package.json b/package.json
index 124288652..804530c47 100644
--- a/package.json
+++ b/package.json
@@ -82,7 +82,7 @@
"devDependencies": {
"assert": "2.0.0",
"axios-mock-adapter": "1.21.5",
- "chai": "4.3.7",
+ "chai": "4.3.8",
"chai-files": "1.4.0",
"eslint": "8.48.0",
"eslint-config-prettier": "9.0.0",
From 15bcd9d8e991282deb820e7cf1daff2aee0441fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 31 Aug 2023 16:12:56 +0200
Subject: [PATCH 65/70] #1097: adapted tests to include fields of type Decimal
and Number as a baseline
---
.../9999999/dataExtension/build-expected.json | 16 ++++++++
.../dataExtension/retrieve-expected.json | 16 ++++++++
.../dataExtension/retrieve-expected.md | 4 +-
.../dataExtension/template-expected.json | 16 ++++++++
.../dataExtension/update-expected.json | 16 ++++++++
...ey=testExisting_dataExtension-response.xml | 37 ++++++++++++++++++-
.../dataExtensionField/retrieve-response.xml | 37 ++++++++++++++++++-
7 files changed, 139 insertions(+), 3 deletions(-)
diff --git a/test/resources/9999999/dataExtension/build-expected.json b/test/resources/9999999/dataExtension/build-expected.json
index f31d2e876..21d43fdbf 100644
--- a/test/resources/9999999/dataExtension/build-expected.json
+++ b/test/resources/9999999/dataExtension/build-expected.json
@@ -44,6 +44,22 @@
"IsRequired": true,
"IsPrimaryKey": true,
"FieldType": "Text"
+ },
+ {
+ "Name": "decimalField",
+ "DefaultValue": "",
+ "MaxLength": 6,
+ "Scale": 3,
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "FieldType": "Decimal"
+ },
+ {
+ "Name": "numberField",
+ "DefaultValue": "",
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "FieldType": "Number"
}
],
"r__folder_ContentType": "dataextension",
diff --git a/test/resources/9999999/dataExtension/retrieve-expected.json b/test/resources/9999999/dataExtension/retrieve-expected.json
index bf80cd122..c8c945cc3 100644
--- a/test/resources/9999999/dataExtension/retrieve-expected.json
+++ b/test/resources/9999999/dataExtension/retrieve-expected.json
@@ -44,6 +44,22 @@
"IsRequired": true,
"IsPrimaryKey": true,
"FieldType": "Text"
+ },
+ {
+ "Name": "decimalField",
+ "DefaultValue": "",
+ "MaxLength": 6,
+ "Scale": 3,
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "FieldType": "Decimal"
+ },
+ {
+ "Name": "numberField",
+ "DefaultValue": "",
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "FieldType": "Number"
}
],
"r__folder_ContentType": "dataextension",
diff --git a/test/resources/9999999/dataExtension/retrieve-expected.md b/test/resources/9999999/dataExtension/retrieve-expected.md
index fda321a2d..51cffe4b6 100644
--- a/test/resources/9999999/dataExtension/retrieve-expected.md
+++ b/test/resources/9999999/dataExtension/retrieve-expected.md
@@ -4,7 +4,7 @@
**Folder:** Data Extensions/
-**Fields in table:** 4
+**Fields in table:** 6
**Sendable:** Yes (`ContactKey` to `Subscriber Key`)
@@ -16,3 +16,5 @@
| LastName | Text | 50 | - | + | |
| EmailAddress | EmailAddress | 254 | - | - | |
| ContactKey | Text | 50 | + | - | |
+| decimalField | Decimal | 6 | - | - | |
+| numberField | Number | | - | - | |
diff --git a/test/resources/9999999/dataExtension/template-expected.json b/test/resources/9999999/dataExtension/template-expected.json
index 5c3cd96b7..c2513cfa0 100644
--- a/test/resources/9999999/dataExtension/template-expected.json
+++ b/test/resources/9999999/dataExtension/template-expected.json
@@ -44,6 +44,22 @@
"IsRequired": true,
"IsPrimaryKey": true,
"FieldType": "Text"
+ },
+ {
+ "Name": "decimalField",
+ "DefaultValue": "",
+ "MaxLength": 6,
+ "Scale": 3,
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "FieldType": "Decimal"
+ },
+ {
+ "Name": "numberField",
+ "DefaultValue": "",
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "FieldType": "Number"
}
],
"r__folder_ContentType": "dataextension",
diff --git a/test/resources/9999999/dataExtension/update-expected.json b/test/resources/9999999/dataExtension/update-expected.json
index bc10677a2..7106168c8 100644
--- a/test/resources/9999999/dataExtension/update-expected.json
+++ b/test/resources/9999999/dataExtension/update-expected.json
@@ -41,6 +41,22 @@
"IsPrimaryKey": true,
"FieldType": "Text"
},
+ {
+ "Name": "decimalField",
+ "DefaultValue": "",
+ "MaxLength": 6,
+ "Scale": 3,
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "FieldType": "Decimal"
+ },
+ {
+ "Name": "numberField",
+ "DefaultValue": "",
+ "IsPrimaryKey": false,
+ "IsRequired": true,
+ "FieldType": "Number"
+ },
{
"Name": "testField",
"DefaultValue": "",
diff --git a/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtension-response.xml b/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtension-response.xml
index 3ffc1b3eb..c927c2258 100644
--- a/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtension-response.xml
+++ b/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtension-response.xml
@@ -93,6 +93,41 @@
testExisting_dataExtension
+
+
+ 7b7ef009-4b85-455b-9bdf-b7bef93791d7
+ [testExisting_dataExtension].[numberField]
+ numberField
+ 0
+
+ true
+ 5
+ false
+ Number
+
+
+
+ testExisting_dataExtension
+
+
+
+
+ c5d553cc-2c2a-464d-953d-6901be040f20
+ [testExisting_dataExtension].[decimalField]
+ decimalField
+ 3
+
+ 6
+ true
+ 4
+ false
+ Decimal
+
+
+
+ testExisting_dataExtension
+
+
-
\ No newline at end of file
+
diff --git a/test/resources/9999999/dataExtensionField/retrieve-response.xml b/test/resources/9999999/dataExtensionField/retrieve-response.xml
index 3ffc1b3eb..c927c2258 100644
--- a/test/resources/9999999/dataExtensionField/retrieve-response.xml
+++ b/test/resources/9999999/dataExtensionField/retrieve-response.xml
@@ -93,6 +93,41 @@
testExisting_dataExtension
+
+
+ 7b7ef009-4b85-455b-9bdf-b7bef93791d7
+ [testExisting_dataExtension].[numberField]
+ numberField
+ 0
+
+ true
+ 5
+ false
+ Number
+
+
+
+ testExisting_dataExtension
+
+
+
+
+ c5d553cc-2c2a-464d-953d-6901be040f20
+ [testExisting_dataExtension].[decimalField]
+ decimalField
+ 3
+
+ 6
+ true
+ 4
+ false
+ Decimal
+
+
+
+ testExisting_dataExtension
+
+
-
\ No newline at end of file
+
From a64a66a4f9a05468d81e4f7d679ff432bec45d81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 31 Aug 2023 16:22:30 +0200
Subject: [PATCH 66/70] #1097: fixed decimal length documentation in
dataExtension markdowns
---
lib/metadataTypes/DataExtension.js | 6 +++++-
test/resources/9999999/dataExtension/retrieve-expected.md | 2 +-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/lib/metadataTypes/DataExtension.js b/lib/metadataTypes/DataExtension.js
index 07dfe3637..86fe9e342 100644
--- a/lib/metadataTypes/DataExtension.js
+++ b/lib/metadataTypes/DataExtension.js
@@ -1215,7 +1215,11 @@ class DataExtension extends MetadataType {
for (const element of fieldsJson) {
const newJsonElement = {};
for (const field of fieldsToKeep) {
- newJsonElement[field] = element[field];
+ if (field === 'MaxLength' && element.FieldType === 'Decimal') {
+ newJsonElement.MaxLength = `${element.MaxLength},${element.Scale}`;
+ } else {
+ newJsonElement[field] = element[field];
+ }
}
newJson.push(newJsonElement);
}
diff --git a/test/resources/9999999/dataExtension/retrieve-expected.md b/test/resources/9999999/dataExtension/retrieve-expected.md
index 51cffe4b6..4f2221484 100644
--- a/test/resources/9999999/dataExtension/retrieve-expected.md
+++ b/test/resources/9999999/dataExtension/retrieve-expected.md
@@ -16,5 +16,5 @@
| LastName | Text | 50 | - | + | |
| EmailAddress | EmailAddress | 254 | - | - | |
| ContactKey | Text | 50 | + | - | |
-| decimalField | Decimal | 6 | - | - | |
+| decimalField | Decimal | 6,3 | - | - | |
| numberField | Number | | - | - | |
From ed60e34fa3b4ecf0c6e9426d9d935d67828230ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 31 Aug 2023 16:49:00 +0200
Subject: [PATCH 67/70] #0: manually applied hotfix for outdated sfmc-sdk
dependency fast-xml-parser
---
package-lock.json | 39 +++++++++++++++++----------------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 86e352906..683469afe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3628,7 +3628,6 @@
"version": "4.2.7",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.7.tgz",
"integrity": "sha512-J8r6BriSLO1uj2miOk1NW0YVm8AGOOu3Si2HQp/cSmo6EA4m3fcwu2WKjJ4RK9wMLBtg69y1kS8baDiQBR41Ig==",
- "dev": true,
"funding": [
{
"type": "paypal",
@@ -8835,7 +8834,7 @@
"integrity": "sha512-0GdDnNa6jqoLGSHf3ByoQNAzlzdGxjSHeH55zFaY9tM4YPtSRgTrsBkZCh5xOBLwr4u7u2X9lbJpxbTWyULhpA==",
"dependencies": {
"axios": "^1.3.5",
- "fast-xml-parser": "4.2.0",
+ "fast-xml-parser": "4.2.7",
"p-limit": "3.1.0"
},
"engines": {
@@ -8843,20 +8842,27 @@
"npm": ">=6.14.4"
}
},
- "node_modules/sfmc-sdk/node_modules/fast-xml-parser": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.0.tgz",
- "integrity": "sha512-+zVQv4aVTO+o8oRUyRL7PjgeVo1J6oP8Cw2+a8UTZQcj5V0yUK5T63gTN0ldgiHDPghUjKc4OpT6SwMTwnOQug==",
+ "node_modules/sfmc-sdk/fast-xml-parser": {
+ "version": "4.2.7",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.7.tgz",
+ "integrity": "sha512-J8r6BriSLO1uj2miOk1NW0YVm8AGOOu3Si2HQp/cSmo6EA4m3fcwu2WKjJ4RK9wMLBtg69y1kS8baDiQBR41Ig==",
+ "extraneous": true,
"dependencies": {
"strnum": "^1.0.5"
},
"bin": {
"fxparser": "src/cli/cli.js"
},
- "funding": {
- "type": "paypal",
- "url": "https://paypal.me/naturalintelligence"
- }
+ "funding": [
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/naturalintelligence"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ]
},
"node_modules/shebang-command": {
"version": "2.0.0",
@@ -12780,7 +12786,6 @@
"version": "4.2.7",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.7.tgz",
"integrity": "sha512-J8r6BriSLO1uj2miOk1NW0YVm8AGOOu3Si2HQp/cSmo6EA4m3fcwu2WKjJ4RK9wMLBtg69y1kS8baDiQBR41Ig==",
- "dev": true,
"requires": {
"strnum": "^1.0.5"
}
@@ -16595,18 +16600,8 @@
"integrity": "sha512-0GdDnNa6jqoLGSHf3ByoQNAzlzdGxjSHeH55zFaY9tM4YPtSRgTrsBkZCh5xOBLwr4u7u2X9lbJpxbTWyULhpA==",
"requires": {
"axios": "^1.3.5",
- "fast-xml-parser": "4.2.0",
+ "fast-xml-parser": "4.2.7",
"p-limit": "3.1.0"
- },
- "dependencies": {
- "fast-xml-parser": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.0.tgz",
- "integrity": "sha512-+zVQv4aVTO+o8oRUyRL7PjgeVo1J6oP8Cw2+a8UTZQcj5V0yUK5T63gTN0ldgiHDPghUjKc4OpT6SwMTwnOQug==",
- "requires": {
- "strnum": "^1.0.5"
- }
- }
}
},
"shebang-command": {
From 4f125f7a7daa36d73dc8c9914308470ac30fd52c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 31 Aug 2023 16:50:49 +0200
Subject: [PATCH 68/70] #0: semver dependency hotfix
---
package-lock.json | 100 +++++++++++++++++++++++-----------------------
1 file changed, 49 insertions(+), 51 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 683469afe..1ff0c6351 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -154,9 +154,9 @@
}
},
"node_modules/@babel/core/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -195,9 +195,9 @@
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -4089,9 +4089,7 @@
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"optional": true,
- "os": [
- "darwin"
- ],
+ "os": ["darwin"],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
@@ -5369,9 +5367,9 @@
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@@ -6334,9 +6332,9 @@
}
},
"node_modules/make-dir/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -6886,9 +6884,9 @@
}
},
"node_modules/normalize-package-data/node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@@ -7169,9 +7167,9 @@
}
},
"node_modules/npm-run-all/node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@@ -7671,9 +7669,9 @@
}
},
"node_modules/package-json/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -8806,9 +8804,9 @@
}
},
"node_modules/semver-diff/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -10163,9 +10161,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@@ -10194,9 +10192,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@@ -13995,9 +13993,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
}
}
@@ -14729,9 +14727,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -15149,9 +15147,9 @@
},
"dependencies": {
"semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
}
}
@@ -15368,9 +15366,9 @@
"dev": true
},
"semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
},
"shebang-command": {
@@ -15745,9 +15743,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -16573,9 +16571,9 @@
},
"dependencies": {
"semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
From 96120fe56f4b06006b4eec869df326cf1e1e0037 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 31 Aug 2023 16:57:21 +0200
Subject: [PATCH 69/70] 5.3.0
---
package-lock.json | 8 +++++---
package.json | 2 +-
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 1ff0c6351..f288104a7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mcdev",
- "version": "5.2.0",
+ "version": "5.3.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mcdev",
- "version": "5.2.0",
+ "version": "5.3.0",
"license": "MIT",
"dependencies": {
"beauty-amp-core": "0.3.7",
@@ -4089,7 +4089,9 @@
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"optional": true,
- "os": ["darwin"],
+ "os": [
+ "darwin"
+ ],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
diff --git a/package.json b/package.json
index 804530c47..a8d1faa23 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mcdev",
- "version": "5.2.0",
+ "version": "5.3.0",
"description": "Accenture Salesforce Marketing Cloud DevTools",
"author": "Accenture: joern.berkefeld, douglas.midgley, robert.zimmermann, maciej.barnas",
"license": "MIT",
From e4e4f47e45fcf553cff8f1b24d2118a75183b37d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20Berkefeld?=
Date: Thu, 31 Aug 2023 17:02:10 +0200
Subject: [PATCH 70/70] #0: release 5.3 prep
---
.github/ISSUE_TEMPLATE/bug.yml | 1 +
test/mockRoot/.mcdevrc.json | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index a5c9d99d7..461f21e53 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -39,6 +39,7 @@ body:
label: Version
description: What version of our software are you running? (mcdev --version)
options:
+ - 5.3.0
- 5.2.0
- 5.1.0
- 5.0.2
diff --git a/test/mockRoot/.mcdevrc.json b/test/mockRoot/.mcdevrc.json
index bc3be43a4..30c384a28 100644
--- a/test/mockRoot/.mcdevrc.json
+++ b/test/mockRoot/.mcdevrc.json
@@ -78,5 +78,5 @@
"triggeredSend"
]
},
- "version": "5.2.0"
+ "version": "5.3.0"
}