mcdev 7.4.2 → 7.4.4

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.
Files changed (94) hide show
  1. package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
  2. package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
  3. package/@types/lib/metadataTypes/DataExtract.d.ts.map +1 -1
  4. package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
  5. package/@types/lib/metadataTypes/Journey.d.ts +13 -0
  6. package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
  7. package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
  8. package/@types/lib/metadataTypes/Script.d.ts +2 -2
  9. package/@types/lib/metadataTypes/SendClassification.d.ts +12 -0
  10. package/@types/lib/metadataTypes/SendClassification.d.ts.map +1 -1
  11. package/@types/lib/metadataTypes/SenderProfile.d.ts +49 -6
  12. package/@types/lib/metadataTypes/SenderProfile.d.ts.map +1 -1
  13. package/@types/lib/metadataTypes/TransactionalEmail.d.ts +7 -0
  14. package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -1
  15. package/@types/lib/metadataTypes/User.d.ts +10 -2
  16. package/@types/lib/metadataTypes/User.d.ts.map +1 -1
  17. package/@types/lib/metadataTypes/Verification.d.ts.map +1 -1
  18. package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +13 -0
  19. package/@types/lib/metadataTypes/definitions/Script.definition.d.ts +2 -2
  20. package/@types/lib/metadataTypes/definitions/SenderProfile.definition.d.ts +42 -6
  21. package/@types/lib/metadataTypes/definitions/TransactionalEmail.definition.d.ts +7 -0
  22. package/@types/lib/util/validations.d.ts +4 -2
  23. package/@types/lib/util/validations.d.ts.map +1 -1
  24. package/boilerplate/config.json +3 -0
  25. package/boilerplate/files/.prettierrc +6 -0
  26. package/boilerplate/files/eslint.config.js +18 -0
  27. package/boilerplate/forcedUpdates.json +4 -0
  28. package/lib/metadataTypes/DataExtension.js +1 -5
  29. package/lib/metadataTypes/DataExtract.js +29 -0
  30. package/lib/metadataTypes/Event.js +36 -4
  31. package/lib/metadataTypes/Journey.js +216 -41
  32. package/lib/metadataTypes/MetadataType.js +19 -17
  33. package/lib/metadataTypes/SendClassification.js +44 -6
  34. package/lib/metadataTypes/SenderProfile.js +49 -0
  35. package/lib/metadataTypes/TransactionalEmail.js +32 -0
  36. package/lib/metadataTypes/User.js +74 -40
  37. package/lib/metadataTypes/Verification.js +15 -0
  38. package/lib/metadataTypes/definitions/DataExtract.definition.js +1 -1
  39. package/lib/metadataTypes/definitions/Event.definition.js +1 -1
  40. package/lib/metadataTypes/definitions/Journey.definition.js +14 -0
  41. package/lib/metadataTypes/definitions/Script.definition.js +4 -2
  42. package/lib/metadataTypes/definitions/SendClassification.definition.js +1 -1
  43. package/lib/metadataTypes/definitions/SenderProfile.definition.js +54 -21
  44. package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +8 -1
  45. package/lib/metadataTypes/definitions/Verification.definition.js +2 -2
  46. package/lib/util/validations.js +30 -4
  47. package/package.json +1 -1
  48. package/test/general.test.js +21 -21
  49. package/test/mockRoot/.mcdevrc.json +1 -1
  50. package/test/resources/9999999/accountUser/retrieve-response.xml +104 -0
  51. package/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/patch-response.json +2 -2
  52. package/test/resources/9999999/automation/v1/dataextracts/post-response.json +2 -2
  53. package/test/resources/9999999/dataExtract/get-expected.json +2 -2
  54. package/test/resources/9999999/dataExtract/patch-expected.json +2 -2
  55. package/test/resources/9999999/dataExtract/post-expected.json +2 -2
  56. package/test/resources/9999999/event/get-expected.json +2 -2
  57. package/test/resources/9999999/interaction/v1/eventDefinitions/get-response.json +4 -4
  58. package/test/resources/9999999/journey/build-expected.json +1 -0
  59. package/test/resources/9999999/journey/get-multistep-expected.json +1 -0
  60. package/test/resources/9999999/journey/get-quicksend-expected.json +1 -0
  61. package/test/resources/9999999/journey/get-quicksend-rcb-id-expected.json +1 -0
  62. package/test/resources/9999999/journey/get-quicksend-rcb-key-expected.json +1 -0
  63. package/test/resources/9999999/journey/get-quicksend-rcb-name-expected.json +1 -0
  64. package/test/resources/9999999/journey/get-transactionalEmail-expected.json +3 -2
  65. package/test/resources/9999999/journey/template-expected.json +1 -0
  66. package/test/resources/9999999/sendClassification/retrieve-response.xml +4 -4
  67. package/test/resources/9999999/senderProfile/build-expected.json +1 -0
  68. package/test/resources/9999999/senderProfile/create-response.xml +1 -0
  69. package/test/resources/9999999/senderProfile/get-expected.json +4 -1
  70. package/test/resources/9999999/senderProfile/get-rcb-id-expected.json +3 -0
  71. package/test/resources/9999999/senderProfile/get-rcb-key-expected.json +3 -0
  72. package/test/resources/9999999/senderProfile/get-rcb-name-expected.json +3 -0
  73. package/test/resources/9999999/senderProfile/patch-expected.json +1 -0
  74. package/test/resources/9999999/senderProfile/post-expected.json +1 -0
  75. package/test/resources/9999999/senderProfile/retrieve-CustomerKey=Default-response.xml +5 -0
  76. package/test/resources/9999999/senderProfile/retrieve-response.xml +15 -0
  77. package/test/resources/9999999/senderProfile/template-expected.json +1 -0
  78. package/test/resources/9999999/senderProfile/update-response.xml +1 -0
  79. package/test/resources/9999999/transactionalEmail/build-expected.json +2 -2
  80. package/test/resources/9999999/transactionalEmail/get-expected.json +2 -2
  81. package/test/resources/9999999/transactionalEmail/patch-expected.json +2 -2
  82. package/test/resources/9999999/transactionalEmail/post-expected.json +2 -2
  83. package/test/resources/9999999/transactionalEmail/template-expected.json +2 -2
  84. package/test/resources/9999999/verification/get-expected.json +1 -0
  85. package/test/resources/9999999/verification/patch-expected.json +1 -0
  86. package/test/resources/9999999/verification/post-expected.json +1 -0
  87. package/test/type.automation.test.js +4 -4
  88. package/test/type.dataExtract.test.js +4 -4
  89. package/test/type.event.test.js +6 -6
  90. package/test/type.journey.test.js +11 -11
  91. package/test/type.senderProfile.test.js +6 -6
  92. package/test/type.transactionalEmail.test.js +3 -3
  93. package/test/type.user.test.js +2 -2
  94. package/test/type.verification.test.js +3 -3
