mcdev 7.1.4 → 7.2.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.
Files changed (28) hide show
  1. package/.fork/custom-commands.json +123 -21
  2. package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
  3. package/.github/dependabot.yml +1 -0
  4. package/.husky/post-checkout +6 -1
  5. package/.husky/post-merge +5 -0
  6. package/@types/lib/metadataTypes/Journey.d.ts +0 -1
  7. package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
  8. package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -1
  9. package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +0 -1
  10. package/@types/lib/util/file.d.ts.map +1 -1
  11. package/lib/metadataTypes/Journey.js +280 -141
  12. package/lib/metadataTypes/TransactionalEmail.js +20 -3
  13. package/lib/metadataTypes/definitions/Journey.definition.js +0 -1
  14. package/lib/util/file.js +53 -49
  15. package/package.json +12 -12
  16. package/test/general.test.js +13 -13
  17. package/test/mockRoot/.mcdevrc.json +1 -1
  18. package/test/resourceFactory.js +12 -3
  19. package/test/resources/9999999/dataExtension/retrieve-response.xml +29 -0
  20. package/test/resources/9999999/interaction/v1/interactions/get-response.json +38 -0
  21. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_temail_notPublished/get-response.json +226 -0
  22. package/test/resources/9999999/interaction/v1/interactions/transactional/create/post-response.json +3 -0
  23. package/test/resources/9999999/messaging/v1/email/definitions/get-response.json +7 -0
  24. package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail_notPublished/get-response.json +26 -0
  25. package/test/type.automation.test.js +1 -1
  26. package/test/type.dataExtension.test.js +4 -4
  27. package/test/type.journey.test.js +84 -21
  28. package/test/type.transactionalEmail.test.js +7 -7
@@ -6,6 +6,7 @@ import { Util } from '../util/util.js';
6
6
  import cache from '../util/cache.js';
7
7
  import File from '../util/file.js';
8
8
  import ReplaceCbReference from '../util/replaceContentBlockReference.js';
9
+ import Retriever from '../Retriever.js';
9
10
 
