mcdev 4.3.4 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.coverage-comment-template.md +20 -0
- package/.coverage-comment-template.svelte +178 -0
- package/.eslintrc.json +2 -0
- package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
- package/.github/workflows/code-test.yml +36 -0
- package/.github/workflows/coverage-base-update.yml +57 -0
- package/.github/workflows/coverage-develop-branch.yml +41 -0
- package/.github/workflows/coverage-main-branch.yml +41 -0
- package/.github/workflows/coverage.yml +77 -0
- package/.husky/post-checkout +1 -1
- package/.prettierrc +1 -1
- package/.vscode/extensions.json +0 -4
- package/README.md +1 -1
- package/boilerplate/config.json +1 -1
- package/boilerplate/files/.prettierrc +1 -1
- package/boilerplate/files/.vscode/extensions.json +1 -1
- package/boilerplate/forcedUpdates.json +4 -0
- package/docs/dist/documentation.md +1196 -430
- package/lib/Builder.js +6 -1
- package/lib/Deployer.js +30 -5
- package/lib/MetadataTypeDefinitions.js +8 -6
- package/lib/MetadataTypeInfo.js +8 -6
- package/lib/cli.js +54 -42
- package/lib/index.js +82 -8
- package/lib/metadataTypes/Asset.js +73 -1
- package/lib/metadataTypes/AttributeGroup.js +0 -1
- package/lib/metadataTypes/Automation.js +48 -5
- package/lib/metadataTypes/Campaign.js +20 -7
- package/lib/metadataTypes/ContentArea.js +1 -1
- package/lib/metadataTypes/DataExtension.js +221 -184
- package/lib/metadataTypes/DataExtensionField.js +12 -19
- package/lib/metadataTypes/DataExtensionTemplate.js +1 -1
- package/lib/metadataTypes/DataExtract.js +1 -1
- package/lib/metadataTypes/DataExtractType.js +1 -1
- package/lib/metadataTypes/Email.js +1 -1
- package/lib/metadataTypes/{EmailSendDefinition.js → EmailSend.js} +5 -5
- package/lib/metadataTypes/{EventDefinition.js → Event.js} +17 -35
- package/lib/metadataTypes/{FtpLocation.js → FileLocation.js} +2 -2
- package/lib/metadataTypes/FileTransfer.js +8 -7
- package/lib/metadataTypes/Filter.js +1 -1
- package/lib/metadataTypes/Folder.js +8 -3
- package/lib/metadataTypes/ImportFile.js +6 -6
- package/lib/metadataTypes/{Interaction.js → Journey.js} +311 -147
- package/lib/metadataTypes/List.js +2 -2
- package/lib/metadataTypes/MetadataType.js +318 -90
- package/lib/metadataTypes/MobileCode.js +0 -1
- package/lib/metadataTypes/MobileKeyword.js +336 -40
- package/lib/metadataTypes/MobileMessage.js +473 -0
- package/lib/metadataTypes/Query.js +114 -32
- package/lib/metadataTypes/Role.js +60 -21
- package/lib/metadataTypes/Script.js +2 -3
- package/lib/metadataTypes/SendClassification.js +40 -0
- package/lib/metadataTypes/SetDefinition.js +1 -7
- package/lib/metadataTypes/TransactionalEmail.js +2 -3
- package/lib/metadataTypes/TransactionalMessage.js +1 -2
- package/lib/metadataTypes/TransactionalSMS.js +8 -15
- package/lib/metadataTypes/{TriggeredSendDefinition.js → TriggeredSend.js} +35 -27
- package/lib/metadataTypes/User.js +1185 -0
- package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
- package/lib/metadataTypes/definitions/AttributeGroup.definition.js +1 -0
- package/lib/metadataTypes/definitions/Automation.definition.js +3 -2
- package/lib/metadataTypes/definitions/Campaign.definition.js +79 -4
- package/lib/metadataTypes/definitions/ContentArea.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtension.definition.js +2 -1
- package/lib/metadataTypes/definitions/DataExtensionField.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtract.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtractType.definition.js +1 -0
- package/lib/metadataTypes/definitions/Discovery.definition.js +1 -0
- package/lib/metadataTypes/definitions/Email.definition.js +1 -0
- package/lib/metadataTypes/definitions/{EmailSendDefinition.definition.js → EmailSend.definition.js} +4 -2
- package/lib/metadataTypes/definitions/{EventDefinition.definition.js → Event.definition.js} +2 -1
- package/lib/metadataTypes/definitions/{FtpLocation.definition.js → FileLocation.definition.js} +4 -3
- package/lib/metadataTypes/definitions/FileTransfer.definition.js +3 -2
- package/lib/metadataTypes/definitions/Filter.definition.js +1 -0
- package/lib/metadataTypes/definitions/Folder.definition.js +2 -0
- package/lib/metadataTypes/definitions/ImportFile.definition.js +4 -3
- package/lib/metadataTypes/definitions/{Interaction.definition.js → Journey.definition.js} +11 -2
- package/lib/metadataTypes/definitions/List.definition.js +1 -0
- package/lib/metadataTypes/definitions/MobileCode.definition.js +3 -1
- package/lib/metadataTypes/definitions/MobileKeyword.definition.js +27 -17
- package/lib/metadataTypes/definitions/MobileMessage.definition.js +743 -0
- package/lib/metadataTypes/definitions/Query.definition.js +3 -2
- package/lib/metadataTypes/definitions/Role.definition.js +5 -0
- package/lib/metadataTypes/definitions/Script.definition.js +1 -0
- package/lib/metadataTypes/definitions/SendClassification.definition.js +114 -0
- package/lib/metadataTypes/definitions/SetDefinition.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +2 -1
- package/lib/metadataTypes/definitions/TransactionalPush.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +1 -0
- package/lib/metadataTypes/definitions/{TriggeredSendDefinition.definition.js → TriggeredSend.definition.js} +5 -3
- package/lib/metadataTypes/definitions/User.definition.js +365 -0
- package/lib/retrieveChangelog.js +1 -2
- package/lib/util/auth.js +38 -9
- package/lib/util/businessUnit.js +3 -3
- package/lib/util/cli.js +55 -7
- package/lib/util/devops.js +6 -4
- package/lib/util/file.js +55 -13
- package/lib/util/init.config.js +1 -2
- package/lib/util/init.npm.js +3 -3
- package/lib/util/util.js +23 -14
- package/package.json +16 -15
- package/test/general.test.js +62 -0
- package/test/mockRoot/.mcdevrc.json +7 -5
- package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testBlocked_user.user-meta.json +23 -0
- package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testExisting_user.user-meta.json +31 -0
- package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testNew_user.user-meta.json +27 -0
- package/test/mockRoot/deploy/testInstance/testBU/dataExtension/{childBU_dataextension_test.dataExtension-meta.json → testExisting_dataExtension.dataExtension-meta.json} +2 -2
- package/test/mockRoot/deploy/testInstance/testBU/dataExtension/{testDataExtension.dataExtension-meta.json → testNew_dataExtension.dataExtension-meta.json} +2 -2
- package/test/mockRoot/deploy/testInstance/testBU/journey/testExisting_interaction.interaction-meta.json +576 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword.mobileKeyword-meta.amp +2 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword.mobileKeyword-meta.json +10 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword_blocked.mobileKeyword-meta.amp +2 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword_blocked.mobileKeyword-meta.json +10 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/NTIzOjc4OjA.mobileMessage-meta.amp +1 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/NTIzOjc4OjA.mobileMessage-meta.json +61 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/new.mobileMessage-meta.amp +1 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/new.mobileMessage-meta.json +60 -0
- package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.sql +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json +1 -1
- package/test/resourceFactory.js +13 -0
- package/test/resources/1111111/accountUser/configure-response.xml +70 -0
- package/test/resources/1111111/accountUser/create-response.xml +97 -0
- package/test/resources/1111111/accountUser/retrieve-response.xml +156 -0
- package/test/resources/1111111/accountUser/update-response.xml +111 -0
- package/test/resources/1111111/accountUserAccount/retrieve-response.xml +77 -0
- package/test/resources/1111111/platform/v1/setup/quickflow/data/get-response.json +455 -0
- package/test/resources/1111111/role/retrieve-response.xml +76 -0
- package/test/resources/1111111/user/build-expected.json +16 -0
- package/test/resources/1111111/user/create-expected.json +21 -0
- package/test/resources/1111111/user/retrieve-expected.json +24 -0
- package/test/resources/1111111/user/template-expected.json +16 -0
- package/test/resources/1111111/user/update-expected.json +21 -0
- package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/delete-response.json +1 -0
- package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json +17 -0
- package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +3 -3
- package/test/resources/9999999/automation/v1/queries/get-response.json +21 -4
- package/test/resources/9999999/automation/v1/queries/post-response.json +4 -4
- package/test/resources/9999999/data/v1/customobjectdata/key/{childBU_dataextension_test → testExisting_dataExtension}/rowset/get-response.json +1 -1
- package/test/resources/9999999/dataExtension/build-expected.json +3 -3
- package/test/resources/9999999/dataExtension/create-expected.json +2 -2
- package/test/resources/9999999/dataExtension/create-response.xml +8 -3
- package/test/resources/9999999/dataExtension/retrieve-expected.json +3 -3
- package/test/resources/9999999/dataExtension/retrieve-response.xml +9 -4
- package/test/resources/9999999/dataExtension/template-expected.json +3 -3
- package/test/resources/9999999/dataExtension/update-expected.json +3 -3
- package/test/resources/9999999/dataExtension/update-response.xml +9 -4
- package/test/resources/9999999/dataExtensionField/retrieve-response.xml +14 -9
- package/test/resources/9999999/interaction/v1/interactions/get-response.json +312 -0
- package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/get-response.json +312 -0
- package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/put-response.json +592 -0
- package/test/resources/9999999/journey/build-expected.json +572 -0
- package/test/resources/9999999/journey/get-expected.json +576 -0
- package/test/resources/9999999/journey/put-expected.json +576 -0
- package/test/resources/9999999/journey/template-expected.json +572 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/NXV4ZFMwTEFwRVczd3RaLUF5X3p5dzo4Njow/get-response.json +42 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/cTVJaG5oSDJPVUNHcUh6Z3pQT2tVdzo4Njow/delete-response.json +0 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/get-response.json +1 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/post-response.json +3 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/delete-response.json +0 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/get-response.json +106 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/post-response.json +0 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/NTQ3Ojc4OjA/get-response.json +127 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/get-response.json +129 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/post-response.json +3 -0
- package/test/resources/9999999/legacy/v1/beta2/data/campaign/get-response.json +29 -0
- package/test/resources/9999999/messaging/v1/email/definitions/post-response.json +1 -1
- package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/get-response.json +1 -1
- package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/patch-response.json +1 -1
- package/test/resources/9999999/mobileKeyword/build-expected.amp +2 -0
- package/test/resources/9999999/mobileKeyword/build-expected.json +9 -0
- package/test/resources/9999999/mobileKeyword/get-expected.amp +2 -0
- package/test/resources/9999999/mobileKeyword/get-expected.json +15 -0
- package/test/resources/9999999/mobileKeyword/post-create-expected.amp +2 -0
- package/test/resources/9999999/mobileKeyword/post-create-expected.json +17 -0
- package/test/resources/9999999/mobileKeyword/template-expected.amp +2 -0
- package/test/resources/9999999/mobileKeyword/template-expected.json +9 -0
- package/test/resources/9999999/mobileMessage/build-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/build-expected.json +60 -0
- package/test/resources/9999999/mobileMessage/get-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/get-expected.json +61 -0
- package/test/resources/9999999/mobileMessage/post-create-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/post-create-expected.json +63 -0
- package/test/resources/9999999/mobileMessage/post-update-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/post-update-expected.json +61 -0
- package/test/resources/9999999/mobileMessage/template-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/template-expected.json +60 -0
- package/test/resources/9999999/query/build-expected.json +1 -1
- package/test/resources/9999999/query/get-expected.json +1 -1
- package/test/resources/9999999/query/get2-expected.json +11 -0
- package/test/resources/9999999/query/patch-expected.json +1 -1
- package/test/resources/9999999/query/post-expected.json +1 -1
- package/test/resources/9999999/query/template-expected.json +1 -1
- package/test/resources/9999999/queryDefinition/retrieve-response.xml +30 -0
- package/test/resources/9999999/transactionalEmail/build-expected.json +5 -5
- package/test/resources/9999999/transactionalEmail/get-expected.json +1 -1
- package/test/resources/9999999/transactionalEmail/patch-expected.json +1 -1
- package/test/resources/9999999/transactionalEmail/post-expected.json +1 -1
- package/test/resources/9999999/transactionalEmail/template-expected.json +5 -5
- package/test/resources/9999999/transactionalPush/build-expected.json +2 -2
- package/test/resources/9999999/transactionalPush/template-expected.json +2 -2
- package/test/resources/9999999/transactionalSMS/build-expected.json +3 -3
- package/test/resources/9999999/transactionalSMS/template-expected.json +3 -3
- package/test/{dataExtension.test.js → type.dataExtension.test.js} +78 -21
- package/test/{interaction.test.js → type.journey.test.js} +64 -30
- package/test/type.mobileKeyword.test.js +250 -0
- package/test/type.mobileMessage.test.js +205 -0
- package/test/{query.test.js → type.query.test.js} +102 -5
- package/test/{transactionalEmail.test.js → type.transactionalEmail.test.js} +40 -2
- package/test/{transactionalPush.test.js → type.transactionalPush.test.js} +41 -2
- package/test/{transactionalSMS.test.js → type.transactionalSMS.test.js} +73 -3
- package/test/type.user.test.js +160 -0
- package/test/utils.js +17 -5
- package/types/mcdev.d.js +48 -15
- package/.github/workflows/code-analysis.yml +0 -57
- package/lib/metadataTypes/AccountUser.js +0 -426
- package/lib/metadataTypes/definitions/AccountUser.definition.js +0 -227
- package/test/mockRoot/deploy/testInstance/testBU/interaction/testExisting_interaction.interaction-meta.json +0 -266
- package/test/resources/9999999/interaction/build-expected.json +0 -260
- package/test/resources/9999999/interaction/get-expected.json +0 -264
- package/test/resources/9999999/interaction/put-expected.json +0 -264
- package/test/resources/9999999/interaction/template-expected.json +0 -260
- package/test/resources/9999999/interaction/v1/interactions/put-response.json +0 -280
- /package/test/mockRoot/deploy/testInstance/testBU/{interaction → journey}/testNew_interaction.interaction-meta.json +0 -0
- /package/test/resources/9999999/{interaction → journey}/post-expected.json +0 -0
|
@@ -9,6 +9,7 @@ const Util = require('../util/util');
|
|
|
9
9
|
const File = require('../util/file');
|
|
10
10
|
const auth = require('../util/auth');
|
|
11
11
|
const cache = require('../util/cache');
|
|
12
|
+
const pLimit = require('p-limit');
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* DataExtension MetadataType
|
|
@@ -20,16 +21,13 @@ class DataExtension extends MetadataType {
|
|
|
20
21
|
* Upserts dataExtensions after retrieving them from source and target to compare
|
|
21
22
|
* if create or update operation is needed.
|
|
22
23
|
*
|
|
23
|
-
* @param {TYPE.DataExtensionMap}
|
|
24
|
+
* @param {TYPE.DataExtensionMap} metadataMap dataExtensions mapped by their customerKey
|
|
24
25
|
* @returns {Promise} Promise
|
|
25
26
|
*/
|
|
26
|
-
static async upsert(
|
|
27
|
-
// get dataExtensions from target BU for add/update decision
|
|
28
|
-
/** @type {TYPE.DataExtensionMap} */
|
|
29
|
-
const targetMetadata = cache.getCache().dataExtension || {};
|
|
27
|
+
static async upsert(metadataMap) {
|
|
30
28
|
// get existing DE-fields for DE-keys in deployment package to properly handle add/update/delete of fields
|
|
31
29
|
const fieldOptions = {};
|
|
32
|
-
for (const key of Object.keys(
|
|
30
|
+
for (const key of Object.keys(metadataMap)) {
|
|
33
31
|
fieldOptions.filter = fieldOptions.filter
|
|
34
32
|
? {
|
|
35
33
|
leftOperand: {
|
|
@@ -47,80 +45,71 @@ class DataExtension extends MetadataType {
|
|
|
47
45
|
};
|
|
48
46
|
}
|
|
49
47
|
Util.logger.info(` - Caching dependent Metadata: dataExtensionField`);
|
|
50
|
-
await this._attachFields(
|
|
48
|
+
await this._attachFields(metadataMap, fieldOptions);
|
|
51
49
|
|
|
52
|
-
/** @type {
|
|
53
|
-
const
|
|
54
|
-
/** @type {
|
|
55
|
-
const
|
|
50
|
+
/** @type {object[]} */
|
|
51
|
+
const metadataToCreate = [];
|
|
52
|
+
/** @type {object[]} */
|
|
53
|
+
const metadataToUpdate = [];
|
|
56
54
|
let filteredByPreDeploy = 0;
|
|
57
|
-
for (const
|
|
58
|
-
if (desToDeploy[dataExtension].Name.startsWith('_')) {
|
|
59
|
-
Util.logger.warn(
|
|
60
|
-
` ☇ skipping dataExtension ${desToDeploy[dataExtension].Name}: Cannot Upsert Strongly Typed Data Extensions`
|
|
61
|
-
);
|
|
62
|
-
filteredByPreDeploy++;
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (
|
|
66
|
-
this.buObject.eid !== this.buObject.mid &&
|
|
67
|
-
desToDeploy[dataExtension].r__folder_Path.startsWith('Shared Items')
|
|
68
|
-
) {
|
|
69
|
-
// this needs to be run before executing preDeployTasks()
|
|
70
|
-
Util.logger.warn(
|
|
71
|
-
` ☇ skipping dataExtension ${desToDeploy[dataExtension].Name}: Cannot Create/Update a Shared Data Extension from the Child BU`
|
|
72
|
-
);
|
|
73
|
-
filteredByPreDeploy++;
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
if (
|
|
77
|
-
desToDeploy[dataExtension].r__folder_Path.startsWith('Synchronized Data Extensions')
|
|
78
|
-
) {
|
|
79
|
-
// this needs to be run before executing preDeployTasks()
|
|
80
|
-
Util.logger.warn(
|
|
81
|
-
` ☇ skipping dataExtension ${desToDeploy[dataExtension].Name}:Cannot Create/Update a Synchronized Data Extension. Please use Contact Builder to maintain these`
|
|
82
|
-
);
|
|
83
|
-
filteredByPreDeploy++;
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
55
|
+
for (const metadataKey in metadataMap) {
|
|
86
56
|
try {
|
|
87
|
-
|
|
57
|
+
metadataMap[metadataKey] = await this.preDeployTasks(metadataMap[metadataKey]);
|
|
88
58
|
} catch (ex) {
|
|
89
|
-
// problem with retrieving folder for this DE found
|
|
90
59
|
// output error & remove from deploy list
|
|
91
60
|
Util.logger.error(
|
|
92
|
-
|
|
61
|
+
` ☇ skipping ${this.definition.type} ${
|
|
62
|
+
metadataMap[this.definition.keyField]
|
|
63
|
+
} / ${metadataMap[this.definition.nameField]}: ${ex.message}`
|
|
93
64
|
);
|
|
94
|
-
delete
|
|
65
|
+
delete metadataMap[metadataKey];
|
|
95
66
|
// skip rest of handling for this DE
|
|
67
|
+
filteredByPreDeploy++;
|
|
96
68
|
continue;
|
|
97
69
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
70
|
+
await this.createOrUpdate(
|
|
71
|
+
metadataMap,
|
|
72
|
+
metadataKey,
|
|
73
|
+
false,
|
|
74
|
+
metadataToUpdate,
|
|
75
|
+
metadataToCreate
|
|
76
|
+
);
|
|
105
77
|
}
|
|
106
|
-
if (
|
|
78
|
+
if (metadataToUpdate.length) {
|
|
107
79
|
Util.logger.info(
|
|
108
80
|
' - Please note that Data Retention Policies can only be set during creation, not during update.'
|
|
109
81
|
);
|
|
110
82
|
}
|
|
83
|
+
const createLimit = pLimit(10);
|
|
84
|
+
const createResults = (
|
|
85
|
+
await Promise.allSettled(
|
|
86
|
+
metadataToCreate
|
|
87
|
+
.filter((r) => r !== undefined && r !== null)
|
|
88
|
+
.map((metadataEntry) => createLimit(() => this.create(metadataEntry)))
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
.filter((r) => r !== undefined && r !== null)
|
|
92
|
+
.filter(this.#filterUpsertResults);
|
|
111
93
|
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
94
|
+
const updateLimit = pLimit(10);
|
|
95
|
+
const updateResults = (
|
|
96
|
+
await Promise.allSettled(
|
|
97
|
+
metadataToUpdate
|
|
98
|
+
.filter((r) => r !== undefined && r !== null)
|
|
99
|
+
.map((metadataEntry) =>
|
|
100
|
+
updateLimit(() => this.update(metadataEntry.after, metadataEntry.before))
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
.filter((r) => r !== undefined && r !== null)
|
|
105
|
+
.filter(this.#filterUpsertResults);
|
|
118
106
|
|
|
119
107
|
const successfulResults = [...createResults, ...updateResults];
|
|
120
108
|
Util.logger.info(
|
|
121
|
-
`${this.definition.type} upsert: ${createResults.length} of ${
|
|
109
|
+
`${this.definition.type} upsert: ${createResults.length} of ${metadataToCreate.length} created / ${updateResults.length} of ${metadataToUpdate.length} updated` +
|
|
122
110
|
(filteredByPreDeploy > 0 ? ` / ${filteredByPreDeploy} filtered` : '')
|
|
123
111
|
);
|
|
112
|
+
let upsertResults;
|
|
124
113
|
if (successfulResults.length > 0) {
|
|
125
114
|
const metadataResults = successfulResults
|
|
126
115
|
.map((r) => r.value.Results[0].Object)
|
|
@@ -133,19 +122,94 @@ class DataExtension extends MetadataType {
|
|
|
133
122
|
}
|
|
134
123
|
return r;
|
|
135
124
|
});
|
|
136
|
-
|
|
125
|
+
upsertResults = super.parseResponseBody({ Results: metadataResults });
|
|
137
126
|
} else {
|
|
138
|
-
|
|
127
|
+
upsertResults = {};
|
|
139
128
|
}
|
|
129
|
+
await this.postDeployTasks(upsertResults, metadataMap, {
|
|
130
|
+
created: createResults.length,
|
|
131
|
+
updated: updateResults.length,
|
|
132
|
+
});
|
|
133
|
+
return upsertResults;
|
|
140
134
|
}
|
|
141
135
|
|
|
136
|
+
/**
|
|
137
|
+
* helper for {@link MetadataType.upsert}
|
|
138
|
+
*
|
|
139
|
+
* @param {TYPE.MetadataTypeMap} metadataMap list of metadata
|
|
140
|
+
* @param {string} metadataKey key of item we are looking at
|
|
141
|
+
* @param {boolean} hasError error flag from previous code
|
|
142
|
+
* @param {TYPE.MetadataTypeItemDiff[]} metadataToUpdate list of items to update
|
|
143
|
+
* @param {TYPE.MetadataTypeItem[]} metadataToCreate list of items to create
|
|
144
|
+
* @returns {'create' | 'update' | 'skip'} action to take
|
|
145
|
+
*/
|
|
146
|
+
static async createOrUpdate(
|
|
147
|
+
metadataMap,
|
|
148
|
+
metadataKey,
|
|
149
|
+
hasError,
|
|
150
|
+
metadataToUpdate,
|
|
151
|
+
metadataToCreate
|
|
152
|
+
) {
|
|
153
|
+
const action = await super.createOrUpdate(
|
|
154
|
+
metadataMap,
|
|
155
|
+
metadataKey,
|
|
156
|
+
hasError,
|
|
157
|
+
metadataToUpdate,
|
|
158
|
+
metadataToCreate
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
if (action === 'update') {
|
|
162
|
+
// Update dataExtension + Columns if they already exist; Create them if not
|
|
163
|
+
// Modify columns for update call
|
|
164
|
+
DataExtensionField.client = this.client;
|
|
165
|
+
DataExtensionField.properties = this.properties;
|
|
166
|
+
DataExtension.oldFields ||= {};
|
|
167
|
+
DataExtension.oldFields[metadataMap[metadataKey][this.definition.keyField]] =
|
|
168
|
+
await DataExtensionField.prepareDeployColumnsOnUpdate(
|
|
169
|
+
metadataMap[metadataKey].Fields,
|
|
170
|
+
metadataKey
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
if (
|
|
174
|
+
metadataMap[metadataKey][this.definition.keyField] !== metadataKey &&
|
|
175
|
+
metadataMap[metadataKey].Fields.length
|
|
176
|
+
) {
|
|
177
|
+
// changeKeyValue / changeKeyField used
|
|
178
|
+
Util.logger.warn(
|
|
179
|
+
` - ${this.definition.type} ${metadataKey}: Cannot change fields while updating the key. Skipping field update in favor of key update.`
|
|
180
|
+
);
|
|
181
|
+
metadataMap[metadataKey].Fields.length = 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// convert simple array into object.Array.object format to cope with how the XML body in the SOAP call needs to look like:
|
|
185
|
+
// <Fields>
|
|
186
|
+
// <Field>
|
|
187
|
+
// <CustomerKey>SubscriberKey</CustomerKey>
|
|
188
|
+
// ..
|
|
189
|
+
// </Field>
|
|
190
|
+
// </Fields>
|
|
191
|
+
metadataMap[metadataKey].Fields = { Field: metadataMap[metadataKey].Fields };
|
|
192
|
+
} else if (action === 'create') {
|
|
193
|
+
this.#cleanupRetentionPolicyFields(metadataMap[metadataKey]);
|
|
194
|
+
|
|
195
|
+
// convert simple array into object.Array.object format to cope with how the XML body in the SOAP call needs to look like:
|
|
196
|
+
// <Fields>
|
|
197
|
+
// <Field>
|
|
198
|
+
// <CustomerKey>SubscriberKey</CustomerKey>
|
|
199
|
+
// ..
|
|
200
|
+
// </Field>
|
|
201
|
+
// </Fields>
|
|
202
|
+
metadataMap[metadataKey].Fields = { Field: metadataMap[metadataKey].Fields };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
142
205
|
/**
|
|
143
206
|
* helper for {@link upsert}
|
|
144
207
|
*
|
|
208
|
+
* @private
|
|
145
209
|
* @param {object} res -
|
|
146
210
|
* @returns {boolean} true: keep, false: discard
|
|
147
211
|
*/
|
|
148
|
-
static
|
|
212
|
+
static #filterUpsertResults(res) {
|
|
149
213
|
if (res.status === 'rejected') {
|
|
150
214
|
// promise rejects, whole request failed
|
|
151
215
|
Util.logger.error('- error upserting dataExtension: ' + res.reason);
|
|
@@ -178,17 +242,6 @@ class DataExtension extends MetadataType {
|
|
|
178
242
|
* @returns {Promise} Promise
|
|
179
243
|
*/
|
|
180
244
|
static async create(metadata) {
|
|
181
|
-
this._cleanupRetentionPolicyFields(metadata);
|
|
182
|
-
|
|
183
|
-
// convert simple array into object.Array.object format to cope with how the XML body in the SOAP call needs to look like:
|
|
184
|
-
// <Fields>
|
|
185
|
-
// <Field>
|
|
186
|
-
// <CustomerKey>SubscriberKey</CustomerKey>
|
|
187
|
-
// ..
|
|
188
|
-
// </Field>
|
|
189
|
-
// </Fields>
|
|
190
|
-
metadata.Fields = { Field: metadata.Fields };
|
|
191
|
-
|
|
192
245
|
return super.createSOAP(metadata);
|
|
193
246
|
}
|
|
194
247
|
|
|
@@ -201,7 +254,7 @@ class DataExtension extends MetadataType {
|
|
|
201
254
|
* @param {TYPE.DataExtensionItem} metadata single metadata entry
|
|
202
255
|
* @returns {void}
|
|
203
256
|
*/
|
|
204
|
-
static
|
|
257
|
+
static #cleanupRetentionPolicyFields(metadata) {
|
|
205
258
|
if (
|
|
206
259
|
metadata.DataRetentionPeriodLength &&
|
|
207
260
|
metadata.DataRetentionPeriodUnitOfMeasure &&
|
|
@@ -220,26 +273,6 @@ class DataExtension extends MetadataType {
|
|
|
220
273
|
* @returns {Promise} Promise
|
|
221
274
|
*/
|
|
222
275
|
static async update(metadata) {
|
|
223
|
-
// Update dataExtension + Columns if they already exist; Create them if not
|
|
224
|
-
// Modify columns for update call
|
|
225
|
-
DataExtensionField.client = this.client;
|
|
226
|
-
DataExtensionField.properties = this.properties;
|
|
227
|
-
DataExtension.oldFields = DataExtension.oldFields || {};
|
|
228
|
-
DataExtension.oldFields[metadata[this.definition.keyField]] =
|
|
229
|
-
await DataExtensionField.prepareDeployColumnsOnUpdate(
|
|
230
|
-
metadata.Fields,
|
|
231
|
-
metadata.CustomerKey
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
// convert simple array into object.Array.object format to cope with how the XML body in the SOAP call needs to look like:
|
|
235
|
-
// <Fields>
|
|
236
|
-
// <Field>
|
|
237
|
-
// <CustomerKey>SubscriberKey</CustomerKey>
|
|
238
|
-
// ..
|
|
239
|
-
// </Field>
|
|
240
|
-
// </Fields>
|
|
241
|
-
|
|
242
|
-
metadata.Fields = { Field: metadata.Fields };
|
|
243
276
|
return super.updateSOAP(metadata);
|
|
244
277
|
}
|
|
245
278
|
/**
|
|
@@ -247,12 +280,19 @@ class DataExtension extends MetadataType {
|
|
|
247
280
|
*
|
|
248
281
|
* @param {TYPE.DataExtensionMap} upsertedMetadata metadata mapped by their keyField
|
|
249
282
|
* @param {TYPE.DataExtensionMap} originalMetadata metadata to be updated (contains additioanl fields)
|
|
283
|
+
* @param {{created: number, updated: number}} createdUpdated counter representing successful creates/updates
|
|
250
284
|
* @returns {void}
|
|
251
285
|
*/
|
|
252
|
-
static postDeployTasks(upsertedMetadata, originalMetadata) {
|
|
286
|
+
static postDeployTasks(upsertedMetadata, originalMetadata, createdUpdated) {
|
|
253
287
|
for (const key in upsertedMetadata) {
|
|
254
288
|
const item = upsertedMetadata[key];
|
|
255
|
-
|
|
289
|
+
|
|
290
|
+
const oldKey = Util.changedKeysMap?.[this.definition.type]?.[key] || key;
|
|
291
|
+
delete Util.changedKeysMap?.[this.definition.type]?.[key];
|
|
292
|
+
|
|
293
|
+
const cachedVersion = createdUpdated.updated
|
|
294
|
+
? cache.getByKey(this.definition.type, oldKey)
|
|
295
|
+
: null;
|
|
256
296
|
if (cachedVersion) {
|
|
257
297
|
// UPDATE
|
|
258
298
|
// restore retention values that are typically not returned by the update call
|
|
@@ -262,25 +302,25 @@ class DataExtension extends MetadataType {
|
|
|
262
302
|
item.RetainUntil = cachedVersion.RetainUntil;
|
|
263
303
|
|
|
264
304
|
const existingFields = DataExtension.oldFields[item[this.definition.keyField]];
|
|
305
|
+
|
|
265
306
|
if (item.Fields === '') {
|
|
266
307
|
// if no fields were updated, we need to set Fields to "empty string" for the API to work
|
|
267
308
|
// reset here to get the correct field list
|
|
268
309
|
item.Fields = Object.keys(existingFields)
|
|
269
|
-
.map((
|
|
310
|
+
.map((el) => existingFields[el])
|
|
270
311
|
.sort((a, b) => a.Ordinal - b.Ordinal);
|
|
271
|
-
}
|
|
272
|
-
if (existingFields) {
|
|
312
|
+
} else if (existingFields) {
|
|
273
313
|
// get list of updated fields
|
|
274
314
|
/** @type {TYPE.DataExtensionFieldItem[]} */
|
|
275
|
-
const updatedFieldsArr = originalMetadata[
|
|
315
|
+
const updatedFieldsArr = originalMetadata[oldKey].Fields.Field.filter(
|
|
276
316
|
(field) => field.ObjectID && field.ObjectID !== ''
|
|
277
317
|
);
|
|
278
318
|
// convert existing fields obj into array and sort
|
|
279
319
|
/** @type {TYPE.DataExtensionFieldItem[]} */
|
|
280
320
|
const finalFieldsArr = Object.keys(existingFields)
|
|
281
|
-
.map((
|
|
321
|
+
.map((el) => {
|
|
282
322
|
/** @type {TYPE.DataExtensionFieldItem} */
|
|
283
|
-
const existingField = existingFields[
|
|
323
|
+
const existingField = existingFields[el];
|
|
284
324
|
// check if the current field was updated and then override with it. otherwise use existing value
|
|
285
325
|
const field =
|
|
286
326
|
updatedFieldsArr.find(
|
|
@@ -296,7 +336,7 @@ class DataExtension extends MetadataType {
|
|
|
296
336
|
|
|
297
337
|
// get list of new fields
|
|
298
338
|
/** @type {TYPE.DataExtensionFieldItem[]} */
|
|
299
|
-
const newFieldsArr = originalMetadata[
|
|
339
|
+
const newFieldsArr = originalMetadata[oldKey].Fields.Field.filter(
|
|
300
340
|
(field) => !field.ObjectID
|
|
301
341
|
);
|
|
302
342
|
// push new fields to end of list
|
|
@@ -487,7 +527,36 @@ class DataExtension extends MetadataType {
|
|
|
487
527
|
if (metadata.SendableSubscriberField?.Name === '_SubscriberKey') {
|
|
488
528
|
metadata.SendableSubscriberField.Name = 'Subscriber Key';
|
|
489
529
|
}
|
|
490
|
-
|
|
530
|
+
this.setFolderPath(metadata);
|
|
531
|
+
|
|
532
|
+
// DataExtensionTemplate
|
|
533
|
+
if (metadata.Template?.CustomerKey) {
|
|
534
|
+
try {
|
|
535
|
+
metadata.r__dataExtensionTemplate_Name = cache.searchForField(
|
|
536
|
+
'dataExtensionTemplate',
|
|
537
|
+
metadata.Template.CustomerKey,
|
|
538
|
+
'CustomerKey',
|
|
539
|
+
'Name'
|
|
540
|
+
);
|
|
541
|
+
delete metadata.Template;
|
|
542
|
+
} catch (ex) {
|
|
543
|
+
Util.logger.debug(ex.message);
|
|
544
|
+
// Let's allow retrieving such DEs but warn that they cannot be deployed to another BU.
|
|
545
|
+
// Deploying to same BU still works!
|
|
546
|
+
// A workaround exists but it's likely not beneficial to explain to users:
|
|
547
|
+
// Create a DE based on the not-supported template on the target BU, retrieve it, copy the Template.CustomerKey into the to-be-deployed DE (or use mcdev-templating), done
|
|
548
|
+
Util.logger.warn(
|
|
549
|
+
` - Issue with dataExtension '${
|
|
550
|
+
metadata[this.definition.nameField]
|
|
551
|
+
}': Could not find specified DataExtension Template. Please note that DataExtensions based on SMSMessageTracking and SMSSubscriptionLog cannot be deployed automatically across BUs at this point.`
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// remove the date fields manually here because we need them in the changelog but not in the saved json
|
|
556
|
+
delete metadata.CreatedDate;
|
|
557
|
+
delete metadata.ModifiedDate;
|
|
558
|
+
|
|
559
|
+
return metadata;
|
|
491
560
|
}
|
|
492
561
|
|
|
493
562
|
/**
|
|
@@ -539,6 +608,16 @@ class DataExtension extends MetadataType {
|
|
|
539
608
|
|
|
540
609
|
metadata[customerKey].Fields = fieldArr;
|
|
541
610
|
}
|
|
611
|
+
/**
|
|
612
|
+
* helper for {@link super.updateREST} and {@link super.updateSOAP} that removes old files after the key was changed
|
|
613
|
+
*
|
|
614
|
+
* @private
|
|
615
|
+
* @param {TYPE.MetadataTypeItem} metadataEntry a single metadata Entry
|
|
616
|
+
* @returns {void}
|
|
617
|
+
*/
|
|
618
|
+
static async _postChangeKeyTasks(metadataEntry) {
|
|
619
|
+
super._postChangeKeyTasks(metadataEntry, true);
|
|
620
|
+
}
|
|
542
621
|
|
|
543
622
|
/**
|
|
544
623
|
* prepares a DataExtension for deployment
|
|
@@ -547,6 +626,21 @@ class DataExtension extends MetadataType {
|
|
|
547
626
|
* @returns {Promise.<TYPE.DataExtensionItem>} Promise of updated single DE
|
|
548
627
|
*/
|
|
549
628
|
static async preDeployTasks(metadata) {
|
|
629
|
+
if (metadata.Name.startsWith('_')) {
|
|
630
|
+
throw new Error(`Cannot Upsert Strongly Typed Data Extensions`);
|
|
631
|
+
}
|
|
632
|
+
if (
|
|
633
|
+
this.buObject.eid !== this.buObject.mid &&
|
|
634
|
+
metadata.r__folder_Path.startsWith('Shared Items')
|
|
635
|
+
) {
|
|
636
|
+
throw new Error(`Cannot Create/Update a Shared Data Extension from the Child BU`);
|
|
637
|
+
}
|
|
638
|
+
if (metadata.r__folder_Path.startsWith('Synchronized Data Extensions')) {
|
|
639
|
+
throw new Error(
|
|
640
|
+
`Cannot Create/Update a Synchronized Data Extension. Please use Contact Builder to maintain these`
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
|
|
550
644
|
// folder
|
|
551
645
|
super.setFolderId(metadata);
|
|
552
646
|
|
|
@@ -584,9 +678,7 @@ class DataExtension extends MetadataType {
|
|
|
584
678
|
// A workaround for cross-BU deploy exists but it's likely not beneficial to explain to users:
|
|
585
679
|
// Create a DE based on the not-supported template on the target BU, retrieve it, copy the Template.CustomerKey into the to-be-deployed DE (or use mcdev-templating), done
|
|
586
680
|
throw new Error(
|
|
587
|
-
`
|
|
588
|
-
metadata[this.definition.nameField]
|
|
589
|
-
}': Could not find specified DataExtension Template. Please note that DataExtensions based on SMSMessageTracking and SMSSubscriptionLog cannot be deployed automatically across BUs at this point.`
|
|
681
|
+
`Could not find specified DataExtension Template. Please note that DataExtensions based on SMSMessageTracking and SMSSubscriptionLog cannot be deployed automatically across BUs at this point.`
|
|
590
682
|
);
|
|
591
683
|
}
|
|
592
684
|
}
|
|
@@ -755,13 +847,13 @@ class DataExtension extends MetadataType {
|
|
|
755
847
|
/**
|
|
756
848
|
* Parses metadata into a readable Markdown/HTML format then saves it
|
|
757
849
|
*
|
|
758
|
-
* @param {TYPE.DataExtensionMap} [
|
|
850
|
+
* @param {TYPE.DataExtensionMap} [metadataMap] a list of dataExtension definitions
|
|
759
851
|
* @returns {Promise.<void>} -
|
|
760
852
|
*/
|
|
761
|
-
static async document(
|
|
853
|
+
static async document(metadataMap) {
|
|
762
854
|
try {
|
|
763
|
-
if (!
|
|
764
|
-
|
|
855
|
+
if (!metadataMap) {
|
|
856
|
+
metadataMap = this.readBUMetadataForType(
|
|
765
857
|
File.normalizePath([
|
|
766
858
|
this.properties.directories.retrieve,
|
|
767
859
|
this.buObject.credential,
|
|
@@ -780,7 +872,7 @@ class DataExtension extends MetadataType {
|
|
|
780
872
|
this.buObject.businessUnit,
|
|
781
873
|
this.definition.type,
|
|
782
874
|
]);
|
|
783
|
-
if (!
|
|
875
|
+
if (!metadataMap || !Object.keys(metadataMap).length) {
|
|
784
876
|
// as part of retrieve & manual execution we could face an empty folder
|
|
785
877
|
return;
|
|
786
878
|
}
|
|
@@ -794,16 +886,15 @@ class DataExtension extends MetadataType {
|
|
|
794
886
|
'DefaultValue',
|
|
795
887
|
];
|
|
796
888
|
return Promise.all(
|
|
797
|
-
Object.keys(
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
for (const field of metadata[customerKey].Fields) {
|
|
889
|
+
Object.keys(metadataMap).map((key) => {
|
|
890
|
+
if (metadataMap[key]?.Fields?.length) {
|
|
891
|
+
for (const field of metadataMap[key].Fields) {
|
|
801
892
|
field.IsNullable = !Util.isTrue(field.IsRequired);
|
|
802
|
-
for (const
|
|
803
|
-
if (Util.isTrue(field[
|
|
804
|
-
field[
|
|
805
|
-
} else if (Util.isFalse(field[
|
|
806
|
-
field[
|
|
893
|
+
for (const prop of columnsToIterateThrough) {
|
|
894
|
+
if (Util.isTrue(field[prop])) {
|
|
895
|
+
field[prop] = '+';
|
|
896
|
+
} else if (Util.isFalse(field[prop])) {
|
|
897
|
+
field[prop] = '-';
|
|
807
898
|
}
|
|
808
899
|
}
|
|
809
900
|
}
|
|
@@ -811,8 +902,8 @@ class DataExtension extends MetadataType {
|
|
|
811
902
|
if (['html', 'both'].includes(this.properties.options.documentType)) {
|
|
812
903
|
return this._writeDoc(
|
|
813
904
|
docPath + '/',
|
|
814
|
-
|
|
815
|
-
|
|
905
|
+
key,
|
|
906
|
+
metadataMap[key],
|
|
816
907
|
'html',
|
|
817
908
|
columnsToPrint
|
|
818
909
|
);
|
|
@@ -820,8 +911,8 @@ class DataExtension extends MetadataType {
|
|
|
820
911
|
if (['md', 'both'].includes(this.properties.options.documentType)) {
|
|
821
912
|
return this._writeDoc(
|
|
822
913
|
docPath + '/',
|
|
823
|
-
|
|
824
|
-
|
|
914
|
+
key,
|
|
915
|
+
metadataMap[key],
|
|
825
916
|
'md',
|
|
826
917
|
columnsToPrint
|
|
827
918
|
);
|
|
@@ -838,34 +929,19 @@ class DataExtension extends MetadataType {
|
|
|
838
929
|
* @returns {Promise.<boolean>} deletion success status
|
|
839
930
|
*/
|
|
840
931
|
static deleteByKey(customerKey) {
|
|
841
|
-
return super.deleteByKeySOAP(customerKey
|
|
932
|
+
return super.deleteByKeySOAP(customerKey);
|
|
842
933
|
}
|
|
843
934
|
|
|
844
935
|
/**
|
|
845
936
|
* clean up after deleting a metadata item
|
|
846
937
|
*
|
|
847
938
|
* @param {string} customerKey Identifier of metadata item
|
|
848
|
-
* @returns {void}
|
|
939
|
+
* @returns {Promise.<void>} - promise
|
|
849
940
|
*/
|
|
850
941
|
static async postDeleteTasks(customerKey) {
|
|
851
|
-
// delete local copy: retrieve/cred/bu/dataExtension
|
|
852
|
-
const jsonFile = File.normalizePath([
|
|
853
|
-
this.properties.directories.retrieve,
|
|
854
|
-
this.buObject.credential,
|
|
855
|
-
this.buObject.businessUnit,
|
|
856
|
-
this.definition.type,
|
|
857
|
-
`${customerKey}.${this.definition.type}-meta.json`,
|
|
858
|
-
]);
|
|
859
|
-
await File.remove(jsonFile);
|
|
942
|
+
// delete local copy: retrieve/cred/bu/dataExtension/...-meta.json
|
|
860
943
|
// delete local copy: doc/dataExtension/cred/bu/...md
|
|
861
|
-
|
|
862
|
-
this.properties.directories.docs,
|
|
863
|
-
'dataExtension',
|
|
864
|
-
this.buObject.credential,
|
|
865
|
-
this.buObject.businessUnit,
|
|
866
|
-
`${customerKey}.${this.definition.type}.md`,
|
|
867
|
-
]);
|
|
868
|
-
await File.remove(mdFile);
|
|
944
|
+
await super.postDeleteTasks(customerKey, [`${this.definition.type}-doc.md`]);
|
|
869
945
|
}
|
|
870
946
|
|
|
871
947
|
/**
|
|
@@ -988,45 +1064,6 @@ class DataExtension extends MetadataType {
|
|
|
988
1064
|
}
|
|
989
1065
|
}
|
|
990
1066
|
}
|
|
991
|
-
/**
|
|
992
|
-
* parses retrieved Metadata before saving
|
|
993
|
-
*
|
|
994
|
-
* @private
|
|
995
|
-
* @param {TYPE.DataExtensionItem} metadata a single dataExtension definition
|
|
996
|
-
* @returns {TYPE.DataExtensionItem} a single dataExtension definition
|
|
997
|
-
*/
|
|
998
|
-
static _parseMetadata(metadata) {
|
|
999
|
-
this.setFolderPath(metadata);
|
|
1000
|
-
|
|
1001
|
-
// DataExtensionTemplate
|
|
1002
|
-
if (metadata.Template?.CustomerKey) {
|
|
1003
|
-
try {
|
|
1004
|
-
metadata.r__dataExtensionTemplate_Name = cache.searchForField(
|
|
1005
|
-
'dataExtensionTemplate',
|
|
1006
|
-
metadata.Template.CustomerKey,
|
|
1007
|
-
'CustomerKey',
|
|
1008
|
-
'Name'
|
|
1009
|
-
);
|
|
1010
|
-
delete metadata.Template;
|
|
1011
|
-
} catch (ex) {
|
|
1012
|
-
Util.logger.debug(ex.message);
|
|
1013
|
-
// Let's allow retrieving such DEs but warn that they cannot be deployed to another BU.
|
|
1014
|
-
// Deploying to same BU still works!
|
|
1015
|
-
// A workaround exists but it's likely not beneficial to explain to users:
|
|
1016
|
-
// Create a DE based on the not-supported template on the target BU, retrieve it, copy the Template.CustomerKey into the to-be-deployed DE (or use mcdev-templating), done
|
|
1017
|
-
Util.logger.warn(
|
|
1018
|
-
` - Issue with dataExtension '${
|
|
1019
|
-
metadata[this.definition.nameField]
|
|
1020
|
-
}': Could not find specified DataExtension Template. Please note that DataExtensions based on SMSMessageTracking and SMSSubscriptionLog cannot be deployed automatically across BUs at this point.`
|
|
1021
|
-
);
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
// remove the date fields manually here because we need them in the changelog but not in the saved json
|
|
1025
|
-
delete metadata.CreatedDate;
|
|
1026
|
-
delete metadata.ModifiedDate;
|
|
1027
|
-
|
|
1028
|
-
return metadata;
|
|
1029
|
-
}
|
|
1030
1067
|
|
|
1031
1068
|
/**
|
|
1032
1069
|
* Retrieves dataExtension metadata and cleans it
|
|
@@ -1037,7 +1074,7 @@ class DataExtension extends MetadataType {
|
|
|
1037
1074
|
* @returns {Promise.<TYPE.DataExtensionMap>} keyField => metadata map
|
|
1038
1075
|
*/
|
|
1039
1076
|
static async _retrieveAll(additionalFields, options) {
|
|
1040
|
-
const { metadata } = await super.retrieveSOAP(null, options, additionalFields);
|
|
1077
|
+
const { metadata } = await super.retrieveSOAP(null, options, null, additionalFields);
|
|
1041
1078
|
for (const key in metadata) {
|
|
1042
1079
|
// some system data extensions do not have CategoryID which throws errors in other places. These do not need to be parsed
|
|
1043
1080
|
if (metadata[key].CategoryID) {
|