@@ -65,6 +65,24 @@ export default [
65
65
  'prettier/prettier': 'warn'
66
66
  }
67
67
  },
68
+ {
69
+ files: ['.mcdev-validations.js'],
70
+
71
+ languageOptions: {
72
+ globals: {
73
+ ...globals.nodeBuiltin
74
+ },
75
+
76
+ ecmaVersion: 2022,
77
+ sourceType: 'module'
78
+ },
79
+
80
+ rules: {
81
+ 'no-var': 'error',
82
+ 'prefer-const': 'error',
83
+ 'prettier/prettier': 'warn'
84
+ }
85
+ },
68
86
  {
69
87
  files: ['eslint.config.js'],
70
88
 
@@ -1,4 +1,8 @@
1
1
  [
2
+ {
3
+ "version": "7.4.3",
4
+ "files": ["eslint.config.js", ".prettierrc"]
5
+ },
2
6
  {
3
7
  "version": "7.4.2",
4
8
  "files": [".vscode/settings.json"]
@@ -53,12 +53,8 @@ class DataExtension extends MetadataType {
53
53
  let filteredByPreDeploy = 0;
54
54
  for (const metadataKey in metadataMap) {
55
55
  try {
56
+ await this.validation('deploy', metadataMap[metadataKey], deployDir);
56
57
  metadataMap[metadataKey] = await this.preDeployTasks(metadataMap[metadataKey]);
57
- metadataMap[metadataKey] = await this.validation(
58
- 'deploy',
59
- metadataMap[metadataKey],
60
- deployDir
61
- );
62
58
  } catch (ex) {
63
59
  // output error & remove from deploy list
64
60
  Util.logger.error(
@@ -146,6 +146,35 @@ class DataExtract extends MetadataType {
146
146
  * @returns {MetadataTypeItem} metadata
147
147
  */
148
148
  static postRetrieveTasks(metadata) {
149
+ try {
150
+ metadata.createdBy = cache.searchForField(
151
+ 'user',
152
+ metadata.createdBy,
153
+ 'AccountUserID',
154
+ 'Name'
155
+ );
156
+ } catch (ex) {
157
+ Util.logger.verbose(
158
+ ` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
159
+ metadata[this.definition.keyField]
160
+ }): ${ex.message}.`
161
+ );
162
+ }
163
+
164
+ try {
165
+ metadata.modifiedBy = cache.searchForField(
166
+ 'user',
167
+ metadata.modifiedBy,
168
+ 'AccountUserID',
169
+ 'Name'
170
+ );
171
+ } catch (ex) {
172
+ Util.logger.verbose(
173
+ ` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
174
+ metadata[this.definition.keyField]
175
+ }): ${ex.message}.`
176
+ );
177
+ }
149
178
  try {
150
179
  metadata.r__dataExtractType_name = cache.searchForField(
151
180
  'dataExtractType',
@@ -418,6 +418,36 @@ class Event extends MetadataType {
418
418
  * @returns {Promise.<MetadataTypeItem>} parsed metadata
419
419
  */
420
420
  static async postRetrieveTasks(metadata) {
421
+ try {
422
+ metadata.createdBy = cache.searchForField(
423
+ 'user',
424
+ metadata.createdBy,
425
+ 'AccountUserID',
426
+ 'Name'
427
+ );
428
+ } catch (ex) {
429
+ Util.logger.verbose(
430
+ ` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
431
+ metadata[this.definition.keyField]
432
+ }): ${ex.message}.`
433
+ );
434
+ }
435
+
436
+ try {
437
+ metadata.modifiedBy = cache.searchForField(
438
+ 'user',
439
+ metadata.modifiedBy,
440
+ 'AccountUserID',
441
+ 'Name'
442
+ );
443
+ } catch (ex) {
444
+ Util.logger.verbose(
445
+ ` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
446
+ metadata[this.definition.keyField]
447
+ }): ${ex.message}.`
448
+ );
449
+ }
450
+
421
451
  try {
422
452
  metadata.r__dataExtension_key = cache.searchForField(
423
453
  'dataExtension',
@@ -531,7 +561,7 @@ class Event extends MetadataType {
531
561
  this.sfObjects.objectFields['Lead'] &&
532
562
  !this.sfObjects.workflowObjects.includes(contactLeadName)
533
563
  ) {
534
- Util.logger.info(
564
+ Util.logger.verbose(
535
565
  Util.getGrayMsg(' - Constructing Common / Contacts and Leads object')
536
566
  );
537
567
  // add fake entry to workflowObjects to allow testing for this easily
@@ -622,7 +652,7 @@ class Event extends MetadataType {
622
652
  if (this.sfObjects.objectFields[objectAPIName] || objectAPIName === 'Common') {
623
653
  return;
624
654
  }
625
- Util.logger.info(
655
+ Util.logger.verbose(
626
656
  Util.getGrayMsg(' - Caching Fields for Salesforce Object ' + objectAPIName)
627
657
  );
628
658
 
@@ -870,8 +900,10 @@ class Event extends MetadataType {
870
900
  // throw error if problems were found
871
901
  if (errors?.length) {
872
902
  // add a line break
873
- errors.unshift(``);
874
- throw new Error(errors.join('\n - ')); // eslint-disable-line unicorn/error-message
903
+ if (errors.length > 1) {
904
+ errors.unshift(``);
905
+ }
906
+ throw new Error(errors.join('\n · ')); // eslint-disable-line unicorn/error-message
875
907
  }
876
908
  }
877
909
 
@@ -272,14 +272,31 @@ class Journey extends MetadataType {
272
272
  /**
273
273
  * Deploys metadata - merely kept here to be able to print {@link Util.logBeta} once per deploy
274
274
  *
275
- * @param {MetadataTypeMap} metadata metadata mapped by their keyField
275
+ * @param {MetadataTypeMap} metadataMap metadata mapped by their keyField
276
276
  * @param {string} deployDir directory where deploy metadata are saved
277
277
  * @param {string} retrieveDir directory where metadata after deploy should be saved
278
278
  * @returns {Promise.<MetadataTypeMap>} Promise of keyField => metadata map
279
279
  */
280
- static async deploy(metadata, deployDir, retrieveDir) {
280
+ static async deploy(metadataMap, deployDir, retrieveDir) {
281
281
  Util.logBeta(this.definition.type);
282
- return super.deploy(metadata, deployDir, retrieveDir);
282
+
283
+ let needTransactionalEmail = false;
284
+ for (const key in metadataMap) {
285
+ if (metadataMap[key].definitionType == 'Transactional') {
286
+ needTransactionalEmail = true;
287
+ break;
288
+ }
289
+ }
290
+ if (needTransactionalEmail && !cache.getCache()?.transactionalEmail) {
291
+ // ! interaction and transactionalEmail both link to each other. caching transactionalEmail here "manually", assuming that it's quicker than the other way round
292
+ Util.logger.info(' - Caching dependent Metadata: transactionalEmail');
293
+ TransactionalEmail.buObject = this.buObject;
294
+ TransactionalEmail.client = this.client;
295
+ TransactionalEmail.properties = this.properties;
296
+ const result = await TransactionalEmail.retrieveForCache();
297
+ cache.setMetadata('transactionalEmail', result.metadata);
298
+ }
299
+ return super.deploy(metadataMap, deployDir, retrieveDir);
283
300
  }
284
301
 
285
302
  /**
@@ -499,6 +516,8 @@ class Journey extends MetadataType {
499
516
  delete activity.metaData.highThroughput.definitionKey;
500
517
  }
501
518
 
519
+ this._postRetrieveTasks_activities(metadata);
520
+
502
521
  if (activity.metaData?.highThroughput?.dataExtensionId) {
503
522
  try {
504
523
  activity.metaData.highThroughput.r__dataExtension_key =
@@ -518,9 +537,6 @@ class Journey extends MetadataType {
518
537
  }
519
538
  }
520
539
  }
521
- // ~~~ ACTIVITIES ~~~~
522
-
523
- this._postRetrieveTasks_activities(metadata);
524
540
 
525
541
  break;
526
542
  }
@@ -618,9 +634,120 @@ class Journey extends MetadataType {
618
634
  const triggeredSend = configurationArguments?.triggeredSend;
619
635
  if (triggeredSend) {
620
636
  // this section is likely only relevant for QuickSends and not for Multi-Step Journeys
621
-
622
637
  // triggeredSend key
623
- if (configurationArguments.r__triggeredSend_key) {
638
+ if (configurationArguments.r__transactionalEmail_key) {
639
+ const linkedTE = cache.getByKey(
640
+ 'transactionalEmail',
641
+ configurationArguments.r__transactionalEmail_key
642
+ );
643
+ if (linkedTE) {
644
+ if (linkedTE.subscriptions) {
645
+ triggeredSend.autoAddSubscribers =
646
+ linkedTE.subscriptions.autoAddSubscriber;
647
+ triggeredSend.autoUpdateSubscribers =
648
+ linkedTE.subscriptions.updateSubscriber;
649
+
650
+ // List
651
+ if (linkedTE.subscriptions?.list) {
652
+ triggeredSend.publicationListId = cache.searchForField(
653
+ 'list',
654
+ linkedTE.subscriptions.list,
655
+ 'CustomerKey',
656
+ 'ID'
657
+ );
658
+ } else if (linkedTE.subscriptions.r__list_PathName) {
659
+ delete triggeredSend.publicationListId;
660
+ triggeredSend.r__list_PathName = {
661
+ publicationList:
662
+ linkedTE.subscriptions.r__list_PathName,
663
+ };
664
+ }
665
+
666
+ // dataExtension
667
+ if (linkedTE.subscriptions.dataExtension) {
668
+ try {
669
+ activity.metaData.highThroughput.r__dataExtension_key =
670
+ cache.searchForField(
671
+ 'dataExtension',
672
+ linkedTE.subscriptions.dataExtension,
673
+ 'CustomerKey',
674
+ 'CustomerKey'
675
+ );
676
+ delete activity.metaData.highThroughput.dataExtensionId;
677
+ } catch (ex) {
678
+ Util.logger.warn(
679
+ ` - ${this.definition.type} ${
680
+ metadata[this.definition.nameField]
681
+ } (${metadata[this.definition.keyField]}): ${ex.message}.`
682
+ );
683
+ }
684
+ } else if (linkedTE.subscriptions.r__dataExtension_key) {
685
+ activity.metaData.highThroughput.r__dataExtension_key =
686
+ linkedTE.subscriptions.r__dataExtension_key;
687
+ delete activity.metaData.highThroughput.dataExtensionId;
688
+ }
689
+ }
690
+ if (linkedTE.options) {
691
+ triggeredSend.isTrackingClicks = linkedTE.options.trackLinks;
692
+ }
693
+
694
+ // send classification
695
+ if (linkedTE.classification) {
696
+ try {
697
+ const scKey = cache.searchForField(
698
+ 'sendClassification',
699
+ linkedTE.classification,
700
+ 'CustomerKey',
701
+ 'CustomerKey'
702
+ );
703
+ triggeredSend.r__sendClassification_key = scKey;
704
+ delete triggeredSend.sendClassificationId;
705
+ } catch (ex) {
706
+ Util.logger.warn(
707
+ ` - transactionalEmail ${linkedTE.definitionKey}: ${ex.message} (sendClassification key ${linkedTE.classification})`
708
+ );
709
+ }
710
+ } else if (linkedTE.r__sendClassification_key) {
711
+ triggeredSend.r__sendClassification_key =
712
+ linkedTE.r__sendClassification_key;
713
+ }
714
+
715
+ // senderProfile + deliveryProfile from sendClassification
716
+ if (triggeredSend.r__sendClassification_key) {
717
+ const sc = cache.getByKey(
718
+ 'sendClassification',
719
+ triggeredSend.r__sendClassification_key
720
+ );
721
+
722
+ if (sc.SenderProfile?.ObjectID) {
723
+ triggeredSend.r__senderProfile_key = cache.searchForField(
724
+ 'senderProfile',
725
+ sc.SenderProfile.ObjectID,
726
+ 'ObjectID',
727
+ 'CustomerKey'
728
+ );
729
+ delete triggeredSend.senderProfileId;
730
+ } else if (sc.r__senderProfile_key) {
731
+ triggeredSend.r__senderProfile_key =
732
+ sc.r__senderProfile_key;
733
+ delete triggeredSend.senderProfileId;
734
+ }
735
+ if (sc.DeliveryProfile?.ObjectID) {
736
+ triggeredSend.r__deliveryProfile_key = cache.searchForField(
737
+ 'deliveryProfile',
738
+ sc.DeliveryProfile.ObjectID,
739
+ 'ObjectID',
740
+ 'key'
741
+ );
742
+ delete triggeredSend.deliveryProfileId;
743
+ } else if (sc.r__deliveryProfile_key) {
744
+ triggeredSend.r__deliveryProfile_key =
745
+ sc.r__deliveryProfile_key;
746
+ delete triggeredSend.deliveryProfileId;
747
+ }
748
+ }
749
+ }
750
+ } else if (configurationArguments.r__triggeredSend_key) {
624
751
  // if we have a key set outside of this detailed triggeredSend config then lets overwrite what we've got here with what we cached from the related TS as it will be more current; but we cannot retrieve all info unfortunately
625
752
  triggeredSend.r__triggeredSend_key =
626
753
  configurationArguments.r__triggeredSend_key;
@@ -628,7 +755,7 @@ class Journey extends MetadataType {
628
755
  delete triggeredSend.key;
629
756
  const linkedTS = cache.getByKey(
630
757
  'triggeredSend',
631
- triggeredSend.r__triggeredSend_key
758
+ configurationArguments.r__triggeredSend_key
632
759
  );
633
760
  if (linkedTS) {
634
761
  triggeredSend.emailId = linkedTS.Email?.ID;
@@ -647,6 +774,7 @@ class Journey extends MetadataType {
647
774
  // triggeredSend.fromName = linkedTS.FromName;
648
775
  // triggeredSend.fromAddress = linkedTS.FromAddress;
649
776
 
777
+ // List
650
778
  if (linkedTS.List?.ID) {
651
779
  triggeredSend.publicationListId = linkedTS.List.ID;
652
780
  } else if (linkedTS.r__list_PathName) {
@@ -854,8 +982,21 @@ class Journey extends MetadataType {
854
982
  }
855
983
  // delivery profile
856
984
  if (triggeredSend.deliveryProfileId) {
857
- // remove it because we cannot resolve it and it should be set by selecting the sendClassification
858
- delete triggeredSend.deliveryProfileId;
985
+ try {
986
+ triggeredSend.r__deliveryProfile_key = cache.searchForField(
987
+ 'deliveryProfile',
988
+ triggeredSend.deliveryProfileId,
989
+ 'ObjectID',
990
+ 'key'
991
+ );
992
+ delete triggeredSend.deliveryProfileId;
993
+ } catch {
994
+ Util.logger.warn(
995
+ ` - ${this.definition.type} '${metadata[this.definition.nameField]}' (${
996
+ metadata[this.definition.keyField]
997
+ }): Dependent deliveryProfile was not found. Please note that this can only be resolved if you have at least ONE Send Classification set up on the target BU that uses this Delivery Profile.`
998
+ );
999
+ }
859
1000
  }
860
1001
  // message priority
861
1002
  if (triggeredSend.priority) {
@@ -1150,6 +1291,8 @@ class Journey extends MetadataType {
1150
1291
  delete activity.metaData.highThroughput.r__dataExtension_key;
1151
1292
  }
1152
1293
 
1294
+ this._preDeployTasks_activities(metadata);
1295
+
1153
1296
  break;
1154
1297
  }
1155
1298
  default: {
@@ -1306,6 +1449,25 @@ class Journey extends MetadataType {
1306
1449
  );
1307
1450
  delete triggeredSend.r__sendClassification_key;
1308
1451
  }
1452
+ // delivery profile
1453
+ if (triggeredSend.r__deliveryProfile_key) {
1454
+ // remove it because we cannot resolve it and it should be set by selecting the sendClassification
1455
+ try {
1456
+ triggeredSend.deliveryProfileId = cache.searchForField(
1457
+ 'deliveryProfile',
1458
+ triggeredSend.r__deliveryProfile_key,
1459
+ 'key',
1460
+ 'ObjectID'
1461
+ );
1462
+ delete triggeredSend.r__deliveryProfile_key;
1463
+ } catch (ex) {
1464
+ Util.logger.error(
1465
+ `Could not find the ID for Delivery Profile '${triggeredSend.r__deliveryProfile_key}'. Please note that this can only be resolved if you have at least ONE Send Classification set up on the target BU that uses a Delivery Profile with this key.`
1466
+ );
1467
+ throw ex;
1468
+ }
1469
+ }
1470
+
1309
1471
  // message priority
1310
1472
  if (triggeredSend.c__priority) {
1311
1473
  triggeredSend.priority =
@@ -1824,41 +1986,54 @@ class Journey extends MetadataType {
1824
1986
  }).start();
1825
1987
  const transactionalKeyArr = (await Promise.all(resultsTransactional)).filter(Boolean);
1826
1988
  spinner.success('done.');
1827
- executedKeyArr.push(...transactionalKeyArr);
1828
1989
 
1829
- Util.logger.info('Retrieving relevant journeys');
1830
- const retriever = new Retriever(this.properties, this.buObject);
1990
+ // if all publish actions failed, we don't need to re-retrieve anything here
1991
+ if (transactionalKeyArr.length) {
1992
+ executedKeyArr.push(...transactionalKeyArr);
1831
1993
 
1832
- try {
1833
- const updatedJourneyRetrieve = await retriever.retrieve(
1834
- ['journey'],
1835
- transactionalKeyArr
1836
- );
1994
+ Util.logger.info('Retrieving relevant journeys');
1995
+ const retriever = new Retriever(this.properties, this.buObject);
1837
1996
 
1838
- /** @type {MetadataTypeItem[]} */
1839
- const updatedJourneys = Object.values(updatedJourneyRetrieve?.journey[0]);
1840
- if (updatedJourneys) {
1841
- const updatedTransactionalEmails = [];
1842
- for (const journey of updatedJourneys) {
1843
- updatedTransactionalEmails.push(
1844
- journey.activities?.[0]?.configurationArguments
1845
- ?.r__transactionalEmail_key
1846
- );
1847
- }
1848
- if (updatedTransactionalEmails.filter(Boolean).length) {
1849
- Util.logger.info('Retrieving relevant transactionalEmails');
1850
- await retriever.retrieve(
1851
- ['transactionalEmail'],
1852
- updatedTransactionalEmails.filter(Boolean)
1853
- );
1854
- } else {
1855
- Util.logger.error(
1856
- `Could not find transactional Emails for the published journeys`
1857
- );
1997
+ try {
1998
+ const updatedJourneyRetrieve = await retriever.retrieve(
1999
+ ['journey'],
2000
+ transactionalKeyArr
2001
+ );
2002
+
2003
+ /** @type {MetadataTypeItem[]} */
2004
+ const updatedJourneys =
2005
+ updatedJourneyRetrieve?.journey?.length > 1
2006
+ ? Object.values(
2007
+ updatedJourneyRetrieve?.journey.reduce(
2008
+ (previousValue, currentValue) =>
2009
+ Object.assign(previousValue, currentValue),
2010
+ {}
2011
+ )
2012
+ )
2013
+ : Object.values(updatedJourneyRetrieve?.journey[0]);
2014
+ if (updatedJourneys) {
2015
+ const updatedTransactionalEmails = [];
2016
+ for (const journey of updatedJourneys) {
2017
+ updatedTransactionalEmails.push(
2018
+ journey.activities?.[0]?.configurationArguments
2019
+ ?.r__transactionalEmail_key
2020
+ );
2021
+ }
2022
+ if (updatedTransactionalEmails.filter(Boolean).length) {
2023
+ Util.logger.info('Retrieving relevant transactionalEmails');
2024
+ await retriever.retrieve(
2025
+ ['transactionalEmail'],
2026
+ updatedTransactionalEmails.filter(Boolean)
2027
+ );
2028
+ } else {
2029
+ Util.logger.error(
2030
+ `Could not find transactional Emails for the published journeys`
2031
+ );
2032
+ }
1858
2033
  }
2034
+ } catch (ex) {
2035
+ Util.logger.errorStack(ex, 'retrieve failed');
1859
2036
  }
1860
- } catch (ex) {
1861
- Util.logger.errorStack(ex, 'retrieve failed');
1862
2037
  }
1863
2038
  }
1864
2039
  Util.logger.info(
@@ -730,16 +730,11 @@ class MetadataType {
730
730
  // preDeployTasks parsing
731
731
  let deployableMetadata;
732
732
  try {
733
+ await this.validation('deploy', metadataMap[metadataKey], deployDir);
733
734
  deployableMetadata = await this.preDeployTasks(
734
735
  metadataMap[metadataKey],
735
736
  deployDir
736
737
  );
737
-
738
- deployableMetadata = await this.validation(
739
- 'deploy',
740
- deployableMetadata,
741
- deployDir
742
- );
743
738
  } catch (ex) {
744
739
  // do this in case something went wrong during pre-deploy steps to ensure the total counter is correct
745
740
  hasError = true;
@@ -1969,11 +1964,7 @@ class MetadataType {
1969
1964
  filterCounter++;
1970
1965
  continue;
1971
1966
  }
1972
- results[originalKey] = await this.validation(
1973
- 'retrieve',
1974
- results[originalKey],
1975
- retrieveDir
1976
- );
1967
+ await this.validation('retrieve', results[originalKey], retrieveDir);
1977
1968
 
1978
1969
  savedResults[originalKey] = await this.saveToDisk(
1979
1970
  results,
@@ -2800,11 +2791,13 @@ class MetadataType {
2800
2791
  * @returns {Promise.<MetadataTypeItem | CodeExtractItem>} Promise of a single metadata item
2801
2792
  */
2802
2793
  static async validation(method, item, targetDir) {
2794
+ item = structuredClone(item);
2803
2795
  if (!this.properties.options?.validation?.[method]) {
2804
2796
  return item;
2805
2797
  }
2806
2798
  /** @type {MetadataTypeItem} */
2807
2799
  const metadataItem = item.json && item.codeArr ? item.json : item;
2800
+ const codeArr = item.codeArr || null;
2808
2801
  /** @type {ValidationRules} */
2809
2802
  const validationConfig = structuredClone(this.properties.options?.validation?.[method]);
2810
2803
 
@@ -2827,9 +2820,15 @@ class MetadataType {
2827
2820
 
2828
2821
  // get default and custom validation rules
2829
2822
  const definition = this.definition;
2830
- const validationRules = await validationsRules(this.definition, metadataItem, targetDir);
2823
+ const validationRules = await validationsRules(
2824
+ this.definition,
2825
+ metadataItem,
2826
+ targetDir,
2827
+ codeArr
2828
+ );
2831
2829
 
2832
2830
  // run validation rules
2831
+ const warnings = [];
2833
2832
  for (const rule of Object.keys(validationRules)) {
2834
2833
  if (
2835
2834
  validationConfig[rule] &&
@@ -2840,14 +2839,17 @@ class MetadataType {
2840
2839
  if (!Util.OPTIONS.skipValidation && validationConfig[rule] === 'error') {
2841
2840
  throw new Error(validationRules[rule].failedMsg);
2842
2841
  } else if (Util.OPTIONS.skipValidation || validationConfig[rule] === 'warn') {
2843
- Util.logger.warn(
2844
- ` - ${this.definition.type} ${metadataItem[this.definition.nameField]} (${
2845
- metadataItem[this.definition.keyField]
2846
- }): ${validationRules[rule].failedMsg}`
2847
- );
2842
+ warnings.push(validationRules[rule].failedMsg);
2848
2843
  }
2849
2844
  }
2850
2845
  }
2846
+ if (warnings.length) {
2847
+ Util.logger.warn(
2848
+ ` - ${this.definition.type} ${metadataItem[this.definition.nameField]} (${
2849
+ metadataItem[this.definition.keyField]
2850
+ }):${warnings.length > 1 ? '\n ·' : ''} ${warnings.join('\n · ')}`
2851
+ );
2852
+ }
2851
2853
  return item;
2852
2854
  }
2853
2855
  }
@@ -47,6 +47,22 @@ class SendClassification extends MetadataType {
47
47
  return super.retrieveSOAP(retrieveDir, requestParams, key);
48
48
  }
49
49
 
50
+ /**
51
+ * Retrieves event definition metadata for caching
52
+ *
53
+ * @returns {Promise.<MetadataTypeMapObj>} Promise of metadata
54
+ */
55
+ static async retrieveForCache() {
56
+ const typeMap = await this.retrieve(null);
57
+ if (cache.getCache().deliveryProfile) {
58
+ for (const item of Object.values(typeMap.metadata)) {
59
+ // run postRetrieveTasks to cross-update deliveryProfile cache
60
+ this.updateDeliveryProfileIdInCache(item);
61
+ }
62
+ }
63
+ return typeMap;
64
+ }
65
+
50
66
  /**
51
67
  * Updates a single item
52
68
  *
@@ -100,13 +116,15 @@ class SendClassification extends MetadataType {
100
116
  };
101
117
  delete metadata.r__senderProfile_key;
102
118
 
119
+ const dpId = cache.searchForField(
120
+ 'deliveryProfile',
121
+ metadata.r__deliveryProfile_key,
122
+ 'key',
123
+ 'ObjectID'
124
+ );
103
125
  metadata.DeliveryProfile = {
104
- CustomerKey: cache.searchForField(
105
- 'deliveryProfile',
106
- metadata.r__deliveryProfile_key,
107
- 'key',
108
- 'key'
109
- ),
126
+ ObjectID: dpId,
127
+ CustomerKey: metadata.r__deliveryProfile_key,
110
128
  };
111
129
  delete metadata.r__deliveryProfile_key;
112
130
 
@@ -126,6 +144,7 @@ class SendClassification extends MetadataType {
126
144
  );
127
145
  delete metadata.SendClassificationType;
128
146
 
147
+ // when sendClassification was only cached it can happen that we don't have the senderProfile cache yet
129
148
  try {
130
149
  metadata.r__senderProfile_key = cache.searchForField(
131
150
  'senderProfile',
@@ -144,6 +163,9 @@ class SendClassification extends MetadataType {
144
163
  'key',
145
164
  'key'
146
165
  );
166
+ // add ObjectID to deliveryProfile cache because it cannot be retrieved any other way and this way we can resolve it in journeys
167
+ this.updateDeliveryProfileIdInCache(metadata);
168
+
147
169
  delete metadata.DeliveryProfile;
148
170
  } catch (ex) {
149
171
  Util.logger.warn(` - ${this.definition.type} ${metadata.CustomerKey}: ${ex.message}`);
@@ -151,6 +173,22 @@ class SendClassification extends MetadataType {
151
173
 
152
174
  return metadata;
153
175
  }
176
+
177
+ /**
178
+ * this is the only known way to get the object ID for a deliveryProfile
179
+ *
180
+ * @param {MetadataTypeItem} metadata a single sendClassification item
181
+ */
182
+ static updateDeliveryProfileIdInCache(metadata) {
183
+ const dp = cache.getByKey('deliveryProfile', metadata.DeliveryProfile.CustomerKey);
184
+ if (dp) {
185
+ dp.ObjectID = metadata.DeliveryProfile.ObjectID;
186
+ } else {
187
+ Util.logger.debug(
188
+ ` - ${this.definition.type} ${metadata.CustomerKey}: Could not find deliveryProfile ${metadata.DeliveryProfile.CustomerKey} in cache`
189
+ );
190
+ }
191
+ }
154
192
  }
155
193
 
156
194
  // Assign definition to static attributes