mcdev 4.3.1 → 4.3.3
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 +14 -0
- package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -14
- package/.github/pr-labeler.yml +1 -1
- package/.github/workflows/close_issues_on_merge.yml +1 -0
- package/.github/workflows/code-analysis.yml +2 -2
- package/boilerplate/gitignore-template +1 -0
- package/docs/dist/documentation.md +0 -37
- package/lib/Deployer.js +7 -1
- package/lib/metadataTypes/AccountUser.js +42 -13
- package/lib/metadataTypes/Asset.js +29 -15
- package/lib/metadataTypes/Automation.js +13 -7
- package/lib/metadataTypes/DataExtensionField.js +5 -3
- package/lib/metadataTypes/EmailSendDefinition.js +51 -15
- package/lib/metadataTypes/List.js +17 -15
- package/lib/metadataTypes/MetadataType.js +1 -1
- package/lib/metadataTypes/TriggeredSendDefinition.js +6 -5
- package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +52 -31
- package/lib/util/auth.js +1 -1
- package/lib/util/devops.js +8 -4
- package/package.json +1 -1
- package/test/mockRoot/.mcdevrc.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"name": "Create PR to develop branch",
|
|
4
|
+
"target": "ref",
|
|
5
|
+
"refTargets": [
|
|
6
|
+
"localbranch",
|
|
7
|
+
"remotebranch"
|
|
8
|
+
],
|
|
9
|
+
"action": {
|
|
10
|
+
"type": "url",
|
|
11
|
+
"url": "https://github.com/Accenture/sfmc-devtools/compare/develop...$shortname?expand=1"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
]
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
# PR details
|
|
2
2
|
|
|
3
|
-
## What is the purpose of this pull request? (put an "X" next to an item)
|
|
4
|
-
|
|
5
|
-
_Please delete options that are not relevant._
|
|
6
|
-
|
|
7
|
-
- [ ] Documentation update
|
|
8
|
-
- [ ] Bugfix
|
|
9
|
-
- [ ] New metadata support
|
|
10
|
-
- [ ] Enhanced metadata
|
|
11
|
-
- [ ] Add a CLI option
|
|
12
|
-
- [ ] Add something to the core
|
|
13
|
-
- [ ] Technical debt removed
|
|
14
|
-
- [ ] Dependencies added / updated
|
|
15
|
-
- [ ] Other, please explain:
|
|
16
|
-
|
|
17
3
|
## What changes did you make? (Give an overview)
|
|
18
4
|
|
|
19
5
|
...
|
package/.github/pr-labeler.yml
CHANGED
|
@@ -13,10 +13,10 @@ name: 'CodeAnalysis'
|
|
|
13
13
|
|
|
14
14
|
on:
|
|
15
15
|
push:
|
|
16
|
-
branches: [main, develop]
|
|
16
|
+
branches: [main, develop, hotfix]
|
|
17
17
|
pull_request:
|
|
18
18
|
# The branches below must be a subset of the branches above
|
|
19
|
-
branches: [main, develop]
|
|
19
|
+
branches: [main, develop, hotfix]
|
|
20
20
|
|
|
21
21
|
jobs:
|
|
22
22
|
analyzeAndTest:
|
|
@@ -736,10 +736,7 @@ MessageSendActivity MetadataType
|
|
|
736
736
|
* [AccountUser](#AccountUser) ⇐ [<code>MetadataType</code>](#MetadataType)
|
|
737
737
|
* [.retrieve(retrieveDir, _, [__], [key])](#AccountUser.retrieve) ⇒ <code>Promise.<TYPE.MetadataTypeMapObj></code>
|
|
738
738
|
* [.retrieveChangelog()](#AccountUser.retrieveChangelog) ⇒ <code>Promise.<TYPE.MetadataTypeMapObj></code>
|
|
739
|
-
* [.timeSinceDate(date)](#AccountUser.timeSinceDate) ⇒ <code>number</code>
|
|
740
|
-
* [.getBuName(id)](#AccountUser.getBuName) ⇒ <code>string</code>
|
|
741
739
|
* [.document([metadata])](#AccountUser.document) ⇒ <code>Promise.<void></code>
|
|
742
|
-
* [._generateDocMd(users, type, columnsToPrint)](#AccountUser._generateDocMd) ⇒ <code>string</code>
|
|
743
740
|
* [.postRetrieveTasks(metadata)](#AccountUser.postRetrieveTasks) ⇒ <code>TYPE.MetadataTypeItem</code>
|
|
744
741
|
* [.parseMetadata(metadata)](#AccountUser.parseMetadata) ⇒ <code>TYPE.MetadataTypeItem</code>
|
|
745
742
|
|
|
@@ -765,28 +762,6 @@ Retrieves SOAP based metadata of metadata type into local filesystem. executes c
|
|
|
765
762
|
|
|
766
763
|
**Kind**: static method of [<code>AccountUser</code>](#AccountUser)
|
|
767
764
|
**Returns**: <code>Promise.<TYPE.MetadataTypeMapObj></code> - Promise of metadata
|
|
768
|
-
<a name="AccountUser.timeSinceDate"></a>
|
|
769
|
-
|
|
770
|
-
### AccountUser.timeSinceDate(date) ⇒ <code>number</code>
|
|
771
|
-
**Kind**: static method of [<code>AccountUser</code>](#AccountUser)
|
|
772
|
-
**Returns**: <code>number</code> - time difference
|
|
773
|
-
|
|
774
|
-
| Param | Type | Description |
|
|
775
|
-
| --- | --- | --- |
|
|
776
|
-
| date | <code>string</code> | first date |
|
|
777
|
-
|
|
778
|
-
<a name="AccountUser.getBuName"></a>
|
|
779
|
-
|
|
780
|
-
### AccountUser.getBuName(id) ⇒ <code>string</code>
|
|
781
|
-
helper to print bu names
|
|
782
|
-
|
|
783
|
-
**Kind**: static method of [<code>AccountUser</code>](#AccountUser)
|
|
784
|
-
**Returns**: <code>string</code> - "bu name (bu id)""
|
|
785
|
-
|
|
786
|
-
| Param | Type | Description |
|
|
787
|
-
| --- | --- | --- |
|
|
788
|
-
| id | <code>number</code> | bu id |
|
|
789
|
-
|
|
790
765
|
<a name="AccountUser.document"></a>
|
|
791
766
|
|
|
792
767
|
### AccountUser.document([metadata]) ⇒ <code>Promise.<void></code>
|
|
@@ -799,18 +774,6 @@ Creates markdown documentation of all roles
|
|
|
799
774
|
| --- | --- | --- |
|
|
800
775
|
| [metadata] | <code>TYPE.MetadataTypeMap</code> | user list |
|
|
801
776
|
|
|
802
|
-
<a name="AccountUser._generateDocMd"></a>
|
|
803
|
-
|
|
804
|
-
### AccountUser.\_generateDocMd(users, type, columnsToPrint) ⇒ <code>string</code>
|
|
805
|
-
**Kind**: static method of [<code>AccountUser</code>](#AccountUser)
|
|
806
|
-
**Returns**: <code>string</code> - markdown
|
|
807
|
-
|
|
808
|
-
| Param | Type | Description |
|
|
809
|
-
| --- | --- | --- |
|
|
810
|
-
| users | <code>Array.<object></code> | list of users and installed package |
|
|
811
|
-
| type | <code>'Installed Package'</code> \| <code>'User'</code> | choose what sub type to print |
|
|
812
|
-
| columnsToPrint | <code>Array.<Array></code> | helper array |
|
|
813
|
-
|
|
814
777
|
<a name="AccountUser.postRetrieveTasks"></a>
|
|
815
778
|
|
|
816
779
|
### AccountUser.postRetrieveTasks(metadata) ⇒ <code>TYPE.MetadataTypeItem</code>
|
package/lib/Deployer.js
CHANGED
|
@@ -333,7 +333,13 @@ class Deployer {
|
|
|
333
333
|
const folderMetadata = {};
|
|
334
334
|
const allowedDeFolderContentTypes = ['dataextension', 'shared_dataextension'];
|
|
335
335
|
for (const metadataType of metadataTypeArr) {
|
|
336
|
-
if
|
|
336
|
+
// check if folder or folder-like metadata type is in dependencies
|
|
337
|
+
if (
|
|
338
|
+
!MetadataTypeInfo[metadataType].definition.dependencies.includes('folder') &&
|
|
339
|
+
!MetadataTypeInfo[metadataType].definition.dependencies.some((dep) =>
|
|
340
|
+
dep.startsWith('folder-')
|
|
341
|
+
)
|
|
342
|
+
) {
|
|
337
343
|
Util.logger.debug(` ☇ skipping ${metadataType} folders: folder not a dependency`);
|
|
338
344
|
continue;
|
|
339
345
|
}
|
|
@@ -60,10 +60,17 @@ class AccountUser extends MetadataType {
|
|
|
60
60
|
for (const item of resultsBatch) {
|
|
61
61
|
this.userIdBuMap[item.AccountUser.AccountUserID] =
|
|
62
62
|
this.userIdBuMap[item.AccountUser.AccountUserID] || [];
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
// push to array if not already in array
|
|
64
|
+
if (
|
|
65
|
+
!this.userIdBuMap[item.AccountUser.AccountUserID].some(
|
|
66
|
+
(bu) => bu.ID === item.Account.ID
|
|
67
|
+
)
|
|
68
|
+
) {
|
|
69
|
+
this.userIdBuMap[item.AccountUser.AccountUserID].push({
|
|
70
|
+
ID: item.Account.ID,
|
|
71
|
+
Name: item.Account.Name,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
67
74
|
}
|
|
68
75
|
// get actual user details
|
|
69
76
|
/** @type {TYPE.SoapRequestParams} */
|
|
@@ -114,10 +121,11 @@ class AccountUser extends MetadataType {
|
|
|
114
121
|
}
|
|
115
122
|
/**
|
|
116
123
|
*
|
|
124
|
+
* @private
|
|
117
125
|
* @param {string} date first date
|
|
118
126
|
* @returns {number} time difference
|
|
119
127
|
*/
|
|
120
|
-
static
|
|
128
|
+
static _timeSinceDate(date) {
|
|
121
129
|
const interval = 'days';
|
|
122
130
|
const second = 1000,
|
|
123
131
|
minute = second * 60,
|
|
@@ -172,13 +180,28 @@ class AccountUser extends MetadataType {
|
|
|
172
180
|
/**
|
|
173
181
|
* helper to print bu names
|
|
174
182
|
*
|
|
183
|
+
* @private
|
|
175
184
|
* @param {number} id bu id
|
|
176
185
|
* @returns {string} "bu name (bu id)""
|
|
177
186
|
*/
|
|
178
|
-
static
|
|
187
|
+
static _getBuName(id) {
|
|
179
188
|
const name = this.buObject.eid == id ? '_ParentBU_' : this.buIdName[id];
|
|
180
189
|
return `<nobr>${name} (${id})</nobr>`;
|
|
181
190
|
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* helper that gets BU names from config
|
|
194
|
+
*
|
|
195
|
+
* @private
|
|
196
|
+
*/
|
|
197
|
+
static _getBuNames() {
|
|
198
|
+
this.buIdName = {};
|
|
199
|
+
for (const cred in this.properties.credentials) {
|
|
200
|
+
for (const buName in this.properties.credentials[cred].businessUnits) {
|
|
201
|
+
this.buIdName[this.properties.credentials[cred].businessUnits[buName]] = buName;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
182
205
|
/**
|
|
183
206
|
* Creates markdown documentation of all roles
|
|
184
207
|
*
|
|
@@ -209,7 +232,7 @@ class AccountUser extends MetadataType {
|
|
|
209
232
|
}
|
|
210
233
|
}
|
|
211
234
|
// init map of BU Ids > BU Name
|
|
212
|
-
this.
|
|
235
|
+
this._getBuNames();
|
|
213
236
|
|
|
214
237
|
// initialize permission object
|
|
215
238
|
this.allPermissions = {};
|
|
@@ -244,14 +267,19 @@ class AccountUser extends MetadataType {
|
|
|
244
267
|
}
|
|
245
268
|
let associatedBus = '';
|
|
246
269
|
if (user.AssociatedBusinessUnits__c) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
270
|
+
user.AssociatedBusinessUnits__c.push({
|
|
271
|
+
ID: user.DefaultBusinessUnit,
|
|
272
|
+
});
|
|
273
|
+
// ensure associatedBus have no duplicates
|
|
274
|
+
associatedBus = [
|
|
275
|
+
...new Set(
|
|
276
|
+
user.AssociatedBusinessUnits__c.map((item) => this._getBuName(item.ID))
|
|
277
|
+
),
|
|
278
|
+
]
|
|
251
279
|
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
252
280
|
.join(',<br> ');
|
|
253
281
|
}
|
|
254
|
-
const defaultBUName = this.
|
|
282
|
+
const defaultBUName = this._getBuName(user.DefaultBusinessUnit);
|
|
255
283
|
users.push({
|
|
256
284
|
TYPE: user.type__c,
|
|
257
285
|
UserID: user.UserID,
|
|
@@ -267,7 +295,7 @@ class AccountUser extends MetadataType {
|
|
|
267
295
|
AssociatedBusinessUnits__c: associatedBus,
|
|
268
296
|
Roles: roles,
|
|
269
297
|
UserPermissions: userPermissions,
|
|
270
|
-
LastSuccessfulLogin: this.
|
|
298
|
+
LastSuccessfulLogin: this._timeSinceDate(user.LastSuccessfulLogin),
|
|
271
299
|
CreatedDate: user.CreatedDate.split('T').join(' '),
|
|
272
300
|
ModifiedDate: user.ModifiedDate.split('T').join(' '),
|
|
273
301
|
});
|
|
@@ -325,6 +353,7 @@ class AccountUser extends MetadataType {
|
|
|
325
353
|
}
|
|
326
354
|
/**
|
|
327
355
|
*
|
|
356
|
+
* @private
|
|
328
357
|
* @param {object[]} users list of users and installed package
|
|
329
358
|
* @param {'Installed Package'|'User'} type choose what sub type to print
|
|
330
359
|
* @param {Array[]} columnsToPrint helper array
|
|
@@ -317,22 +317,30 @@ class Asset extends MetadataType {
|
|
|
317
317
|
} catch (ex) {
|
|
318
318
|
failed.push({ item: item, error: ex });
|
|
319
319
|
}
|
|
320
|
+
// even if the extended file failed, still save the metadata
|
|
320
321
|
metadata[item.customerKey] = item;
|
|
321
322
|
}
|
|
322
323
|
// this is a complex type which stores data in the asset itself
|
|
323
324
|
else if (!completed.includes(item.id)) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
try {
|
|
326
|
+
const extendedItem = await this.client.rest.get(
|
|
327
|
+
'asset/v1/content/assets/' + item.id
|
|
328
|
+
);
|
|
329
|
+
// only save the metadata if we have extended content
|
|
330
|
+
metadata[item.customerKey] = extendedItem;
|
|
331
|
+
} catch (ex) {
|
|
332
|
+
failed.push({ item: item, error: ex });
|
|
333
|
+
}
|
|
328
334
|
}
|
|
329
335
|
completed.push(item.id);
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
+
if (metadata[item.customerKey]) {
|
|
337
|
+
await this.saveResults(
|
|
338
|
+
metadata,
|
|
339
|
+
retrieveDir,
|
|
340
|
+
'asset-' + subType,
|
|
341
|
+
templateVariables
|
|
342
|
+
);
|
|
343
|
+
}
|
|
336
344
|
// update the current value in your application..
|
|
337
345
|
extendedBar.increment();
|
|
338
346
|
})
|
|
@@ -346,7 +354,7 @@ class Asset extends MetadataType {
|
|
|
346
354
|
} catch (ex) {
|
|
347
355
|
extendedBar.stop();
|
|
348
356
|
Asset._resetLogLevel(loggerLevelBak, failed);
|
|
349
|
-
// timeouts should be retried, others can be
|
|
357
|
+
// timeouts should be retried, others can be exited
|
|
350
358
|
if (ex.code !== 'ETIMEDOUT') {
|
|
351
359
|
throw ex;
|
|
352
360
|
}
|
|
@@ -394,11 +402,17 @@ class Asset extends MetadataType {
|
|
|
394
402
|
);
|
|
395
403
|
for (const fail of failed) {
|
|
396
404
|
Util.logger.warn(
|
|
397
|
-
` -
|
|
405
|
+
` - "${fail.item.name}" (${fail.item.customerKey}): ${fail.error.message} (${
|
|
406
|
+
fail.error.code
|
|
407
|
+
})${
|
|
408
|
+
fail.error.endpoint
|
|
409
|
+
? Util.getGrayMsg(
|
|
410
|
+
' - ' +
|
|
411
|
+
fail.error.endpoint.split('rest.marketingcloudapis.com')[1]
|
|
412
|
+
)
|
|
413
|
+
: ''
|
|
414
|
+
}`
|
|
398
415
|
);
|
|
399
|
-
Util.logger.debug(`-- Error: ${fail.error.message}`);
|
|
400
|
-
Util.logger.debug(`-- AssetType: ${fail.item.assetType.name}`);
|
|
401
|
-
Util.logger.debug(`-- fileProperties: ${JSON.stringify(fail.item.fileProperties)}`);
|
|
402
416
|
}
|
|
403
417
|
Util.logger.info(
|
|
404
418
|
' - You will still find a JSON file for each of these in the download directory.'
|
|
@@ -419,6 +419,14 @@ class Automation extends MetadataType {
|
|
|
419
419
|
}
|
|
420
420
|
if (schedule !== null) {
|
|
421
421
|
try {
|
|
422
|
+
// remove the fields that are not needed for the schedule but only for CLI output
|
|
423
|
+
const schedule_StartDateTime = schedule._StartDateTime;
|
|
424
|
+
delete schedule._StartDateTime;
|
|
425
|
+
const schedule_interval = schedule._interval;
|
|
426
|
+
delete schedule._interval;
|
|
427
|
+
const schedule_timezoneString = schedule._timezoneString;
|
|
428
|
+
delete schedule._timezoneString;
|
|
429
|
+
// start the automation
|
|
422
430
|
await this.client.soap.schedule(
|
|
423
431
|
'Automation',
|
|
424
432
|
schedule,
|
|
@@ -431,17 +439,17 @@ class Automation extends MetadataType {
|
|
|
431
439
|
{}
|
|
432
440
|
);
|
|
433
441
|
const intervalString =
|
|
434
|
-
(
|
|
442
|
+
(schedule_interval > 1 ? `${schedule_interval} ` : '') +
|
|
435
443
|
(schedule.RecurrenceType === 'Daily'
|
|
436
444
|
? 'Day'
|
|
437
445
|
: schedule.RecurrenceType.slice(0, -2) +
|
|
438
|
-
(
|
|
446
|
+
(schedule_interval > 1 ? 's' : ''));
|
|
439
447
|
Util.logger.warn(
|
|
440
448
|
` - scheduled automation '${
|
|
441
449
|
originalMetadata[key].name
|
|
442
450
|
}' deployed Active: runs every ${intervalString} starting ${
|
|
443
|
-
|
|
444
|
-
} ${
|
|
451
|
+
schedule_StartDateTime.split('T').join(' ').split('.')[0]
|
|
452
|
+
} ${schedule_timezoneString}`
|
|
445
453
|
);
|
|
446
454
|
} catch (ex) {
|
|
447
455
|
Util.logger.error(
|
|
@@ -673,9 +681,7 @@ class Automation extends MetadataType {
|
|
|
673
681
|
? 'ByDay'
|
|
674
682
|
: 'Interval';
|
|
675
683
|
schedule.Recurrence[keyStem + 'lyRecurrencePatternType'] = patternType;
|
|
676
|
-
schedule.Recurrence['
|
|
677
|
-
'xsi:type': keyStem + 'lyRecurrence',
|
|
678
|
-
};
|
|
684
|
+
schedule.Recurrence['@_xsi:type'] = keyStem + 'lyRecurrence';
|
|
679
685
|
schedule.RecurrenceType = keyStem + 'ly';
|
|
680
686
|
if (keyStem === 'Dai') {
|
|
681
687
|
schedule.Recurrence['DayInterval'] = recurHelper.INTERVAL;
|
|
@@ -242,9 +242,11 @@ class DataExtensionField extends MetadataType {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
Util.logger.info(
|
|
245
|
-
|
|
246
|
-
deployColumns.length
|
|
247
|
-
|
|
245
|
+
Util.getGrayMsg(
|
|
246
|
+
` - Found ${deployColumns.length} added/updated Fields for ${deKey}${
|
|
247
|
+
deployColumns.length ? ': ' : ''
|
|
248
|
+
}` + deployColumns.map((item) => item.Name).join(', ')
|
|
249
|
+
)
|
|
248
250
|
);
|
|
249
251
|
return existingFieldByName;
|
|
250
252
|
}
|
|
@@ -104,15 +104,33 @@ class EmailSendDefinition extends MetadataType {
|
|
|
104
104
|
delete metadata.r__email_Name;
|
|
105
105
|
} else if (metadata.r__assetMessage_Key) {
|
|
106
106
|
// content builder
|
|
107
|
-
// * this ignores r__assetMessage_Name on purpose as that is only unique per parent folder but useful during PR reviews
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
// * this ignores r__assetMessage_Name on purpose\ as that is only unique per parent folder but useful during PR reviews
|
|
108
|
+
// will try to find the key with the bu mid at the end, if unable, will try to find the key without it
|
|
109
|
+
try {
|
|
110
|
+
// check asset key as provided
|
|
111
|
+
metadata.Email.ID = cache.searchForField(
|
|
112
|
+
'asset',
|
|
113
|
+
metadata.r__assetMessage_Key,
|
|
114
|
+
'customerKey',
|
|
115
|
+
'legacyData.legacyId'
|
|
116
|
+
);
|
|
117
|
+
delete metadata.r__assetMessage_Key;
|
|
118
|
+
delete metadata.r__assetMessage_Name;
|
|
119
|
+
} catch {
|
|
120
|
+
// if we deploy to another BU, try applying the BU's MID to the end, which we do in preDeployTasks for assets
|
|
121
|
+
|
|
122
|
+
// get suffix to update customer key at the end
|
|
123
|
+
const suffix = '-' + this.buObject.mid;
|
|
124
|
+
|
|
125
|
+
metadata.Email.ID = cache.searchForField(
|
|
126
|
+
'asset',
|
|
127
|
+
metadata.r__assetMessage_Key.slice(0, Math.max(0, 36 - suffix.length)) + suffix,
|
|
128
|
+
'customerKey',
|
|
129
|
+
'legacyData.legacyId'
|
|
130
|
+
);
|
|
131
|
+
delete metadata.r__assetMessage_Key;
|
|
132
|
+
delete metadata.r__assetMessage_Name;
|
|
133
|
+
}
|
|
116
134
|
}
|
|
117
135
|
// Target Audience DataExtension
|
|
118
136
|
// normalize first because this can be an array
|
|
@@ -129,7 +147,7 @@ class EmailSendDefinition extends MetadataType {
|
|
|
129
147
|
if (sdl.r__dataExtension_Key) {
|
|
130
148
|
if (sdl.DataSourceTypeID !== 'CustomObject') {
|
|
131
149
|
throw new Error(
|
|
132
|
-
`
|
|
150
|
+
` ☇ skipping ${this.definition.type} ${metadata.Name} (${metadata.CustomerKey}): Expecting DataSourceTypeID to equal 'CustomObject' when r__dataExtension_Key is defined; Found '${sdl.DataSourceTypeID}'`
|
|
133
151
|
);
|
|
134
152
|
}
|
|
135
153
|
sdl.CustomObjectID = cache.searchForField(
|
|
@@ -141,9 +159,13 @@ class EmailSendDefinition extends MetadataType {
|
|
|
141
159
|
delete sdl.r__dataExtension_Key;
|
|
142
160
|
} else if (sdl.DataSourceTypeID === 'CustomObject') {
|
|
143
161
|
throw new Error(
|
|
144
|
-
`
|
|
162
|
+
` ☇ skipping ${this.definition.type} ${metadata.Name} (${metadata.CustomerKey}): Expecting r__dataExtension_Key to be defined if DataSourceTypeID='CustomObject'`
|
|
145
163
|
);
|
|
146
164
|
}
|
|
165
|
+
if (!sdl.SalesForceObjectID || sdl.SalesForceObjectID === '') {
|
|
166
|
+
// otherwise this causes error 42117 / invalid ObjectID
|
|
167
|
+
delete sdl.SalesForceObjectID;
|
|
168
|
+
}
|
|
147
169
|
// get List (required)
|
|
148
170
|
if (sdl.r__list_PathName) {
|
|
149
171
|
sdl.List = {
|
|
@@ -152,7 +174,7 @@ class EmailSendDefinition extends MetadataType {
|
|
|
152
174
|
delete sdl.r__list_PathName;
|
|
153
175
|
} else {
|
|
154
176
|
throw new Error(
|
|
155
|
-
`Field SendDefinitionList.r__list_PathName was not defined. Please try re-retrieving this ESD from your source BU.`
|
|
177
|
+
` ☇ skipping ${this.definition.type} ${metadata.Name} (${metadata.CustomerKey}) Field SendDefinitionList.r__list_PathName was not defined. Please try re-retrieving this ESD from your source BU.`
|
|
156
178
|
);
|
|
157
179
|
}
|
|
158
180
|
}
|
|
@@ -208,7 +230,11 @@ class EmailSendDefinition extends MetadataType {
|
|
|
208
230
|
delete metadata.Email;
|
|
209
231
|
} catch {
|
|
210
232
|
Util.logger.warn(
|
|
211
|
-
` - ${this.definition.
|
|
233
|
+
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
|
|
234
|
+
metadata[this.definition.keyField]
|
|
235
|
+
}): Could not find email with ID ${
|
|
236
|
+
metadata.Email.ID
|
|
237
|
+
} in Classic nor in Content Builder.`
|
|
212
238
|
);
|
|
213
239
|
}
|
|
214
240
|
}
|
|
@@ -234,7 +260,11 @@ class EmailSendDefinition extends MetadataType {
|
|
|
234
260
|
delete sdl.CustomObjectID;
|
|
235
261
|
} catch {
|
|
236
262
|
Util.logger.warn(
|
|
237
|
-
` - ${this.definition.
|
|
263
|
+
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
|
|
264
|
+
metadata[this.definition.keyField]
|
|
265
|
+
}): Could not find Target Audience (DataExtension) with ObjectID ${
|
|
266
|
+
sdl.CustomObjectID
|
|
267
|
+
}.`
|
|
238
268
|
);
|
|
239
269
|
}
|
|
240
270
|
}
|
|
@@ -245,10 +275,16 @@ class EmailSendDefinition extends MetadataType {
|
|
|
245
275
|
delete sdl.List;
|
|
246
276
|
} catch (ex) {
|
|
247
277
|
Util.logger.warn(
|
|
248
|
-
` - ${this.definition.
|
|
278
|
+
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
|
|
279
|
+
metadata[this.definition.keyField]
|
|
280
|
+
}): ${ex.message}`
|
|
249
281
|
);
|
|
250
282
|
}
|
|
251
283
|
}
|
|
284
|
+
if (!sdl.SalesForceObjectID) {
|
|
285
|
+
// otherwise this causes error 42117 / invalid ObjectID
|
|
286
|
+
delete sdl.SalesForceObjectID;
|
|
287
|
+
}
|
|
252
288
|
}
|
|
253
289
|
|
|
254
290
|
return metadata;
|
|
@@ -53,21 +53,23 @@ class List extends MetadataType {
|
|
|
53
53
|
*/
|
|
54
54
|
static async retrieveForCache() {
|
|
55
55
|
const results = await this.retrieve();
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
const subTypeArr = [
|
|
57
|
+
'list',
|
|
58
|
+
'mysubs',
|
|
59
|
+
'suppression_list',
|
|
60
|
+
'publication',
|
|
61
|
+
'contextual_suppression_list',
|
|
62
|
+
];
|
|
63
|
+
Util.logger.debug('folders not cached but required for list');
|
|
64
|
+
Util.logger.info(' - Caching dependent Metadata: folder');
|
|
65
|
+
Util.logSubtypes(subTypeArr);
|
|
66
|
+
Folder.client = this.client;
|
|
67
|
+
Folder.buObject = this.buObject;
|
|
68
|
+
Folder.properties = this.properties;
|
|
69
|
+
const result = await Folder.retrieveForCache(null, subTypeArr);
|
|
70
|
+
if (cache.getCache()?.folder) {
|
|
71
|
+
cache.mergeMetadata('folder', result.metadata);
|
|
72
|
+
} else {
|
|
71
73
|
cache.setMetadata('folder', result.metadata);
|
|
72
74
|
}
|
|
73
75
|
for (const metadataEntry in results.metadata) {
|
|
@@ -725,7 +725,7 @@ class MetadataType {
|
|
|
725
725
|
Util.logger.info(
|
|
726
726
|
` - updated ${this.definition.type}: ${
|
|
727
727
|
metadataEntry[this.definition.keyField]
|
|
728
|
-
} /
|
|
728
|
+
} / ${metadataEntry[this.definition.nameField]}`
|
|
729
729
|
);
|
|
730
730
|
}
|
|
731
731
|
return response;
|
|
@@ -132,8 +132,9 @@ class TriggeredSendDefinition extends MetadataType {
|
|
|
132
132
|
this.setFolderPath(metadata);
|
|
133
133
|
} catch {
|
|
134
134
|
Util.logger.verbose(
|
|
135
|
-
`
|
|
135
|
+
` ☇ skipping ${this.definition.typeName} '${metadata.Name}'/'${metadata.CustomerKey}': Could not find folder.`
|
|
136
136
|
);
|
|
137
|
+
// do not save this TSD because it would not be visible in the user interface
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
140
|
|
|
@@ -163,9 +164,9 @@ class TriggeredSendDefinition extends MetadataType {
|
|
|
163
164
|
delete metadata.Email;
|
|
164
165
|
} catch {
|
|
165
166
|
Util.logger.verbose(
|
|
166
|
-
` -
|
|
167
|
+
` - ${this.definition.typeName} '${metadata.Name}'/'${metadata.CustomerKey}': Could not find email with ID ${metadata.Email.ID} in Classic nor in Content Builder. This TSD cannot be replublished but potentially restarted with its cached version of the email.`
|
|
167
168
|
);
|
|
168
|
-
|
|
169
|
+
// save this TSD because it could be fixed by the user or potentially restarted without a fix; also, it might be used by a journey
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
// List (optional)
|
|
@@ -175,9 +176,9 @@ class TriggeredSendDefinition extends MetadataType {
|
|
|
175
176
|
delete metadata.List;
|
|
176
177
|
} catch (ex) {
|
|
177
178
|
Util.logger.verbose(
|
|
178
|
-
` -
|
|
179
|
+
` - ${this.definition.typeName} '${metadata.Name}'/'${metadata.CustomerKey}': ${ex.message}`
|
|
179
180
|
);
|
|
180
|
-
|
|
181
|
+
// save this TSD because it could be fixed by the user
|
|
181
182
|
}
|
|
182
183
|
}
|
|
183
184
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
bodyIteratorField: 'Results',
|
|
3
|
-
dependencies: ['folder-userinitiatedsends', 'email', 'asset-message', 'dataExtension', 'list'], // filter,
|
|
3
|
+
dependencies: ['folder-userinitiatedsends', 'email', 'asset-message', 'dataExtension', 'list'], // filter(+), sendClassification(+), SenderProfile(n/a), DeliveryProfile(n/a)
|
|
4
4
|
folderType: 'userinitiatedsends',
|
|
5
5
|
hasExtended: false,
|
|
6
6
|
idField: 'ObjectID',
|
|
@@ -22,31 +22,31 @@ module.exports = {
|
|
|
22
22
|
isCreateable: true,
|
|
23
23
|
isUpdateable: true,
|
|
24
24
|
retrieving: true,
|
|
25
|
-
templating:
|
|
25
|
+
templating: true,
|
|
26
26
|
},
|
|
27
27
|
AutoBccEmail: {
|
|
28
28
|
isCreateable: true,
|
|
29
29
|
isUpdateable: true,
|
|
30
30
|
retrieving: true,
|
|
31
|
-
templating:
|
|
31
|
+
templating: true,
|
|
32
32
|
},
|
|
33
33
|
BccEmail: {
|
|
34
34
|
isCreateable: true,
|
|
35
35
|
isUpdateable: true,
|
|
36
36
|
retrieving: true,
|
|
37
|
-
templating:
|
|
37
|
+
templating: true,
|
|
38
38
|
},
|
|
39
39
|
CategoryID: {
|
|
40
40
|
isCreateable: true,
|
|
41
41
|
isUpdateable: true,
|
|
42
42
|
retrieving: true,
|
|
43
|
-
templating:
|
|
43
|
+
templating: true,
|
|
44
44
|
},
|
|
45
45
|
CCEmail: {
|
|
46
46
|
isCreateable: true,
|
|
47
47
|
isUpdateable: true,
|
|
48
48
|
retrieving: true,
|
|
49
|
-
templating:
|
|
49
|
+
templating: true,
|
|
50
50
|
},
|
|
51
51
|
'Client.ID': {
|
|
52
52
|
isCreateable: false,
|
|
@@ -61,8 +61,8 @@ module.exports = {
|
|
|
61
61
|
templating: false,
|
|
62
62
|
},
|
|
63
63
|
CreatedDate: {
|
|
64
|
-
isCreateable:
|
|
65
|
-
isUpdateable:
|
|
64
|
+
isCreateable: false,
|
|
65
|
+
isUpdateable: false,
|
|
66
66
|
retrieving: true,
|
|
67
67
|
templating: false,
|
|
68
68
|
},
|
|
@@ -70,19 +70,19 @@ module.exports = {
|
|
|
70
70
|
isCreateable: true,
|
|
71
71
|
isUpdateable: true,
|
|
72
72
|
retrieving: true,
|
|
73
|
-
templating:
|
|
73
|
+
templating: true,
|
|
74
74
|
},
|
|
75
75
|
DeduplicateByEmail: {
|
|
76
76
|
isCreateable: true,
|
|
77
77
|
isUpdateable: true,
|
|
78
78
|
retrieving: true,
|
|
79
|
-
templating:
|
|
79
|
+
templating: true,
|
|
80
80
|
},
|
|
81
81
|
'DeliveryProfile.CustomerKey': {
|
|
82
82
|
isCreateable: true,
|
|
83
83
|
isUpdateable: true,
|
|
84
84
|
retrieving: true,
|
|
85
|
-
templating:
|
|
85
|
+
templating: true,
|
|
86
86
|
},
|
|
87
87
|
'DeliveryProfile.DomainType': {
|
|
88
88
|
isCreateable: false,
|
|
@@ -130,13 +130,13 @@ module.exports = {
|
|
|
130
130
|
isCreateable: true,
|
|
131
131
|
isUpdateable: true,
|
|
132
132
|
retrieving: true,
|
|
133
|
-
templating:
|
|
133
|
+
templating: true,
|
|
134
134
|
},
|
|
135
135
|
'DeliveryProfile.PrivateIP': {
|
|
136
136
|
isCreateable: true,
|
|
137
137
|
isUpdateable: true,
|
|
138
138
|
retrieving: true,
|
|
139
|
-
templating:
|
|
139
|
+
templating: true,
|
|
140
140
|
},
|
|
141
141
|
'DeliveryProfile.SourceAddressType': {
|
|
142
142
|
isCreateable: false,
|
|
@@ -154,7 +154,7 @@ module.exports = {
|
|
|
154
154
|
isCreateable: true,
|
|
155
155
|
isUpdateable: true,
|
|
156
156
|
retrieving: true,
|
|
157
|
-
templating:
|
|
157
|
+
templating: true,
|
|
158
158
|
},
|
|
159
159
|
DomainType: {
|
|
160
160
|
isCreateable: false,
|
|
@@ -166,13 +166,13 @@ module.exports = {
|
|
|
166
166
|
isCreateable: true,
|
|
167
167
|
isUpdateable: true,
|
|
168
168
|
retrieving: true,
|
|
169
|
-
templating:
|
|
169
|
+
templating: true,
|
|
170
170
|
},
|
|
171
171
|
'Email.ID': {
|
|
172
172
|
isCreateable: true,
|
|
173
173
|
isUpdateable: true,
|
|
174
174
|
retrieving: true,
|
|
175
|
-
templating:
|
|
175
|
+
templating: true,
|
|
176
176
|
},
|
|
177
177
|
'Email.ObjectID': {
|
|
178
178
|
isCreateable: false,
|
|
@@ -186,17 +186,35 @@ module.exports = {
|
|
|
186
186
|
retrieving: false,
|
|
187
187
|
templating: false,
|
|
188
188
|
},
|
|
189
|
+
'Email.Name': {
|
|
190
|
+
isCreateable: true,
|
|
191
|
+
isUpdateable: true,
|
|
192
|
+
retrieving: false,
|
|
193
|
+
templating: false,
|
|
194
|
+
},
|
|
195
|
+
'Email.Subject': {
|
|
196
|
+
isCreateable: true,
|
|
197
|
+
isUpdateable: true,
|
|
198
|
+
retrieving: false,
|
|
199
|
+
templating: false,
|
|
200
|
+
},
|
|
201
|
+
'Email.Status': {
|
|
202
|
+
isCreateable: true,
|
|
203
|
+
isUpdateable: true,
|
|
204
|
+
retrieving: false,
|
|
205
|
+
templating: false,
|
|
206
|
+
},
|
|
189
207
|
EmailSubject: {
|
|
190
208
|
isCreateable: true,
|
|
191
209
|
isUpdateable: true,
|
|
192
210
|
retrieving: true,
|
|
193
|
-
templating:
|
|
211
|
+
templating: true,
|
|
194
212
|
},
|
|
195
213
|
ExclusionFilter: {
|
|
196
214
|
isCreateable: true,
|
|
197
215
|
isUpdateable: true,
|
|
198
216
|
retrieving: true,
|
|
199
|
-
templating:
|
|
217
|
+
templating: true,
|
|
200
218
|
},
|
|
201
219
|
FooterContentArea: {
|
|
202
220
|
isCreateable: false,
|
|
@@ -256,7 +274,7 @@ module.exports = {
|
|
|
256
274
|
isCreateable: true,
|
|
257
275
|
isUpdateable: true,
|
|
258
276
|
retrieving: true,
|
|
259
|
-
templating:
|
|
277
|
+
templating: true,
|
|
260
278
|
},
|
|
261
279
|
IsPlatformObject: {
|
|
262
280
|
isCreateable: true,
|
|
@@ -280,7 +298,7 @@ module.exports = {
|
|
|
280
298
|
isCreateable: true,
|
|
281
299
|
isUpdateable: true,
|
|
282
300
|
retrieving: true,
|
|
283
|
-
templating:
|
|
301
|
+
templating: true,
|
|
284
302
|
},
|
|
285
303
|
Keyword: {
|
|
286
304
|
isCreateable: false,
|
|
@@ -295,8 +313,8 @@ module.exports = {
|
|
|
295
313
|
templating: false,
|
|
296
314
|
},
|
|
297
315
|
ModifiedDate: {
|
|
298
|
-
isCreateable:
|
|
299
|
-
isUpdateable:
|
|
316
|
+
isCreateable: false,
|
|
317
|
+
isUpdateable: false,
|
|
300
318
|
retrieving: true,
|
|
301
319
|
templating: false,
|
|
302
320
|
},
|
|
@@ -304,7 +322,7 @@ module.exports = {
|
|
|
304
322
|
isCreateable: true,
|
|
305
323
|
isUpdateable: true,
|
|
306
324
|
retrieving: true,
|
|
307
|
-
templating:
|
|
325
|
+
templating: true,
|
|
308
326
|
},
|
|
309
327
|
ObjectID: {
|
|
310
328
|
isCreateable: false,
|
|
@@ -376,7 +394,7 @@ module.exports = {
|
|
|
376
394
|
isCreateable: true,
|
|
377
395
|
isUpdateable: true,
|
|
378
396
|
retrieving: true,
|
|
379
|
-
templating:
|
|
397
|
+
templating: true,
|
|
380
398
|
},
|
|
381
399
|
'SendClassification.ObjectID': {
|
|
382
400
|
isCreateable: false,
|
|
@@ -400,7 +418,7 @@ module.exports = {
|
|
|
400
418
|
isCreateable: true,
|
|
401
419
|
isUpdateable: true,
|
|
402
420
|
retrieving: true,
|
|
403
|
-
templating:
|
|
421
|
+
templating: true,
|
|
404
422
|
},
|
|
405
423
|
'SendDefinitionList[].ObjectID': {
|
|
406
424
|
isCreateable: false,
|
|
@@ -414,6 +432,9 @@ module.exports = {
|
|
|
414
432
|
retrieving: false,
|
|
415
433
|
templating: false,
|
|
416
434
|
},
|
|
435
|
+
'SendDefinitionList[].CustomObjectID': {
|
|
436
|
+
skipValidation: true, // cannot be asked for but will be retrieved
|
|
437
|
+
},
|
|
417
438
|
'SendDefinitionList[].SendDefinitionListType': {
|
|
418
439
|
skipValidation: true, // cannot be asked for but will be retrieved
|
|
419
440
|
},
|
|
@@ -448,7 +469,7 @@ module.exports = {
|
|
|
448
469
|
isCreateable: true,
|
|
449
470
|
isUpdateable: true,
|
|
450
471
|
retrieving: true,
|
|
451
|
-
templating:
|
|
472
|
+
templating: true,
|
|
452
473
|
},
|
|
453
474
|
'SenderProfile.FromAddress': {
|
|
454
475
|
isCreateable: false,
|
|
@@ -478,13 +499,13 @@ module.exports = {
|
|
|
478
499
|
isCreateable: true,
|
|
479
500
|
isUpdateable: true,
|
|
480
501
|
retrieving: true,
|
|
481
|
-
templating:
|
|
502
|
+
templating: true,
|
|
482
503
|
},
|
|
483
504
|
SendWindowClose: {
|
|
484
505
|
isCreateable: true,
|
|
485
506
|
isUpdateable: true,
|
|
486
507
|
retrieving: true,
|
|
487
|
-
templating:
|
|
508
|
+
templating: true,
|
|
488
509
|
},
|
|
489
510
|
SendWindowDelete: {
|
|
490
511
|
isCreateable: false,
|
|
@@ -496,7 +517,7 @@ module.exports = {
|
|
|
496
517
|
isCreateable: true,
|
|
497
518
|
isUpdateable: true,
|
|
498
519
|
retrieving: true,
|
|
499
|
-
templating:
|
|
520
|
+
templating: true,
|
|
500
521
|
},
|
|
501
522
|
SourceAddressType: {
|
|
502
523
|
isCreateable: false,
|
|
@@ -508,13 +529,13 @@ module.exports = {
|
|
|
508
529
|
isCreateable: true,
|
|
509
530
|
isUpdateable: true,
|
|
510
531
|
retrieving: true,
|
|
511
|
-
templating:
|
|
532
|
+
templating: true,
|
|
512
533
|
},
|
|
513
534
|
TestEmailAddr: {
|
|
514
535
|
isCreateable: true,
|
|
515
536
|
isUpdateable: true,
|
|
516
537
|
retrieving: true,
|
|
517
|
-
templating:
|
|
538
|
+
templating: true,
|
|
518
539
|
},
|
|
519
540
|
TimeZone: {
|
|
520
541
|
isCreateable: false,
|
package/lib/util/auth.js
CHANGED
|
@@ -101,7 +101,7 @@ function setupSDK(sessionKey, authObject) {
|
|
|
101
101
|
credentialStore.set(sessionKey, authObject);
|
|
102
102
|
},
|
|
103
103
|
onConnectionError: (ex, remainingAttempts) => {
|
|
104
|
-
Util.logger.
|
|
104
|
+
Util.logger.info(
|
|
105
105
|
` - Connection problem (Code: ${ex.code}). Retrying ${remainingAttempts} time${
|
|
106
106
|
remainingAttempts > 1 ? 's' : ''
|
|
107
107
|
}${
|
package/lib/util/devops.js
CHANGED
|
@@ -111,6 +111,8 @@ const DevOps = {
|
|
|
111
111
|
// Filter to only handle files that start with at least one of the passed filterPaths.
|
|
112
112
|
// ! Filter happens after initial parse, because if file was moved its new path has to be calculated
|
|
113
113
|
.filter((file) => filterPaths.some((path) => file.file.startsWith(path)))
|
|
114
|
+
.filter((file) => !file.file.endsWith('.error.log'))
|
|
115
|
+
.filter((file) => !file.file.endsWith('.md'))
|
|
114
116
|
// ensure badly named files on unsupported metadata types are not in our subset
|
|
115
117
|
.filter((/** @type {TYPE.DeltaPkgItem} */ file) => {
|
|
116
118
|
if (MetadataType[file.type]) {
|
|
@@ -210,10 +212,12 @@ const DevOps = {
|
|
|
210
212
|
const copied = delta.map((file) =>
|
|
211
213
|
File.copyFile(
|
|
212
214
|
file.file,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
215
|
+
path
|
|
216
|
+
.normalize(file.file)
|
|
217
|
+
.replace(
|
|
218
|
+
path.normalize(properties.directories.retrieve),
|
|
219
|
+
path.normalize(properties.directories.deploy)
|
|
220
|
+
)
|
|
217
221
|
)
|
|
218
222
|
);
|
|
219
223
|
const results = await Promise.all(copied);
|
package/package.json
CHANGED