10
11
  /**
11
12
  * @typedef {import('../../types/mcdev.d.js').BuObject} BuObject
@@ -427,50 +428,60 @@ class Journey extends MetadataType {
427
428
  // ! transactional (email) journeys only have one activity (type=EMAILV2) which links back to the transactionalEmail ()
428
429
  switch (metadata.channel) {
429
430
  case 'email': {
430
- if (
431
- metadata.activities?.length > 0 &&
432
- metadata.activities[0].configurationArguments?.triggeredSendKey
433
- ) {
431
+ if (metadata.activities?.length > 0) {
434
432
  const activity = metadata.activities[0];
435
433
  // trigger found; there can only be one entry in this array
436
- try {
437
- const tEmailKey = cache.searchForField(
438
- 'transactionalEmail',
439
- activity.configurationArguments?.triggeredSendId,
440
- 'definitionId',
441
- 'definitionKey'
442
- );
443
- if (
444
- tEmailKey != activity.configurationArguments?.triggeredSendKey
445
- ) {
446
- throw new Error(
447
- ` - ${this.definition.type} ${
448
- metadata[this.definition.nameField]
449
- } (${
450
- metadata[this.definition.keyField]
451
- }): transactionalEmailId not matching Id found on transactionalEmail with key in transactionalEmailKey`
434
+
435
+ if (activity.configurationArguments?.triggeredSendId) {
436
+ try {
437
+ const tEmailKey = cache.searchForField(
438
+ 'transactionalEmail',
439
+ activity.configurationArguments?.triggeredSendId,
440
+ 'definitionId',
441
+ 'definitionKey'
452
442
  );
453
- }
454
- if (
455
- activity.metaData?.highThroughput?.definitionKey &&
456
- activity.metaData?.highThroughput?.definitionKey !=
457
- activity.configurationArguments?.triggeredSendKey
458
- ) {
459
- throw new Error(
443
+ if (
444
+ activity.configurationArguments?.triggeredSendKey &&
445
+ tEmailKey !=
446
+ activity.configurationArguments?.triggeredSendKey
447
+ ) {
448
+ Util.logger.debug(
449
+ `triggeredSendKey not matching triggeredSendId. Overwriting '${activity.configurationArguments.triggeredSendKey}' with the correct key '${tEmailKey}'.`
450
+ );
451
+ }
452
+ activity.configurationArguments.r__transactionalEmail_key =
453
+ activity.configurationArguments.triggeredSendKey;
454
+ delete activity.configurationArguments.triggeredSendKey;
455
+ delete activity.configurationArguments.triggeredSendId;
456
+ } catch (ex) {
457
+ Util.logger.warn(
460
458
  ` - ${this.definition.type} ${
461
459
  metadata[this.definition.nameField]
462
- } (${
463
- metadata[this.definition.keyField]
464
- }): metaData.highThroughput.definitionKey not matching key in configurationArguments.transactionalEmailKey`
460
+ } (${metadata[this.definition.keyField]}): ${ex.message}.`
465
461
  );
466
462
  }
467
- activity.configurationArguments.r__transactionalEmail_key =
468
- activity.configurationArguments.triggeredSendKey;
469
- delete activity.configurationArguments.triggeredSendKey;
470
- delete activity.configurationArguments.triggeredSendId;
463
+ }
464
+ if (
465
+ activity.metaData?.highThroughput?.definitionKey &&
466
+ activity.configurationArguments?.r__transactionalEmail_key &&
467
+ activity.metaData?.highThroughput?.definitionKey !=
468
+ activity.configurationArguments.r__transactionalEmail_key
469
+ ) {
470
+ Util.logger.warn(
471
+ ` - ${this.definition.type} ${
472
+ metadata[this.definition.nameField]
473
+ } (${metadata[this.definition.keyField]}): activities[0].metaData.highThroughput.definitionKey not matching key in activities[0].configurationArguments.r__transactionalEmail_key.`
474
+ );
475
+ } else if (
476
+ activity.configurationArguments?.r__transactionalEmail_key &&
477
+ metadata.status === 'Published'
478
+ ) {
479
+ // as long as status is Draft, we wont have r__transactionalEmail_key set as that record will not have been created
471
480
  delete activity.metaData.highThroughput.definitionKey;
481
+ }
472
482
 
473
- if (activity.metaData?.highThroughput?.dataExtensionId) {
483
+ if (activity.metaData?.highThroughput?.dataExtensionId) {
484
+ try {
474
485
  activity.metaData.highThroughput.r__dataExtension_key =
475
486
  cache.searchForField(
476
487
  'dataExtension',
@@ -479,13 +490,13 @@ class Journey extends MetadataType {
479
490
  'CustomerKey'
480
491
  );
481
492
  delete activity.metaData.highThroughput.dataExtensionId;
493
+ } catch (ex) {
494
+ Util.logger.warn(
495
+ ` - ${this.definition.type} ${
496
+ metadata[this.definition.nameField]
497
+ } (${metadata[this.definition.keyField]}): ${ex.message}.`
498
+ );
482
499
  }
483
- } catch (ex) {
484
- Util.logger.warn(
485
- ` - ${this.definition.type} ${
486
- metadata[this.definition.nameField]
487
- } (${metadata[this.definition.keyField]}): ${ex.message}.`
488
- );
489
500
  }
490
501
  }
491
502
  // ~~~ ACTIVITIES ~~~~
@@ -1032,15 +1043,32 @@ class Journey extends MetadataType {
1032
1043
  const activity = metadata.activities[0];
1033
1044
  if (activity.configurationArguments?.r__transactionalEmail_key) {
1034
1045
  // trigger found; there can only be one entry in this array
1035
- activity.configurationArguments.triggeredSendId = cache.searchForField(
1036
- 'transactionalEmail',
1037
- activity.configurationArguments.r__transactionalEmail_key,
1038
- 'definitionKey',
1039
- 'definitionId'
1040
- );
1041
- activity.configurationArguments.triggeredSendKey =
1042
- activity.configurationArguments.r__transactionalEmail_key;
1046
+ try {
1047
+ activity.configurationArguments.triggeredSendId =
1048
+ cache.searchForField(
1049
+ 'transactionalEmail',
1050
+ activity.configurationArguments.r__transactionalEmail_key,
1051
+ 'definitionKey',
1052
+ 'definitionId'
1053
+ );
1054
+ activity.configurationArguments.triggeredSendKey =
1055
+ activity.configurationArguments.r__transactionalEmail_key;
1056
+ } catch (ex) {
1057
+ const isCreateMode = !cache.getByKey('journey', metadata.key);
1058
+ if (isCreateMode && !Util.OPTIONS.publish) {
1059
+ // no need to add a log entry if the publish-option was provided
1060
+ Util.logger.info(
1061
+ ` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
1062
+ metadata[this.definition.keyField]
1063
+ }): To activate this transactional journey (and create the associated transactionalEmail record), please run 'mcdev publish ${this.buObject.credential}/${this.buObject.businessUnit} journey ${metadata.key}' or click on "Activate" in the GUI.`
1064
+ );
1065
+ } else if (!isCreateMode) {
1066
+ // block deployment if we are in update mode
1067
+ throw ex;
1068
+ }
1069
+ }
1043
1070
  if (activity.metaData?.highThroughput) {
1071
+ // this is crucial for pinging the /interaction/v1/interactions/transactional/create endpoint that creates the transactionalEmail
1044
1072
  activity.metaData.highThroughput.definitionKey =
1045
1073
  activity.configurationArguments.r__transactionalEmail_key;
1046
1074
  }
@@ -1508,113 +1536,224 @@ class Journey extends MetadataType {
1508
1536
  * @returns {Promise.<string[]>} Returns list of updated keys/ids that were published. Success could only be seen with a delay in the UI because the publish-endpoint is async
1509
1537
  */
