mcdev 5.2.0 → 5.3.0
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/.fork/custom-commands.json +12 -0
- package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
- package/.github/PULL_REQUEST_TEMPLATE/pr_template_release.md +19 -0
- package/docs/dist/documentation.md +400 -9
- package/lib/MetadataTypeDefinitions.js +1 -0
- package/lib/MetadataTypeInfo.js +1 -0
- package/lib/cli.js +6 -1
- package/lib/index.js +4 -1
- package/lib/metadataTypes/AttributeSet.js +118 -11
- package/lib/metadataTypes/Automation.js +99 -70
- package/lib/metadataTypes/DataExtension.js +463 -66
- package/lib/metadataTypes/DataExtensionField.js +30 -13
- package/lib/metadataTypes/Journey.js +8 -1
- package/lib/metadataTypes/MetadataType.js +63 -5
- package/lib/metadataTypes/MobileKeyword.js +1 -1
- package/lib/metadataTypes/TransactionalEmail.js +94 -17
- package/lib/metadataTypes/TransactionalMessage.js +3 -2
- package/lib/metadataTypes/Verification.js +230 -0
- package/lib/metadataTypes/definitions/AttributeGroup.definition.js +2 -2
- package/lib/metadataTypes/definitions/AttributeSet.definition.js +74 -21
- package/lib/metadataTypes/definitions/Automation.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +19 -1
- package/lib/metadataTypes/definitions/Verification.definition.js +88 -0
- package/package.json +6 -6
- package/test/mockRoot/.mcdevrc.json +1 -1
- package/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testExisting_dataExtensionShared.dataExtension-meta.json +59 -0
- package/test/mockRoot/deploy/testInstance/_ParentBU_/dataExtension/testNew_dataExtensionShared.dataExtension-meta.json +23 -0
- package/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json +4 -0
- package/test/mockRoot/deploy/testInstance/testBU/dataExtension/testExisting_dataExtension.dataExtension-meta.json +1 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json +3 -4
- package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json +1 -6
- package/test/mockRoot/deploy/testInstance/testBU/verification/testExisting_39f6a488-20eb-4ba0-b0b9.verification-meta.json +11 -0
- package/test/mockRoot/deploy/testInstance/testBU/verification/testNew_39f6a488-20eb-4ba0-b0b9.verification-meta.json +11 -0
- package/test/resources/1111111/data/v1/customobjectdata/key/testExisting_dataExtensionShared/rowset/get-response.json +13 -0
- package/test/resources/1111111/dataExtension/create-expected.json +23 -0
- package/test/resources/1111111/dataExtension/create-response.xml +59 -0
- package/test/resources/1111111/dataExtension/retrieve-expected.json +55 -0
- package/test/resources/1111111/dataExtension/retrieve-expected.md +18 -0
- package/test/resources/1111111/dataExtension/retrieve-response.xml +27 -1
- package/test/resources/1111111/dataExtension/update-expected.json +55 -0
- package/test/resources/1111111/dataExtension/update-response.xml +57 -0
- package/test/resources/1111111/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtensionShared].[TriggerUpdate_randomNumber_]-response.xml +45 -0
- package/test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml +98 -0
- package/test/resources/1111111/dataExtensionField/retrieve-DataExtension.CustomerKey=testNew_dataExtensionSharedORDataExtension.CustomerKey=testExisting_dataExtensionShared-response.xml +98 -0
- package/test/resources/1111111/dataExtensionField/retrieve-response.xml +98 -0
- package/test/resources/1111111/dataExtensionTemplate/retrieve-response.xml +303 -0
- package/test/resources/1111111/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml +387 -0
- package/test/resources/1111111/dataFolder/retrieve-response.xml +353 -9
- package/test/resources/9999999/attributeSet/retrieve-expected.json +89 -694
- package/test/resources/9999999/automation/build-expected.json +4 -0
- package/test/resources/9999999/automation/create-expected.json +4 -0
- package/test/resources/9999999/automation/create-testNew_automation-expected.md +1 -0
- package/test/resources/9999999/automation/retrieve-expected.json +4 -0
- package/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md +1 -0
- package/test/resources/9999999/automation/template-expected.json +4 -0
- package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json +7 -0
- package/test/resources/9999999/automation/v1/automations/post-response.json +7 -0
- package/test/resources/9999999/automation/v1/dataverifications/post-response.json +12 -0
- package/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/delete-response.json +0 -0
- package/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/get-response.json +12 -0
- package/test/resources/9999999/automation/v1/dataverifications/testExisting_39f6a488-20eb-4ba0-b0b9/patch-response.json +12 -0
- package/test/resources/9999999/dataExtension/build-expected.json +16 -0
- package/test/resources/9999999/dataExtension/delete-response.xml +42 -0
- package/test/resources/9999999/dataExtension/retrieve-expected.json +16 -0
- package/test/resources/9999999/dataExtension/retrieve-expected.md +3 -1
- package/test/resources/9999999/dataExtension/template-expected.json +16 -0
- package/test/resources/9999999/dataExtension/update-expected.json +17 -1
- package/test/resources/9999999/dataExtensionField/retrieve-CustomerKey=[testExisting_dataExtension].[LastName]-response.xml +44 -0
- package/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtension-response.xml +36 -1
- package/test/resources/9999999/dataExtensionField/retrieve-response.xml +36 -1
- package/test/resources/9999999/dataFolder/retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml +117 -0
- package/test/resources/9999999/hub/v1/contacts/schema/attributeGroups/get-response.json +43 -0
- package/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json +387 -0
- package/test/resources/9999999/interaction/v1/interactions/233d4413-922c-4568-85a5-e5cc77efc3be/delete-response.json +1 -0
- package/test/resources/9999999/legacy/v1/beta/bulk/automations/automation/definition/get-response.json +1 -1
- package/test/resources/9999999/messaging/v1/email/definitions/post-response.json +1 -1
- package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/delete-response.json +6 -0
- package/test/resources/9999999/transactionalEmail/build-expected.json +3 -7
- package/test/resources/9999999/transactionalEmail/get-expected.json +3 -7
- package/test/resources/9999999/transactionalEmail/patch-expected.json +3 -7
- package/test/resources/9999999/transactionalEmail/post-expected.json +3 -7
- package/test/resources/9999999/transactionalEmail/template-expected.json +3 -7
- package/test/resources/9999999/verification/build-expected.json +11 -0
- package/test/resources/9999999/verification/get-expected.json +11 -0
- package/test/resources/9999999/verification/patch-expected.json +11 -0
- package/test/resources/9999999/verification/post-expected.json +11 -0
- package/test/resources/9999999/verification/template-expected.json +11 -0
- package/test/type.attributeGroup.test.js +4 -4
- package/test/type.attributeSet.test.js +5 -5
- package/test/type.automation.test.js +29 -23
- package/test/type.dataExtension.test.js +205 -45
- package/test/type.dataExtract.test.js +10 -3
- package/test/type.fileTransfer.test.js +10 -3
- package/test/type.importFile.test.js +10 -3
- package/test/type.journey.test.js +38 -11
- package/test/type.mobileKeyword.test.js +6 -4
- package/test/type.mobileMessage.test.js +6 -4
- package/test/type.query.test.js +8 -6
- package/test/type.script.test.js +6 -1
- package/test/type.transactionalEmail.test.js +12 -11
- package/test/type.transactionalPush.test.js +2 -4
- package/test/type.transactionalSMS.test.js +2 -4
- package/test/type.triggeredSend.test.js +6 -4
- package/test/type.verification.test.js +173 -0
- package/test/utils.js +7 -1
- package/types/mcdev.d.js +14 -0
|
@@ -38,6 +38,7 @@ const MetadataTypeDefinitions = {
|
|
|
38
38
|
transactionalSMS: require('./metadataTypes/definitions/TransactionalSMS.definition'),
|
|
39
39
|
triggeredSend: require('./metadataTypes/definitions/TriggeredSend.definition'),
|
|
40
40
|
user: require('./metadataTypes/definitions/User.definition'),
|
|
41
|
+
verification: require('./metadataTypes/definitions/Verification.definition'),
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
module.exports = MetadataTypeDefinitions;
|
package/lib/MetadataTypeInfo.js
CHANGED
|
@@ -38,6 +38,7 @@ const MetadataTypeInfo = {
|
|
|
38
38
|
transactionalSMS: require('./metadataTypes/TransactionalSMS'),
|
|
39
39
|
triggeredSend: require('./metadataTypes/TriggeredSend'),
|
|
40
40
|
user: require('./metadataTypes/User'),
|
|
41
|
+
verification: require('./metadataTypes/Verification'),
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
module.exports = MetadataTypeInfo;
|
package/lib/cli.js
CHANGED
|
@@ -45,7 +45,7 @@ yargs
|
|
|
45
45
|
},
|
|
46
46
|
})
|
|
47
47
|
.command({
|
|
48
|
-
command: 'deploy [BU] [TYPE] [KEY]
|
|
48
|
+
command: 'deploy [BU] [TYPE] [KEY]',
|
|
49
49
|
aliases: ['d'],
|
|
50
50
|
desc: 'deploys local metadata to a business unit',
|
|
51
51
|
builder: (yargs) => {
|
|
@@ -97,6 +97,11 @@ yargs
|
|
|
97
97
|
group: 'Options for deploy:',
|
|
98
98
|
describe:
|
|
99
99
|
'optionally start existing schedule instead of running item once immediately (only works for automations)',
|
|
100
|
+
})
|
|
101
|
+
.option('fixShared', {
|
|
102
|
+
group: 'Options for deploy:',
|
|
103
|
+
describe:
|
|
104
|
+
"optionally ensure that updates to shared DataExtensions become visible in child BU's data designer (SF Known issue W-11031095)",
|
|
100
105
|
});
|
|
101
106
|
},
|
|
102
107
|
handler: (argv) => {
|
package/lib/index.js
CHANGED
|
@@ -56,12 +56,14 @@ class Mcdev {
|
|
|
56
56
|
'commitHistory',
|
|
57
57
|
'execute',
|
|
58
58
|
'filter',
|
|
59
|
+
'fixShared',
|
|
59
60
|
'fromRetrieve',
|
|
60
61
|
'json',
|
|
61
62
|
'like',
|
|
62
63
|
'noLogColors',
|
|
63
64
|
'noLogFile',
|
|
64
65
|
'refresh',
|
|
66
|
+
'_runningTest',
|
|
65
67
|
'schedule',
|
|
66
68
|
'skipInteraction',
|
|
67
69
|
];
|
|
@@ -310,7 +312,8 @@ class Mcdev {
|
|
|
310
312
|
triggeredSend: 'triggeredSendDefinition',
|
|
311
313
|
user: 'accountUser',
|
|
312
314
|
};
|
|
313
|
-
Util.logger.info(
|
|
315
|
+
Util.logger.info('');
|
|
316
|
+
Util.logger.info(`:: Retrieving ${cred}/${bu}`);
|
|
314
317
|
const retrieveTypesArr = [];
|
|
315
318
|
if (selectedTypesArr) {
|
|
316
319
|
for (const selectedType of Array.isArray(selectedTypesArr)
|
|
@@ -31,13 +31,7 @@ class AttributeSet extends MetadataType {
|
|
|
31
31
|
const result = await AttributeGroup.retrieveForCache();
|
|
32
32
|
cache.setMetadata('attributeGroup', result.metadata);
|
|
33
33
|
}
|
|
34
|
-
return super.retrieveREST(
|
|
35
|
-
retrieveDir,
|
|
36
|
-
'/hub/v1/contacts/schema/setDefinitions',
|
|
37
|
-
null,
|
|
38
|
-
null,
|
|
39
|
-
key
|
|
40
|
-
);
|
|
34
|
+
return super.retrieveREST(retrieveDir, '/hub/v1/contacts/schema/setDefinitions', null, key);
|
|
41
35
|
}
|
|
42
36
|
/**
|
|
43
37
|
* Retrieves Metadata of schema set definitions for caching.
|
|
@@ -47,6 +41,110 @@ class AttributeSet extends MetadataType {
|
|
|
47
41
|
static retrieveForCache() {
|
|
48
42
|
return super.retrieveREST(null, '/hub/v1/contacts/schema/setDefinitions');
|
|
49
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* used to identify updated shared data extensions that are used in attributeSets.
|
|
46
|
+
* helper for DataExtension.#fixShared_onBU
|
|
47
|
+
*
|
|
48
|
+
* @param {Object.<string, string>} sharedDataExtensionMap ID-Key relationship of shared data extensions
|
|
49
|
+
* @param {object} fixShared_fields DataExtensionField.fixShared_fields
|
|
50
|
+
* @returns {Promise.<string[]>} Promise of list of shared dataExtension IDs
|
|
51
|
+
*/
|
|
52
|
+
static async fixShared_retrieve(sharedDataExtensionMap, fixShared_fields) {
|
|
53
|
+
if (!Object.keys(sharedDataExtensionMap).length) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
const result = await super.retrieveREST(null, '/hub/v1/contacts/schema/setDefinitions');
|
|
57
|
+
const metadataMap = result?.metadata;
|
|
58
|
+
if (metadataMap && Object.keys(metadataMap).length) {
|
|
59
|
+
const sharedDeIds = Object.keys(metadataMap)
|
|
60
|
+
.filter(
|
|
61
|
+
(asKey) =>
|
|
62
|
+
metadataMap[asKey].storageLogicalType === 'ExactTargetSchema' ||
|
|
63
|
+
metadataMap[asKey].storageLogicalType === 'DataExtension'
|
|
64
|
+
)
|
|
65
|
+
.filter((asKey) => {
|
|
66
|
+
// check if dataExtension ID is found on any attributeSet of this BU
|
|
67
|
+
if (sharedDataExtensionMap[metadataMap[asKey].storageReferenceID.value]) {
|
|
68
|
+
Util.logger.debug(
|
|
69
|
+
` shared dataExtension ID ${metadataMap[asKey].storageReferenceID.value} found in attributeSet ${asKey}`
|
|
70
|
+
);
|
|
71
|
+
return true;
|
|
72
|
+
} else {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
.filter((asKey) => {
|
|
77
|
+
// check if any of the dataExtension fields dont exist on the attributeSet or are out of date
|
|
78
|
+
const deKey =
|
|
79
|
+
sharedDataExtensionMap[metadataMap[asKey].storageReferenceID.value];
|
|
80
|
+
const asFields = metadataMap[asKey].valueDefinitions;
|
|
81
|
+
const deFields = Object.values(fixShared_fields[deKey]);
|
|
82
|
+
return deFields.some((deField) => {
|
|
83
|
+
const search = asFields.filter((asf) => asf.name === deField.Name);
|
|
84
|
+
if (!search.length) {
|
|
85
|
+
Util.logger.debug(
|
|
86
|
+
Util.getGrayMsg(
|
|
87
|
+
` - Field ${deField.Name} not found in attributeSet; Note: only first recognized difference is printed to log`
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
const asField = search[0];
|
|
93
|
+
if (asField.dataType !== deField.FieldType) {
|
|
94
|
+
Util.logger.debug(
|
|
95
|
+
Util.getGrayMsg(
|
|
96
|
+
` - Field ${deField.Name} FieldType changed (old: ${asField.dataType}; new: ${deField.FieldType}); Note: only first recognized difference is printed to log`
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
asField.defaultValue ||= '';
|
|
102
|
+
if (
|
|
103
|
+
(asField.defaultValue && deField.DefaultValue === '') ||
|
|
104
|
+
(deField.FieldType === 'Boolean' &&
|
|
105
|
+
deField.DefaultValue !== '' &&
|
|
106
|
+
(deField.DefaultValue
|
|
107
|
+
? 'True'
|
|
108
|
+
: 'False' !== asField.defaultValue)) ||
|
|
109
|
+
(deField.FieldType !== 'Boolean' &&
|
|
110
|
+
deField.DefaultValue !== asField.defaultValue)
|
|
111
|
+
) {
|
|
112
|
+
Util.logger.debug(
|
|
113
|
+
` - Field ${deField.Name} DefaultValue changed (old: ${asField.defaultValue}; new: ${deField.DefaultValue}); Note: only first recognized difference is printed to log`
|
|
114
|
+
);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
// some field types don't carry the length property. reset to 0 to ease comparison
|
|
118
|
+
asField.length ||= 0;
|
|
119
|
+
if (asField.length !== deField.MaxLength) {
|
|
120
|
+
Util.logger.debug(
|
|
121
|
+
` - Field ${deField.Name} MaxLength changed (old: ${asField.length}; new: ${deField.MaxLength}); Note: only first recognized difference is printed to log`
|
|
122
|
+
);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
if (asField.isNullable !== deField.IsRequired) {
|
|
126
|
+
Util.logger.debug(
|
|
127
|
+
` - Field ${deField.Name} IsRequired changed (old: ${asField.isNullable}; new: ${deField.IsRequired}); Note: only first recognized difference is printed to log`
|
|
128
|
+
);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
if (asField.isPrimaryKey !== deField.IsPrimaryKey) {
|
|
132
|
+
Util.logger.debug(
|
|
133
|
+
` - Field ${deField.Name} IsPrimaryKey changed (old: ${asField.isPrimaryKey}; new: ${deField.IsPrimaryKey}); Note: only first recognized difference is printed to log`
|
|
134
|
+
);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
return false;
|
|
138
|
+
});
|
|
139
|
+
})
|
|
140
|
+
.map((key) => metadataMap[key].storageReferenceID.value)
|
|
141
|
+
.filter(Boolean);
|
|
142
|
+
return sharedDeIds;
|
|
143
|
+
} else {
|
|
144
|
+
// nothing to do - return empty array
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
50
148
|
|
|
51
149
|
/**
|
|
52
150
|
* Builds map of metadata entries mapped to their keyfields
|
|
@@ -83,7 +181,7 @@ class AttributeSet extends MetadataType {
|
|
|
83
181
|
switch (metadata.storageLogicalType) {
|
|
84
182
|
case 'ExactTargetSchema': // synced / shared DEs
|
|
85
183
|
case 'DataExtension': {
|
|
86
|
-
// local DEs
|
|
184
|
+
// shared / local DEs
|
|
87
185
|
try {
|
|
88
186
|
metadata.r__dataExtension_CustomerKey = cache.searchForField(
|
|
89
187
|
'dataExtension',
|
|
@@ -226,6 +324,12 @@ class AttributeSet extends MetadataType {
|
|
|
226
324
|
// Member ID
|
|
227
325
|
delete metadata.customObjectOwnerMID;
|
|
228
326
|
|
|
327
|
+
// remove duplicate ID fields (main field is definitionID)
|
|
328
|
+
delete metadata.setDefinitionID;
|
|
329
|
+
if (metadata.dataRetentionProperties?.setDefinitionID) {
|
|
330
|
+
delete metadata.dataRetentionProperties?.setDefinitionID;
|
|
331
|
+
}
|
|
332
|
+
|
|
229
333
|
// connectingID.identifierType seems to be always set to 'FullyQualifiedName' - to be sure we check it here and remove it if it's the case
|
|
230
334
|
if (metadata.connectingID?.identifierType === 'FullyQualifiedName') {
|
|
231
335
|
// remove useless field
|
|
@@ -241,8 +345,11 @@ class AttributeSet extends MetadataType {
|
|
|
241
345
|
* @returns {object[]} all system value definitions
|
|
242
346
|
*/
|
|
243
347
|
static _getSystemValueDefinitions() {
|
|
244
|
-
|
|
245
|
-
|
|
348
|
+
this.systemValueDefinitions ||= {};
|
|
349
|
+
if (!this.systemValueDefinitions[this.buObject.mid]) {
|
|
350
|
+
this.systemValueDefinitions[this.buObject.mid] = Object.values(
|
|
351
|
+
cache.getCache()['attributeSet']
|
|
352
|
+
)
|
|
246
353
|
.flatMap((item) => {
|
|
247
354
|
if (item.isSystemDefined) {
|
|
248
355
|
return item.valueDefinitions;
|
|
@@ -250,7 +357,7 @@ class AttributeSet extends MetadataType {
|
|
|
250
357
|
})
|
|
251
358
|
.filter(Boolean);
|
|
252
359
|
}
|
|
253
|
-
return this.systemValueDefinitions;
|
|
360
|
+
return this.systemValueDefinitions[this.buObject.mid];
|
|
254
361
|
}
|
|
255
362
|
}
|
|
256
363
|
|
|
@@ -25,71 +25,53 @@ class Automation extends MetadataType {
|
|
|
25
25
|
* @returns {Promise.<TYPE.AutomationMapObj>} Promise of metadata
|
|
26
26
|
*/
|
|
27
27
|
static async retrieve(retrieveDir, _, __, key) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
28
|
+
let metadataMap;
|
|
29
|
+
if (key && this._cachedMetadataMap?.[key]) {
|
|
30
|
+
metadataMap = {};
|
|
31
|
+
metadataMap[key] = this._cachedMetadataMap[key];
|
|
32
|
+
delete this._cachedMetadataMap;
|
|
33
|
+
} else if (!key && this._cachedMetadataMap) {
|
|
34
|
+
metadataMap = this._cachedMetadataMap;
|
|
35
|
+
delete this._cachedMetadataMap;
|
|
36
|
+
} else {
|
|
37
|
+
/** @type {TYPE.SoapRequestParams} */
|
|
38
|
+
let requestParams = null;
|
|
39
|
+
if (key) {
|
|
40
|
+
requestParams = {
|
|
41
|
+
filter: {
|
|
42
|
+
leftOperand: 'CustomerKey',
|
|
43
|
+
operator: 'equals',
|
|
44
|
+
rightOperand: key,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const results = await this.client.soap.retrieveBulk(
|
|
49
|
+
'Program',
|
|
50
|
+
['ObjectID'],
|
|
51
|
+
requestParams
|
|
48
52
|
);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return await this.client.rest.get(
|
|
59
|
-
'/automation/v1/automations/' + item.ObjectID
|
|
60
|
-
);
|
|
61
|
-
} catch (ex) {
|
|
62
|
-
try {
|
|
63
|
-
if (ex.message == 'socket hang up') {
|
|
64
|
-
// one more retry; it's a rare case but retrying again should solve the issue gracefully
|
|
65
|
-
return await this.client.rest.get(
|
|
66
|
-
'/automation/v1/automations/' + item.ObjectID
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
} catch {
|
|
70
|
-
// no extra action needed, handled below
|
|
71
|
-
}
|
|
72
|
-
// if we do get here, we should log the error and continue instead of failing to download all automations
|
|
73
|
-
Util.logger.error(
|
|
74
|
-
` ☇ skipping Automation ${item.ObjectID}: ${ex.message} ${ex.code}`
|
|
75
|
-
);
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
})
|
|
53
|
+
// the API seems to handle 50 concurrent requests nicely
|
|
54
|
+
const response = results?.Results?.length
|
|
55
|
+
? await this.retrieveRESTcollection(
|
|
56
|
+
results?.Results.map((item) => ({
|
|
57
|
+
id: item.ObjectID,
|
|
58
|
+
uri: '/automation/v1/automations/' + item.ObjectID,
|
|
59
|
+
})),
|
|
60
|
+
50,
|
|
61
|
+
!key
|
|
79
62
|
)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// * 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
|
|
84
|
-
let metadataMap = this.parseResponseBody({ items: details.filter(Boolean) });
|
|
63
|
+
: null;
|
|
64
|
+
metadataMap = response?.metadata || {};
|
|
65
|
+
}
|
|
85
66
|
|
|
86
|
-
if (Object.keys(metadataMap).length) {
|
|
67
|
+
if (!this._skipNotificationRetrieve && Object.keys(metadataMap).length) {
|
|
87
68
|
// attach notification information to each automation that has any
|
|
88
69
|
await this.#getAutomationNotificationsREST(metadataMap);
|
|
89
70
|
}
|
|
90
71
|
|
|
91
72
|
// * retrieveDir can be empty when we use it in the context of postDeployTasks
|
|
92
73
|
if (retrieveDir) {
|
|
74
|
+
this.retrieveDir = retrieveDir;
|
|
93
75
|
metadataMap = await this.saveResults(metadataMap, retrieveDir, null, null);
|
|
94
76
|
Util.logger.info(
|
|
95
77
|
`Downloaded: ${this.definition.type} (${Object.keys(metadataMap).length})` +
|
|
@@ -101,6 +83,27 @@ class Automation extends MetadataType {
|
|
|
101
83
|
return { metadata: metadataMap, type: this.definition.type };
|
|
102
84
|
}
|
|
103
85
|
|
|
86
|
+
/**
|
|
87
|
+
* helper for {@link this.retrieveRESTcollection}
|
|
88
|
+
*
|
|
89
|
+
* @param {Error} ex exception
|
|
90
|
+
* @param {string} id id or key of item
|
|
91
|
+
* @returns {null} -
|
|
92
|
+
*/
|
|
93
|
+
static async handleRESTErrors(ex, id) {
|
|
94
|
+
try {
|
|
95
|
+
if (ex.message == 'socket hang up') {
|
|
96
|
+
// one more retry; it's a rare case but retrying again should solve the issue gracefully
|
|
97
|
+
return await this.client.rest.get('/automation/v1/automations/' + id);
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
// no extra action needed, handled below
|
|
101
|
+
}
|
|
102
|
+
// if we do get here, we should log the error and continue instead of failing to download all automations
|
|
103
|
+
Util.logger.error(` ☇ skipping Automation ${id}: ${ex.message} ${ex.code}`);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
104
107
|
/**
|
|
105
108
|
* helper for {@link Automation.retrieve} to get Automation Notifications
|
|
106
109
|
*
|
|
@@ -230,12 +233,18 @@ class Automation extends MetadataType {
|
|
|
230
233
|
* @returns {Promise.<TYPE.AutomationMapObj>} Promise of metadata
|
|
231
234
|
*/
|
|
232
235
|
static async retrieveForCache() {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
let results = {};
|
|
237
|
+
if (this._cachedMetadataMap) {
|
|
238
|
+
results.Results = Object.values(this._cachedMetadataMap);
|
|
239
|
+
delete this._cachedMetadataMap;
|
|
240
|
+
} else {
|
|
241
|
+
// get automations for cache
|
|
242
|
+
results = await this.client.soap.retrieveBulk('Program', [
|
|
243
|
+
'ObjectID',
|
|
244
|
+
'CustomerKey',
|
|
245
|
+
'Name',
|
|
246
|
+
]);
|
|
247
|
+
}
|
|
239
248
|
const resultsConverted = {};
|
|
240
249
|
if (Array.isArray(results?.Results)) {
|
|
241
250
|
// get encodedAutomationID to retrieve notification information
|
|
@@ -252,16 +261,16 @@ class Automation extends MetadataType {
|
|
|
252
261
|
|
|
253
262
|
// merge encodedAutomationID into results
|
|
254
263
|
for (const m of results.Results) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
264
|
+
const key = m.CustomerKey || m.key;
|
|
265
|
+
resultsConverted[key] = {
|
|
266
|
+
id: m.ObjectID || m.id,
|
|
267
|
+
key: key,
|
|
268
|
+
name: m.Name || m.name,
|
|
269
|
+
programId: automationsLegacy.metadata[key]?.id,
|
|
270
|
+
status: automationsLegacy.metadata[key]?.status,
|
|
261
271
|
};
|
|
262
272
|
}
|
|
263
273
|
}
|
|
264
|
-
|
|
265
274
|
return { metadata: resultsConverted, type: this.definition.type };
|
|
266
275
|
}
|
|
267
276
|
|
|
@@ -423,6 +432,7 @@ class Automation extends MetadataType {
|
|
|
423
432
|
} due to missing activityObjectId: ${JSON.stringify(activity)}`
|
|
424
433
|
);
|
|
425
434
|
// empty if block
|
|
435
|
+
continue;
|
|
426
436
|
} else if (!this.definition.dependencies.includes(activity.r__type)) {
|
|
427
437
|
Util.logger.debug(
|
|
428
438
|
` - skipping ${
|
|
@@ -433,9 +443,10 @@ class Automation extends MetadataType {
|
|
|
433
443
|
activity.r__type
|
|
434
444
|
} is not set up as a dependency for ${this.definition.type}`
|
|
435
445
|
);
|
|
446
|
+
continue;
|
|
436
447
|
}
|
|
437
448
|
// / if managed by cache we can update references to support deployment
|
|
438
|
-
|
|
449
|
+
if (
|
|
439
450
|
Definitions[activity.r__type]?.['idField'] &&
|
|
440
451
|
cache.getCache(this.buObject.mid)[activity.r__type]
|
|
441
452
|
) {
|
|
@@ -803,6 +814,7 @@ class Automation extends MetadataType {
|
|
|
803
814
|
delete metadata.schedule;
|
|
804
815
|
delete metadata.type;
|
|
805
816
|
let i = 0;
|
|
817
|
+
const buName = this.buObject.credential + '/' + this.buObject.businessUnit;
|
|
806
818
|
if (metadata.steps) {
|
|
807
819
|
for (const step of metadata.steps) {
|
|
808
820
|
let displayOrder = 0;
|
|
@@ -812,6 +824,23 @@ class Automation extends MetadataType {
|
|
|
812
824
|
activity.name &&
|
|
813
825
|
this.definition.dependencies.includes(activity.r__type)
|
|
814
826
|
) {
|
|
827
|
+
if (
|
|
828
|
+
activity.r__type === 'verification' &&
|
|
829
|
+
this.createdKeyMap?.[buName]?.verification?.[activity.name]
|
|
830
|
+
) {
|
|
831
|
+
Util.logger.info(
|
|
832
|
+
Util.getGrayMsg(
|
|
833
|
+
` - updated verification activity name from ${
|
|
834
|
+
activity.name
|
|
835
|
+
} to ${
|
|
836
|
+
this.createdKeyMap[buName].verification[activity.name]
|
|
837
|
+
}`
|
|
838
|
+
)
|
|
839
|
+
);
|
|
840
|
+
// map structure: cred/bu --> type --> old key --> new key
|
|
841
|
+
activity.name =
|
|
842
|
+
this.createdKeyMap[buName].verification[activity.name];
|
|
843
|
+
}
|
|
815
844
|
// automations can have empty placeholder for activities with only their type defined
|
|
816
845
|
activity.activityObjectId = cache.searchForField(
|
|
817
846
|
activity.r__type,
|