1510
1538
  static async publish(keyArr) {
1511
- const results = [];
1539
+ const resultsJourney = [];
1540
+ const resultsTransactional = [];
1512
1541
  // works only with objectId
1513
- let objectId;
1514
- let idFound = false;
1515
- let versionFound = false;
1516
1542
  const statusUrls = [];
1543
+ const executedKeyArr = [];
1544
+ const metadataMap = await this.retrieveForCache();
1545
+
1517
1546
  for (let key of keyArr) {
1547
+ let objectId;
1518
1548
  let version;
1519
- if (key) {
1520
- if (key.startsWith('%23')) {
1521
- // if the key started with %23 assume an ID was copied from the URL but the user forgot to prefix it with id:
1522
- // correct the format
1523
- key = 'id:' + key.slice(3);
1549
+ let journey;
1550
+ if (!key) {
1551
+ continue;
1552
+ }
1553
+ if (key.startsWith('%23')) {
1554
+ // if the key started with %23 assume an ID was copied from the URL but the user forgot to prefix it with id:
1555
+ // correct the format
1556
+ key = 'id:' + key.slice(3);
1557
+ }
1558
+ if (key.startsWith('id:')) {
1559
+ // ! allow selecting journeys by ID because that's what users see in the URL
1560
+ // remove id
1561
+ objectId = key.slice(3);
1562
+ if (objectId.startsWith('%23')) {
1563
+ // in the journey URL the Id is prefixed with an HTML-encoded "#" which could accidentally be copied by users
1564
+ // despite the slicing above, this still needs testing here because users might have prefixed the ID with id: but did not know to remove the #23
1565
+ objectId = objectId.slice(3);
1566
+ // correct the format to ensure we show sth readable in the "Downloaded" log
1567
+ // objectId = objectId;
1568
+ // update this here to show it in the log
1569
+ key = 'id:' + objectId;
1524
1570
  }
1525
- if (key.startsWith('id:')) {
1526
- idFound = true;
1527
- // ! allow selecting journeys by ID because that's what users see in the URL
1528
- // remove id
1529
- objectId = key.slice(3);
1530
- if (objectId.startsWith('%23')) {
1531
- // in the journey URL the Id is prefixed with an HTML-encoded "#" which could accidentally be copied by users
1532
- // despite the slicing above, this still needs testing here because users might have prefixed the ID with id: but did not know to remove the #23
1533
- objectId = objectId.slice(3);
1534
- // correct the format to ensure we show sth readable in the "Downloaded" log
1535
- objectId = 'id:' + objectId;
1536
- // update this here to show it in the log
1537
- key = objectId;
1538
- }
1539
- if (objectId.includes('/')) {
1540
- versionFound = true;
1541
- version = objectId.split('/')[1];
1542
- // in the journey URL the version is appended after the ID, separated by a forward-slash. Needs to be removed from the ID for caching as we always aim to retrieve the latest version only
1543
- objectId = objectId.split('/')[0];
1544
- } else {
1545
- // if we didn't find a version we need to cache this from the API after all
1546
- objectId = null;
1547
- if (key.includes('/')) {
1548
- // in the journey URL the version is appended after the ID, separated by a forward-slash. Needs to be removed from the key for caching as we always aim to retrieve the latest version only
1549
- key = key.split('/')[0];
1550
- }
1571
+ if (objectId.includes('/')) {
1572
+ version = objectId.split('/')[1];
1573
+ // in the journey URL the version is appended after the ID, separated by a forward-slash. Needs to be removed from the ID for caching as we always aim to retrieve the latest version only
1574
+ objectId = objectId.split('/')[0];
1575
+ } else {
1576
+ // if we didn't find a version we need to cache this from the API after all
1577
+ if (key.includes('/')) {
1578
+ // in the journey URL the version is appended after the ID, separated by a forward-slash. Needs to be removed from the key for caching as we always aim to retrieve the latest version only
1579
+ key = key.split('/')[0];
1551
1580
  }
1552
1581
  }
1553
- if (!objectId) {
1582
+ journey = Object.values(metadataMap.metadata).find((el) => el.id === objectId);
1583
+ if (!journey) {
1554
1584
  Util.logger.info(
1555
- ` - getting${!idFound && !versionFound ? ' ID and' : ''} latest version from server`
1585
+ ` skipping ${this.definition.type} ${key}: not found on server (1)`
1556
1586
  );
1557
- const metadataMap = await this.retrieveForCache(undefined, undefined, key);
1558
- const journey = Object.values(metadataMap.metadata);
1559
- if (!journey.length) {
1560
- Util.logger.info(`Skipping ${key} - did not find an item with such key`);
1561
- continue;
1562
- }
1563
- objectId = journey[0].id;
1564
- version = journey[0].version;
1565
- if (!objectId || !version) {
1566
- Util.logger.info(`Skipping ${key} - did not find an item with such key`);
1567
- continue;
1568
- }
1587
+ continue;
1569
1588
  }
1589
+ } else {
1590
+ // key assumed
1591
+ journey = metadataMap.metadata[key];
1570
1592
  }
1571
1593
 
1572
- results.push(
1573
- (async () => {
1574
- try {
1575
- const response = await this.client.rest.post(
1576
- `/interaction/v1/interactions/publishAsync/${objectId}?versionNumber=${version}`,
1577
- {}
1578
- ); // payload is empty for this request
1579
- if (response.statusUrl && response.statusId) {
1580
- Util.logger.info(
1581
- ` - queued for publishing ${this.definition.type}: ${key}`
1582
- );
1583
- statusUrls.push({ key, statusUrl: response.statusUrl });
1584
- } else {
1585
- throw new Error(response);
1586
- }
1587
- return key;
1588
- } catch (ex) {
1589
- if (ex.message === 'Cannot publish interaction in Published status.') {
1590
- Util.logger.info(
1591
- ` - ${this.definition.type} ${key} is already published`
1592
- );
1593
- } else if (ex.message === 'Cannot publish interaction in Stopped status.') {
1594
- Util.logger.warn(
1595
- ` - ${this.definition.type} ${key} is already published but stopped. Please resume it manually.`
1596
- );
1597
- } else {
1598
- Util.logger.error(
1599
- `Failed to publish ${this.definition.type} ${key}: ${ex.message}`
1600
- );
1601
- }
1602
- }
1603
- })()
1604
- );
1594
+ if (!journey) {
1595
+ Util.logger.info(
1596
+ ` ☇ skipping ${this.definition.type} ${key}: not found on server (2)`
1597
+ );
1598
+ continue;
1599
+ }
1600
+ if (!version) {
1601
+ version = journey.version;
1602
+ }
1603
+ if (journey.status === 'Published') {
1604
+ // api would return error code 30000 and ask to open a support case when in fact we simply already have a transactionalEmail created based on this status
1605
+ Util.logger.error(
1606
+ ` skipping ${this.definition.type} ${
1607
+ journey[this.definition.nameField]
1608
+ } (${journey[this.definition.keyField]}): already published`
1609
+ );
1610
+ continue;
1611
+ }
1612
+
1613
+ switch (journey.definitionType) {
1614
+ case 'Transactional': {
1615
+ resultsTransactional.push(
1616
+ (async () => {
1617
+ try {
1618
+ const response = await this.client.rest.post(
1619
+ `/interaction/v1/interactions/transactional/create`,
1620
+ { definitionId: journey.id }
1621
+ );
1622
+ if (response.errors?.length) {
1623
+ throw new Error(JSON.stringify(response));
1624
+ } else {
1625
+ Util.logger.info(
1626
+ ` - published ${this.definition.type}: ${
1627
+ journey[this.definition.nameField]
1628
+ } (${journey[this.definition.keyField]} by creating the matching transactionalEmail`
1629
+ );
1630
+ statusUrls.push({ key, statusUrl: response.statusUrl });
1631
+ }
1632
+ return key;
1633
+ } catch (ex) {
1634
+ if (
1635
+ ex.response.status === 400 &&
1636
+ ex.response?.data?.errors?.length === 1 &&
1637
+ ex.response?.data?.errors?.[0]?.errorCode === '121500'
1638
+ ) {
1639
+ Util.logger.error(
1640
+ `Failed to publish ${
1641
+ journey[this.definition.nameField]
1642
+ } (${journey[this.definition.keyField]}): Make sure the Event Definition Key, Data Extension and E-Mail are saved to the journey`
1643
+ );
1644
+ } else {
1645
+ Util.logger.error(
1646
+ `Failed to publish ${
1647
+ journey[this.definition.nameField]
1648
+ } (${journey[this.definition.keyField]}): ${ex.message}`
1649
+ );
1650
+ if (ex.response?.data?.errors?.length) {
1651
+ Util.logger.error(
1652
+ JSON.stringify(ex.response?.data?.errors, null, 2)
1653
+ );
1654
+ }
1655
+ }
1656
+ }
1657
+ })()
1658
+ );
1659
+ break;
1660
+ }
1661
+ case 'Multistep':
1662
+ case 'Quicksend': {
1663
+ resultsJourney.push(
1664
+ (async () => {
1665
+ try {
1666
+ const response = await this.client.rest.post(
1667
+ `/interaction/v1/interactions/publishAsync/${journey.id}?versionNumber=${version}`,
1668
+ {}
1669
+ ); // payload is empty for this request
1670
+ if (response.statusUrl && response.statusId) {
1671
+ Util.logger.info(
1672
+ ` - queued for publishing ${this.definition.type}: ${key}`
1673
+ );
1674
+ statusUrls.push({ key, statusUrl: response.statusUrl });
1675
+ } else {
1676
+ throw new Error(response);
1677
+ }
1678
+ return journey.key;
1679
+ } catch (ex) {
1680
+ if (
1681
+ ex.message === 'Cannot publish interaction in Published status.'
1682
+ ) {
1683
+ Util.logger.info(
1684
+ ` - ${this.definition.type} ${key} is already published`
1685
+ );
1686
+ } else if (
1687
+ ex.message === 'Cannot publish interaction in Stopped status.'
1688
+ ) {
1689
+ Util.logger.warn(
1690
+ ` - ${this.definition.type} ${key} is already published but stopped. Please resume it manually.`
1691
+ );
1692
+ } else {
1693
+ Util.logger.error(
1694
+ `Failed to publish ${this.definition.type} ${key}: ${ex.message}`
1695
+ );
1696
+ }
1697
+ }
1698
+ })()
1699
+ );
1700
+ }
1701
+ }
1702
+ } // for loop
1703
+ if (resultsJourney.length) {
1704
+ Util.logger.info(`Found ${resultsJourney.length} journey results`);
1705
+ executedKeyArr.push(...(await Promise.all(resultsJourney)).filter(Boolean));
1706
+
1707
+ if (!Util.OPTIONS.skipStatusCheck && statusUrls.length) {
1708
+ Util.logger.info(
1709
+ `Checking status of ${statusUrls.length} published item${statusUrls.length === 1 ? '' : 's'}`
1710
+ );
1711
+ executedKeyArr.length = 0;
1712
+ await Util.sleep(5000);
1713
+ for (const item of statusUrls) {
1714
+ executedKeyArr.push(await this._checkPublishStatus(item.statusUrl, item.key));
1715
+ }
1716
+ }
1605
1717
  }
1606
- const executedKeyArr = (await Promise.all(results)).filter(Boolean);
1718
+ if (resultsTransactional.length) {
1719
+ Util.logger.info(`Found ${resultsTransactional.length} journey results`);
1720
+ const transactionalKeyArr = (await Promise.all(resultsTransactional)).filter(Boolean);
1721
+ executedKeyArr.push(...transactionalKeyArr);
1722
+
1723
+ Util.logger.info('Retrieving relevant journeys');
1724
+ const retriever = new Retriever(this.properties, this.buObject);
1725
+
1726
+ try {
1727
+ const updatedJourneyRetrieve = await retriever.retrieve(
1728
+ ['journey'],
1729
+ transactionalKeyArr
1730
+ );
1607
1731
 
1608
- if (!Util.OPTIONS.skipStatusCheck && statusUrls.length) {
1609
- Util.logger.info(
1610
- `Checking status of ${statusUrls.length} published item${statusUrls.length === 1 ? '' : 's'}`
1611
- );
1612
- executedKeyArr.length = 0;
1613
- await Util.sleep(5000);
1614
- for (const item of statusUrls) {
1615
- executedKeyArr.push(await this._checkPublishStatus(item.statusUrl, item.key));
1732
+ /** @type {MetadataTypeItem[]} */
1733
+ const updatedJourneys = Object.values(updatedJourneyRetrieve?.journey[0]);
1734
+ if (updatedJourneys) {
1735
+ const updatedTransactionalEmails = [];
1736
+ for (const journey of updatedJourneys) {
1737
+ updatedTransactionalEmails.push(
1738
+ journey.activities?.[0]?.configurationArguments
1739
+ ?.r__transactionalEmail_key
1740
+ );
1741
+ }
1742
+ if (updatedTransactionalEmails.filter(Boolean).length) {
1743
+ Util.logger.info('Retrieving relevant transactionalEmails');
1744
+ await retriever.retrieve(
1745
+ ['transactionalEmail'],
1746
+ updatedTransactionalEmails.filter(Boolean)
1747
+ );
1748
+ } else {
1749
+ Util.logger.error(
1750
+ `Could not find transactional Emails for the published journeys`
1751
+ );
1752
+ }
1753
+ }
1754
+ } catch (ex) {
1755
+ Util.logger.errorStack(ex, 'retrieve failed');
1616
1756
  }
1617
- // return executedKeyArr;
1618
1757
  }
1619
1758
  Util.logger.info(
1620
1759
  `Published ${executedKeyArr.filter(Boolean).length} of ${keyArr.length} items`
@@ -47,6 +47,24 @@ class TransactionalEmail extends TransactionalMessage {
47
47
  return super.update(metadata);
48
48
  }
49
49
 
50
+ /**
51
+ * Updates a single item
52
+ *
53
+ * @param {MetadataTypeItem} metadata how the item shall look after the update
54
+ * @returns {Promise} Promise
55
+ */
56
+ static create(metadata) {
57
+ if (metadata.definitionType === 'Transactional' && metadata.channel === 'email') {
58
+ // only send this during create or else we might end up with an unexpected outcome
59
+ Util.logger.warn(
60
+ ` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
61
+ metadata[this.definition.keyField]
62
+ }): While possible, it is not recommended to create transactional journeys via transactionalEmail. Instead, create the journey and then publish it (mcdev deploy cred/bu journey --publish)`
63
+ );
64
+ }
65
+ return super.create(metadata);
66
+ }
67
+
50
68
  /**
51
69
  * prepares for deployment
52
70
  *
@@ -124,9 +142,8 @@ class TransactionalEmail extends TransactionalMessage {
124
142
  static async postDeployTasks() {
125
143
  if (this._createdJourneyKeys?.length) {
126
144
  Util.logger.warn(
127
- `Please download related journeys via: mcdev r ${this.buObject.credential}/${
128
- this.buObject.businessUnit
129
- } journey "${this._createdJourneyKeys.join(',')}"`
145
+ `Please download related journeys via: mcdev retrieve ${this.buObject.credential}/${this.buObject.businessUnit} -m
146
+ ${this._createdJourneyKeys.map((el) => `"journey:${el}"`).join(' ')}`
130
147
  );
131
148
  }
132
149
  delete this._createdJourneyKeys;
@@ -23,7 +23,6 @@ export default {
23
23
  dependencyGraph: {
24
24
  // classic email cannot be deployed anymore
25
25
  event: ['triggers.metaData.r__event_key'],
26
- transactionalEmail: ['activities.configurationArguments.r__transactionalEmail_key'],
27
26
  dataExtension: [
28
27
  'activities.metaData.highThroughput.r__dataExtension_key',
29
28
  'activities.configurationArguments.triggeredSend.r__dataExtension_key.domainExclusions',
package/lib/util/file.js CHANGED
@@ -260,57 +260,61 @@ const File = {
260
260
  // will throw an error falsely assuming bad syntax
261
261
  return await this.beautify_beautyAmp(content, true);
262
262
  }
263
- // load the right prettier config relative to our file
264
- switch (filetype) {
265
- case 'htm':
266
- case 'html': {
267
- FileFs.prettierConfig.parser = 'html';
268
- break;
269
- }
270
- case 'ssjs':
271
- case 'js': {
272
- FileFs.prettierConfig.parser = 'babel';
273
- break;
274
- }
275
- case 'json': {
276
- FileFs.prettierConfig.parser = 'json';
277
- break;
278
- }
279
- case 'yaml':
280
- case 'yml': {
281
- FileFs.prettierConfig.parser = 'yaml';
282
- break;
283
- }
284
- case 'ts': {
285
- FileFs.prettierConfig.parser = 'babel-ts';
286
- break;
287
- }
288
- case 'css': {
289
- FileFs.prettierConfig.parser = 'css';
290
- break;
291
- }
292
- case 'less': {
293
- FileFs.prettierConfig.parser = 'less';
294
- break;
295
- }
296
- case 'sass':
297
- case 'scss': {
298
- FileFs.prettierConfig.parser = 'scss';
299
- break;
300
- }
301
- case 'md': {
302
- FileFs.prettierConfig.parser = 'markdown';
303
- break;
304
- }
305
- case 'sql': {
306
- FileFs.prettierConfig.parser = 'sql';
307
- FileFs.prettierConfig.plugins = ['prettier-plugin-sql'];
308
- break;
309
- }
310
- default: {
311
- FileFs.prettierConfig.parser = 'babel';
263
+
264
+ if (!FileFs.prettierConfig.parser) {
265
+ // load the right prettier config relative to our file
266
+ switch (filetype) {
267
+ case 'htm':
268
+ case 'html': {
269
+ FileFs.prettierConfig.parser = 'html';
270
+ break;
271
+ }
272
+ case 'ssjs':
273
+ case 'js': {
274
+ FileFs.prettierConfig.parser = 'babel';
275
+ break;
276
+ }
277
+ case 'json': {
278
+ FileFs.prettierConfig.parser = 'json';
279
+ break;
280
+ }
281
+ case 'yaml':
282
+ case 'yml': {
283
+ FileFs.prettierConfig.parser = 'yaml';
284
+ break;
285
+ }
286
+ case 'ts': {
287
+ FileFs.prettierConfig.parser = 'babel-ts';
288
+ break;
289
+ }
290
+ case 'css': {
291
+ FileFs.prettierConfig.parser = 'css';
292
+ break;
293
+ }
294
+ case 'less': {
295
+ FileFs.prettierConfig.parser = 'less';
296
+ break;
297
+ }
298
+ case 'sass':
299
+ case 'scss': {
300
+ FileFs.prettierConfig.parser = 'scss';
301
+ break;
302
+ }
303
+ case 'md': {
304
+ FileFs.prettierConfig.parser = 'markdown';
305
+ break;
306
+ }
307
+ case 'sql': {
308
+ FileFs.prettierConfig.parser = 'sql';
309
+ FileFs.prettierConfig.plugins = ['prettier-plugin-sql'];
310
+ break;
311
+ }
312
+ default: {
313
+ FileFs.prettierConfig.parser = 'babel';
314
+ }
312
315
  }
313
316
  }
317
+
314
318
  formatted = await prettier.format(content, FileFs.prettierConfig);
315
319
  } catch (ex) {
316
320
  // save prettier errror into log file