mcdev 7.0.4 → 7.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
  2. package/.husky/post-checkout +1 -1
  3. package/.husky/post-merge +7 -1
  4. package/.husky/pre-commit +2 -0
  5. package/@types/lib/Builder.d.ts.map +1 -1
  6. package/@types/lib/Deployer.d.ts +3 -0
  7. package/@types/lib/Deployer.d.ts.map +1 -1
  8. package/@types/lib/Retriever.d.ts.map +1 -1
  9. package/@types/lib/index.d.ts +70 -19
  10. package/@types/lib/index.d.ts.map +1 -1
  11. package/@types/lib/metadataTypes/Asset.d.ts +107 -16
  12. package/@types/lib/metadataTypes/Asset.d.ts.map +1 -1
  13. package/@types/lib/metadataTypes/AttributeGroup.d.ts +3 -0
  14. package/@types/lib/metadataTypes/AttributeGroup.d.ts.map +1 -1
  15. package/@types/lib/metadataTypes/AttributeSet.d.ts +80 -0
  16. package/@types/lib/metadataTypes/AttributeSet.d.ts.map +1 -1
  17. package/@types/lib/metadataTypes/Automation.d.ts +11 -0
  18. package/@types/lib/metadataTypes/Automation.d.ts.map +1 -1
  19. package/@types/lib/metadataTypes/Campaign.d.ts +1 -0
  20. package/@types/lib/metadataTypes/Campaign.d.ts.map +1 -1
  21. package/@types/lib/metadataTypes/ContentArea.d.ts +1 -0
  22. package/@types/lib/metadataTypes/ContentArea.d.ts.map +1 -1
  23. package/@types/lib/metadataTypes/DataExtension.d.ts +5 -2
  24. package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
  25. package/@types/lib/metadataTypes/DataExtensionField.d.ts +3 -4
  26. package/@types/lib/metadataTypes/DataExtensionField.d.ts.map +1 -1
  27. package/@types/lib/metadataTypes/DataExtensionTemplate.d.ts +1 -0
  28. package/@types/lib/metadataTypes/DataExtensionTemplate.d.ts.map +1 -1
  29. package/@types/lib/metadataTypes/DataExtract.d.ts +1 -0
  30. package/@types/lib/metadataTypes/DataExtract.d.ts.map +1 -1
  31. package/@types/lib/metadataTypes/DataExtractType.d.ts +1 -0
  32. package/@types/lib/metadataTypes/DataExtractType.d.ts.map +1 -1
  33. package/@types/lib/metadataTypes/DeliveryProfile.d.ts +1 -0
  34. package/@types/lib/metadataTypes/DeliveryProfile.d.ts.map +1 -1
  35. package/@types/lib/metadataTypes/Discovery.d.ts +1 -0
  36. package/@types/lib/metadataTypes/Discovery.d.ts.map +1 -1
  37. package/@types/lib/metadataTypes/Email.d.ts +1 -0
  38. package/@types/lib/metadataTypes/Email.d.ts.map +1 -1
  39. package/@types/lib/metadataTypes/EmailSend.d.ts +9 -1
  40. package/@types/lib/metadataTypes/EmailSend.d.ts.map +1 -1
  41. package/@types/lib/metadataTypes/Event.d.ts +99 -0
  42. package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
  43. package/@types/lib/metadataTypes/FileLocation.d.ts +1 -0
  44. package/@types/lib/metadataTypes/FileLocation.d.ts.map +1 -1
  45. package/@types/lib/metadataTypes/FileTransfer.d.ts +1 -0
  46. package/@types/lib/metadataTypes/FileTransfer.d.ts.map +1 -1
  47. package/@types/lib/metadataTypes/Filter.d.ts +1 -0
  48. package/@types/lib/metadataTypes/Filter.d.ts.map +1 -1
  49. package/@types/lib/metadataTypes/Folder.d.ts +39 -25
  50. package/@types/lib/metadataTypes/Folder.d.ts.map +1 -1
  51. package/@types/lib/metadataTypes/ImportFile.d.ts +30 -1
  52. package/@types/lib/metadataTypes/ImportFile.d.ts.map +1 -1
  53. package/@types/lib/metadataTypes/Journey.d.ts +123 -3
  54. package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
  55. package/@types/lib/metadataTypes/List.d.ts +1 -0
  56. package/@types/lib/metadataTypes/List.d.ts.map +1 -1
  57. package/@types/lib/metadataTypes/MetadataType.d.ts +50 -3
  58. package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
  59. package/@types/lib/metadataTypes/MobileCode.d.ts +1 -0
  60. package/@types/lib/metadataTypes/MobileCode.d.ts.map +1 -1
  61. package/@types/lib/metadataTypes/MobileKeyword.d.ts +9 -0
  62. package/@types/lib/metadataTypes/MobileKeyword.d.ts.map +1 -1
  63. package/@types/lib/metadataTypes/MobileMessage.d.ts +4 -0
  64. package/@types/lib/metadataTypes/MobileMessage.d.ts.map +1 -1
  65. package/@types/lib/metadataTypes/Query.d.ts +3 -0
  66. package/@types/lib/metadataTypes/Query.d.ts.map +1 -1
  67. package/@types/lib/metadataTypes/Role.d.ts +1 -0
  68. package/@types/lib/metadataTypes/Role.d.ts.map +1 -1
  69. package/@types/lib/metadataTypes/Script.d.ts +3 -1
  70. package/@types/lib/metadataTypes/Script.d.ts.map +1 -1
  71. package/@types/lib/metadataTypes/SendClassification.d.ts +3 -0
  72. package/@types/lib/metadataTypes/SendClassification.d.ts.map +1 -1
  73. package/@types/lib/metadataTypes/SenderProfile.d.ts +1 -6
  74. package/@types/lib/metadataTypes/SenderProfile.d.ts.map +1 -1
  75. package/@types/lib/metadataTypes/TransactionalEmail.d.ts +6 -0
  76. package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -1
  77. package/@types/lib/metadataTypes/TransactionalMessage.d.ts +1 -0
  78. package/@types/lib/metadataTypes/TransactionalMessage.d.ts.map +1 -1
  79. package/@types/lib/metadataTypes/TransactionalPush.d.ts +3 -0
  80. package/@types/lib/metadataTypes/TransactionalPush.d.ts.map +1 -1
  81. package/@types/lib/metadataTypes/TransactionalSMS.d.ts +4 -0
  82. package/@types/lib/metadataTypes/TransactionalSMS.d.ts.map +1 -1
  83. package/@types/lib/metadataTypes/TriggeredSend.d.ts +6 -6
  84. package/@types/lib/metadataTypes/TriggeredSend.d.ts.map +1 -1
  85. package/@types/lib/metadataTypes/User.d.ts +1 -0
  86. package/@types/lib/metadataTypes/User.d.ts.map +1 -1
  87. package/@types/lib/metadataTypes/Verification.d.ts +3 -0
  88. package/@types/lib/metadataTypes/Verification.d.ts.map +1 -1
  89. package/@types/lib/metadataTypes/definitions/Asset.definition.d.ts +78 -14
  90. package/@types/lib/metadataTypes/definitions/AttributeGroup.definition.d.ts +3 -0
  91. package/@types/lib/metadataTypes/definitions/AttributeSet.definition.d.ts +80 -0
  92. package/@types/lib/metadataTypes/definitions/Automation.definition.d.ts +16 -0
  93. package/@types/lib/metadataTypes/definitions/Campaign.definition.d.ts +1 -0
  94. package/@types/lib/metadataTypes/definitions/ContentArea.definition.d.ts +1 -0
  95. package/@types/lib/metadataTypes/definitions/DataExtension.definition.d.ts +1 -0
  96. package/@types/lib/metadataTypes/definitions/DataExtensionField.definition.d.ts +1 -0
  97. package/@types/lib/metadataTypes/definitions/DataExtensionTemplate.definition.d.ts +1 -0
  98. package/@types/lib/metadataTypes/definitions/DataExtract.definition.d.ts +1 -0
  99. package/@types/lib/metadataTypes/definitions/DataExtractType.definition.d.ts +1 -0
  100. package/@types/lib/metadataTypes/definitions/DeliveryProfile.definition.d.ts +1 -0
  101. package/@types/lib/metadataTypes/definitions/Discovery.definition.d.ts +1 -0
  102. package/@types/lib/metadataTypes/definitions/Email.definition.d.ts +1 -0
  103. package/@types/lib/metadataTypes/definitions/EmailSend.definition.d.ts +9 -1
  104. package/@types/lib/metadataTypes/definitions/Event.definition.d.ts +99 -0
  105. package/@types/lib/metadataTypes/definitions/FileLocation.definition.d.ts +1 -0
  106. package/@types/lib/metadataTypes/definitions/FileTransfer.definition.d.ts +1 -0
  107. package/@types/lib/metadataTypes/definitions/Filter.definition.d.ts +1 -0
  108. package/@types/lib/metadataTypes/definitions/Folder.definition.d.ts +1 -0
  109. package/@types/lib/metadataTypes/definitions/ImportFile.definition.d.ts +30 -1
  110. package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +94 -0
  111. package/@types/lib/metadataTypes/definitions/List.definition.d.ts +1 -0
  112. package/@types/lib/metadataTypes/definitions/MobileCode.definition.d.ts +1 -0
  113. package/@types/lib/metadataTypes/definitions/MobileKeyword.definition.d.ts +9 -0
  114. package/@types/lib/metadataTypes/definitions/MobileMessage.definition.d.ts +4 -0
  115. package/@types/lib/metadataTypes/definitions/Query.definition.d.ts +3 -0
  116. package/@types/lib/metadataTypes/definitions/Role.definition.d.ts +1 -0
  117. package/@types/lib/metadataTypes/definitions/Script.definition.d.ts +1 -0
  118. package/@types/lib/metadataTypes/definitions/SendClassification.definition.d.ts +3 -0
  119. package/@types/lib/metadataTypes/definitions/SenderProfile.definition.d.ts +1 -0
  120. package/@types/lib/metadataTypes/definitions/TransactionalEmail.definition.d.ts +6 -0
  121. package/@types/lib/metadataTypes/definitions/TransactionalMessage.definition.d.ts +1 -0
  122. package/@types/lib/metadataTypes/definitions/TransactionalPush.definition.d.ts +3 -0
  123. package/@types/lib/metadataTypes/definitions/TransactionalSMS.definition.d.ts +4 -0
  124. package/@types/lib/metadataTypes/definitions/TriggeredSend.definition.d.ts +6 -0
  125. package/@types/lib/metadataTypes/definitions/User.definition.d.ts +1 -0
  126. package/@types/lib/metadataTypes/definitions/Verification.definition.d.ts +3 -0
  127. package/@types/lib/util/cache.d.ts +10 -0
  128. package/@types/lib/util/cache.d.ts.map +1 -1
  129. package/@types/lib/util/cli.d.ts +3 -6
  130. package/@types/lib/util/cli.d.ts.map +1 -1
  131. package/@types/lib/util/config.d.ts.map +1 -1
  132. package/@types/lib/util/devops.d.ts.map +1 -1
  133. package/@types/lib/util/file.d.ts.map +1 -1
  134. package/@types/lib/util/init.config.d.ts.map +1 -1
  135. package/@types/lib/util/init.d.ts.map +1 -1
  136. package/@types/lib/util/init.git.d.ts.map +1 -1
  137. package/@types/lib/util/replaceContentBlockReference.d.ts +27 -4
  138. package/@types/lib/util/replaceContentBlockReference.d.ts.map +1 -1
  139. package/@types/lib/util/util.d.ts +32 -3
  140. package/@types/lib/util/util.d.ts.map +1 -1
  141. package/@types/types/mcdev.d.d.ts +87 -0
  142. package/@types/types/mcdev.d.d.ts.map +1 -1
  143. package/boilerplate/files/.vscode/settings.json +1 -0
  144. package/boilerplate/forcedUpdates.json +4 -0
  145. package/boilerplate/gitignore-template +0 -1
  146. package/lib/Builder.js +13 -8
  147. package/lib/Deployer.js +15 -7
  148. package/lib/Retriever.js +13 -2
  149. package/lib/cli.js +179 -14
  150. package/lib/index.js +543 -205
  151. package/lib/metadataTypes/Asset.js +469 -218
  152. package/lib/metadataTypes/Automation.js +34 -0
  153. package/lib/metadataTypes/DataExtension.js +34 -29
  154. package/lib/metadataTypes/DataExtensionField.js +2 -2
  155. package/lib/metadataTypes/Event.js +28 -2
  156. package/lib/metadataTypes/Folder.js +63 -48
  157. package/lib/metadataTypes/ImportFile.js +70 -28
  158. package/lib/metadataTypes/Journey.js +475 -95
  159. package/lib/metadataTypes/MetadataType.js +280 -61
  160. package/lib/metadataTypes/MobileKeyword.js +12 -1
  161. package/lib/metadataTypes/Script.js +4 -3
  162. package/lib/metadataTypes/SenderProfile.js +17 -5
  163. package/lib/metadataTypes/TriggeredSend.js +20 -5
  164. package/lib/metadataTypes/definitions/Asset.definition.js +66 -4
  165. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +1 -0
  166. package/lib/metadataTypes/definitions/AttributeSet.definition.js +86 -0
  167. package/lib/metadataTypes/definitions/Automation.definition.js +9 -0
  168. package/lib/metadataTypes/definitions/Campaign.definition.js +1 -0
  169. package/lib/metadataTypes/definitions/ContentArea.definition.js +1 -0
  170. package/lib/metadataTypes/definitions/DataExtension.definition.js +1 -0
  171. package/lib/metadataTypes/definitions/DataExtensionField.definition.js +1 -0
  172. package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +1 -0
  173. package/lib/metadataTypes/definitions/DataExtract.definition.js +2 -1
  174. package/lib/metadataTypes/definitions/DataExtractType.definition.js +1 -0
  175. package/lib/metadataTypes/definitions/DeliveryProfile.definition.js +1 -0
  176. package/lib/metadataTypes/definitions/Discovery.definition.js +1 -0
  177. package/lib/metadataTypes/definitions/Email.definition.js +1 -0
  178. package/lib/metadataTypes/definitions/EmailSend.definition.js +9 -1
  179. package/lib/metadataTypes/definitions/Event.definition.js +97 -96
  180. package/lib/metadataTypes/definitions/FileLocation.definition.js +1 -0
  181. package/lib/metadataTypes/definitions/FileTransfer.definition.js +4 -0
  182. package/lib/metadataTypes/definitions/Filter.definition.js +1 -0
  183. package/lib/metadataTypes/definitions/Folder.definition.js +10 -8
  184. package/lib/metadataTypes/definitions/ImportFile.definition.js +37 -2
  185. package/lib/metadataTypes/definitions/Journey.definition.js +111 -2
  186. package/lib/metadataTypes/definitions/List.definition.js +1 -0
  187. package/lib/metadataTypes/definitions/MobileCode.definition.js +1 -0
  188. package/lib/metadataTypes/definitions/MobileKeyword.definition.js +7 -0
  189. package/lib/metadataTypes/definitions/MobileMessage.definition.js +9 -0
  190. package/lib/metadataTypes/definitions/Query.definition.js +3 -0
  191. package/lib/metadataTypes/definitions/Role.definition.js +1 -0
  192. package/lib/metadataTypes/definitions/Script.definition.js +1 -0
  193. package/lib/metadataTypes/definitions/SendClassification.definition.js +4 -0
  194. package/lib/metadataTypes/definitions/SenderProfile.definition.js +1 -0
  195. package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +7 -0
  196. package/lib/metadataTypes/definitions/TransactionalMessage.definition.js +1 -0
  197. package/lib/metadataTypes/definitions/TransactionalPush.definition.js +3 -0
  198. package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +4 -0
  199. package/lib/metadataTypes/definitions/TriggeredSend.definition.js +12 -5
  200. package/lib/metadataTypes/definitions/User.definition.js +3 -0
  201. package/lib/metadataTypes/definitions/Verification.definition.js +1 -0
  202. package/lib/util/cache.js +35 -0
  203. package/lib/util/cli.js +96 -139
  204. package/lib/util/config.js +11 -19
  205. package/lib/util/devops.js +41 -41
  206. package/lib/util/file.js +1 -12
  207. package/lib/util/init.config.js +6 -10
  208. package/lib/util/init.git.js +43 -57
  209. package/lib/util/init.js +35 -59
  210. package/lib/util/replaceContentBlockReference.js +107 -60
  211. package/lib/util/util.js +90 -4
  212. package/package.json +14 -13
  213. package/test/general.test.js +1121 -167
  214. package/test/mockRoot/.mcdevrc.json +1 -1
  215. package/test/mockRoot/deploy/testInstance/testBU/event/testNew_event_withExistingDE.event-meta.json +1 -0
  216. package/test/mockRoot/deploy/testInstance/testBU/event/testNew_event_withSchema.event-meta.json +1 -0
  217. package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/4912312345678.TESTNEW_KEYWORD.mobileKeyword-meta.json +1 -0
  218. package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/4912312345678.TESTNEW_KEYWORD_BLOCKED.mobileKeyword-meta.json +1 -0
  219. package/test/resourceFactory.js +43 -11
  220. package/test/resources/1111111/dataFolder/retrieve-ContentTypeINshared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-response.xml +364 -0
  221. package/test/resources/9999999/asset/{block-1157-retrieve-expected.html → build-asset_htmlblock-expected.html} +1 -1
  222. package/test/resources/9999999/asset/build-asset_htmlblock-expected.json +29 -0
  223. package/test/resources/9999999/asset/build-templatebasedemail-expected.json +65 -0
  224. package/test/resources/9999999/asset/resolveId-1295064-noPath-expected.json +3 -3
  225. package/test/resources/9999999/asset/resolveId-1295064-withPath-expected.json +3 -3
  226. package/test/resources/9999999/asset/retrieve-templatebasedemail-expected.json +65 -0
  227. package/test/resources/9999999/asset/template-emailTemplate-expected.json +20 -0
  228. package/test/resources/9999999/asset/template-templatebasedemail-expected.json +65 -0
  229. package/test/resources/9999999/asset/template-testExisting_asset_htmlblock-expected.json +29 -0
  230. package/test/resources/9999999/asset/testExisting_asset_htmlblock-retrieve-expected.html +23 -0
  231. package/test/resources/9999999/asset/{block-1157-retrieve-expected.json → testExisting_asset_htmlblock-retrieve-expected.json} +3 -3
  232. package/test/resources/9999999/asset/testExisting_asset_message-html-rcb-key-expected.html +6 -6
  233. package/test/resources/9999999/asset/testExisting_asset_message-preheader-rcb-id-expected.amp +1 -1
  234. package/test/resources/9999999/asset/testExisting_asset_message-preheader-rcb-key-expected.amp +4 -4
  235. package/test/resources/9999999/asset/testExisting_asset_message-preheader-rcb-name-expected.amp +1 -1
  236. package/test/resources/9999999/asset/testExisting_asset_message-text-rcb-key-expected.amp +4 -4
  237. package/test/resources/9999999/asset/v1/content/assets/1295064/get-response.json +4 -4
  238. package/test/resources/9999999/asset/v1/content/assets/1295065/get-response.json +60 -0
  239. package/test/resources/9999999/asset/v1/content/assets/1295066/get-response.json +60 -0
  240. package/test/resources/9999999/asset/v1/content/assets/5289/get-response.json +75 -0
  241. package/test/resources/9999999/asset/v1/content/assets/808714/get-response.json +3 -3
  242. package/test/resources/9999999/asset/v1/content/assets/950143/get-response.json +97 -0
  243. package/test/resources/9999999/asset/v1/content/assets/get-response-customerKey=testExisting_asset.json +1 -1
  244. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN195,196,197,198,199,200,201,202,203,210,211,212,213,3.json +78 -2
  245. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN205,206,230,232,1,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,14,193,194,15,195,196,197,198,199,200,201,202,203,210,211,212,213,3,207,208,209,5,214,4,215,216.json +370 -0
  246. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN205,206,230,232,1,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,14,193,194,15,195,196,197,198,199,200,201,202,203,210,211,212,213,3,215,216,217,218,219,220,221,222.json +243 -0
  247. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN205,206,230,232,1,207,208,209,5.json +229 -0
  248. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN205,206,230,232,1.json +98 -1
  249. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN217,218,219,220,221,222,223,224,225,226,227,228.json +7 -0
  250. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN223,224,225,226,227,228,214,4.json +35 -0
  251. package/test/resources/9999999/asset/v1/content/assets/query/post-response-assetType.idIN223,224,225,226,227,228.json +7 -0
  252. package/test/resources/9999999/asset/v1/content/assets/query/{post-response-customerKey=mcdev-issue-1157.json → post-response-customerKey=testExisting_asset_htmlblock.json} +2 -2
  253. package/test/resources/9999999/automation/v1/imports/d2474efb-a449-ef11-b876-f40343c95928/get-response.json +37 -0
  254. package/test/resources/9999999/automation/v1/imports/get-response.json +32 -1
  255. package/test/resources/9999999/automation/v1/queries/get-response-Name=testExisting_query.json +24 -0
  256. package/test/resources/9999999/automation/v1/scripts/get-response-name=testExisting_script.json +17 -0
  257. package/test/resources/9999999/automation/v1/scripts/get-response.json +2 -2
  258. package/test/resources/9999999/dataFolder/retrieve-ContentType=asset-shared-QAA-response.xml +70 -0
  259. package/test/resources/9999999/dataFolder/retrieve-ContentType=asset-shared-response.xml +70 -0
  260. package/test/resources/9999999/dataFolder/retrieve-ContentType=journey-response.xml +48 -0
  261. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-sha,automatio,dataexten,hidden,journey,list,mysubs,publicati,queryacti,salesforc,shared_da,shared_da,shared_sa,ssjsactiv,synchroni,triggered,triggered,useriniti-response.xml +519 -0
  262. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-sha,dataexten,salesforc,shared_da,shared_da,shared_sa,synchroni,automatio,useriniti,journey,mysubs,list,publicati,queryacti,ssjsactiv,triggered,triggered-response.xml +519 -0
  263. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-shared,journey-response.xml +92 -0
  264. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-shared,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-QAA-response.xml +115 -0
  265. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-shared,ssjsactivity-response.xml +92 -0
  266. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-shared-QAA-response.xml +70 -0
  267. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset-shared,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-QAA-response.xml +431 -0
  268. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINautomations,queryactivity-response.xml +70 -0
  269. package/test/resources/9999999/dataFolder/{retrieve-response.xml → retrieve-ContentTypeINdataextension,hidden,queryactivity,salesforcedataextension,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-response.xml} +32 -119
  270. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINdataextension,salesforcedataextension,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-QAA-response.xml +117 -0
  271. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINhidden,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-response.xml +46 -0
  272. package/test/resources/9999999/dataFolder/retrieve-ContentTypeINshared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-QAA-response.xml +251 -0
  273. package/test/resources/9999999/dataFolder/retrieve-response-.xml +519 -0
  274. package/test/resources/9999999/event/build-expected.json +0 -1
  275. package/test/resources/9999999/event/get-expected.json +0 -1
  276. package/test/resources/9999999/event/post_withExistingDE-callout-expected.json +3 -0
  277. package/test/resources/9999999/event/post_withExistingDE-expected.json +2 -0
  278. package/test/resources/9999999/event/post_withSchema-callout-expected.json +3 -0
  279. package/test/resources/9999999/event/post_withSchema-expected.json +2 -0
  280. package/test/resources/9999999/event/put-callout-expected.json +3 -1
  281. package/test/resources/9999999/event/put-expected.json +2 -2
  282. package/test/resources/9999999/event/template-expected.json +0 -1
  283. package/test/resources/9999999/importFile/build-expected.json +2 -4
  284. package/test/resources/9999999/importFile/get-dataImport-expected.json +36 -0
  285. package/test/resources/9999999/importFile/get-expected.json +2 -4
  286. package/test/resources/9999999/importFile/get-sms-expected.json +2 -1
  287. package/test/resources/9999999/importFile/patch-expected.json +2 -4
  288. package/test/resources/9999999/importFile/post-expected.json +2 -4
  289. package/test/resources/9999999/importFile/template-expected.json +2 -4
  290. package/test/resources/9999999/interaction/v1/eventDefinitions/key_testExisting_event/put-response.json +2 -1
  291. package/test/resources/9999999/interaction/v1/eventDefinitions/post_withExistingDE-response.json +2 -0
  292. package/test/resources/9999999/interaction/v1/eventDefinitions/post_withSchema-response.json +2 -0
  293. package/test/resources/9999999/interaction/v1/interactions/3c3f4112-9b43-43ca-8a89-aa0375b2c1a2/get-response.json +4 -4
  294. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_journey_Quicksend/get-response.json +4 -4
  295. package/test/resources/9999999/interaction/v1/interactions/publishAsync/3c3f4112-9b43-43ca-8a89-aa0375b2c1a2/post-response.json +4 -0
  296. package/test/resources/9999999/interaction/v1/interactions/publishStatus/45f06c0a-3ed2-48b2-a6a8-b5119253f01c/get-response-failed.json +34 -0
  297. package/test/resources/9999999/interaction/v1/interactions/publishStatus/45f06c0a-3ed2-48b2-a6a8-b5119253f01c/get-response-success.json +5 -0
  298. package/test/resources/9999999/interaction/v1/interactions/publishStatus/45f06c0a-3ed2-48b2-a6a8-b5119253f01c/get-response-successWarnings.json +36 -0
  299. package/test/resources/9999999/journey/build-expected.json +5 -5
  300. package/test/resources/9999999/journey/get-multistep-expected.json +1 -1
  301. package/test/resources/9999999/journey/get-quicksend-expected.json +5 -5
  302. package/test/resources/9999999/journey/get-quicksend-rcb-id-expected.json +1 -1
  303. package/test/resources/9999999/journey/get-quicksend-rcb-key-expected.json +7 -7
  304. package/test/resources/9999999/journey/get-quicksend-rcb-name-expected.json +1 -1
  305. package/test/resources/9999999/journey/post-expected.json +1 -1
  306. package/test/resources/9999999/journey/publish-callout-expected.json +1 -0
  307. package/test/resources/9999999/journey/put-expected.json +1 -1
  308. package/test/resources/9999999/journey/template-expected.json +5 -5
  309. package/test/resources/9999999/mobileKeyword/build-expected.json +1 -0
  310. package/test/resources/9999999/mobileKeyword/get-expected.json +1 -0
  311. package/test/resources/9999999/mobileKeyword/post-create-expected.json +1 -0
  312. package/test/resources/9999999/mobileKeyword/template-expected.json +1 -0
  313. package/test/resources/{1111111/accountUser/retrieve-CustomerKey=testExisting_userANDActiveFlag=trueANDEmailisNullORNamelikeapp userANDMustChangePassword=false-response.xml → 9999999/queryDefinition/retrieve-CustomerKey=badANDStatus=Active-response.xml} +10 -11
  314. package/test/resources/9999999/script/get_ampincluded-rcb-key-expected.html +2 -2
  315. package/test/resources/9999999/script/get_ampscript-expected.html +1 -0
  316. package/test/resources/9999999/script/get_ampscript-rcb-id-expected.html +1 -0
  317. package/test/resources/9999999/script/get_ampscript-rcb-key-expected.html +3 -2
  318. package/test/resources/9999999/script/get_ampscript-rcb-name-expected.html +3 -0
  319. package/test/resources/9999999/script/get_mixed-expected.html +2 -2
  320. package/test/resources/9999999/script/get_mixed-rcb-key-expected.html +2 -2
  321. package/test/resources/9999999/senderProfile/get-rcb-key-expected.json +4 -4
  322. package/test/resources/9999999/senderProfile/retrieve-response.xml +1 -1
  323. package/test/resources/9999999/triggeredSend/get-rcb-key-expected.json +4 -4
  324. package/test/resources/9999999/triggeredSendDefinition/retrieve-TriggeredSendStatusINNew,Active,Inactive,Moved,Canceled-response.xml +1 -1
  325. package/test/type.asset.test.js +232 -39
  326. package/test/type.automation.test.js +121 -77
  327. package/test/type.dataExtract.test.js +4 -4
  328. package/test/type.emailSend.test.js +3 -3
  329. package/test/type.event.test.js +0 -2
  330. package/test/type.importFile.test.js +12 -7
  331. package/test/type.journey.test.js +322 -9
  332. package/test/type.query.test.js +33 -29
  333. package/test/type.script.test.js +61 -11
  334. package/test/type.senderProfile.test.js +36 -3
  335. package/test/type.transactionalEmail.test.js +3 -3
  336. package/test/type.triggeredSend.test.js +75 -6
  337. package/test/utils.js +13 -3
  338. package/types/mcdev.d.js +27 -1
  339. /package/test/resources/1111111/accountUser/{retrieve-ActiveFlag=falseANDCustomerKey=testExisting_userANDEmaillike@-response.xml → retrieve-ActiveFlag=falseANDCustomerKey=testExisting_userANDEmaillike@-QAA-response.xml} +0 -0
  340. /package/test/resources/1111111/accountUser/{retrieve-ActiveFlag=falseANDEmaillike@-response.xml → retrieve-ActiveFlag=falseANDEmaillike@-QAA-response.xml} +0 -0
  341. /package/test/resources/1111111/accountUser/{retrieve-ActiveFlag=trueANDCustomerKey=testExisting_userANDEmaillike@-response.xml → retrieve-ActiveFlag=trueANDCustomerKey=testExisting_userANDEmaillike@-QAA-response.xml} +0 -0
  342. /package/test/resources/1111111/accountUser/{retrieve-ActiveFlag=trueANDEmailisNullORNamelikeapp userANDMustChangePassword=false-response.xml → retrieve-ActiveFlag=trueANDEmailisNullORNamelikeapp userANDMustChangePassword=false-QAA-response.xml} +0 -0
  343. /package/test/resources/1111111/accountUser/{retrieve-ActiveFlag=trueANDEmaillike@-response.xml → retrieve-ActiveFlag=trueANDEmaillike@-QAA-response.xml} +0 -0
  344. /package/test/resources/1111111/businessUnit/{retrieve-ID=1111111-response.xml → retrieve-ID=1111111-QAA-response.xml} +0 -0
  345. /package/test/resources/1111111/dataFolder/{retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml → retrieve-ContentTypeINdataextension,hidden,salesforcedataextension,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-response.xml} +0 -0
  346. /package/test/resources/1111111/dataFolder/{retrieve-response.xml → retrieve-response-.xml} +0 -0
  347. /package/test/resources/9999999/dataFolder/{retrieve-ContentType=asset-sharedORContentType=asset-response.xml → retrieve-ContentTypeINasset,asset-shared-response.xml} +0 -0
  348. /package/test/resources/9999999/dataFolder/{retrieve-ContentType=contextual_suppression_listORContentType=publicationORContentType=suppression_listORContentType=mysubsORContentType=list-response.xml → retrieve-ContentTypeINcontextual_suppression_list,list,mysubs,publication,suppression_list-response.xml} +0 -0
  349. /package/test/resources/9999999/dataFolder/{retrieve-ContentType=synchronizeddataextensionORContentType=shared_salesforcedataextensionORContentType=shared_dataextensionORContentType=shared_dataORContentType=salesforcedataextensionORContentType=dataextensionORContentType=hidden-response.xml → retrieve-ContentTypeINdataextension,hidden,salesforcedataextension,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-response.xml} +0 -0
  350. /package/test/resources/9999999/dataFolder/{retrieve-ContentType=triggered_send_journeybuilderORContentType=triggered_sendORContentType=hidden-response.xml → retrieve-ContentTypeINhidden,triggered_send,triggered_send_journeybuilder-response.xml} +0 -0
package/lib/index.js CHANGED
@@ -17,6 +17,8 @@ import Retriever from './Retriever.js';
17
17
  import cache from './util/cache.js';
18
18
  import ReplaceContentBlockReference from './util/replaceContentBlockReference.js';
19
19
 
20
+ import { confirm } from '@inquirer/prompts';
21
+
20
22
  /**
21
23
  * @typedef {import('../types/mcdev.d.js').BuObject} BuObject
22
24
  * @typedef {import('../types/mcdev.d.js').CodeExtract} CodeExtract
@@ -79,28 +81,34 @@ class Mcdev {
79
81
  static setOptions(argv) {
80
82
  const knownOptions = [
81
83
  'api',
82
- 'keySuffix',
83
84
  'changeKeyField',
84
85
  'changeKeyValue',
85
86
  'commitHistory',
87
+ 'dependencies',
86
88
  'errorLog',
87
89
  'execute',
88
90
  'filter',
89
91
  'fixShared',
90
92
  'fromRetrieve',
91
93
  'json',
94
+ 'keySuffix',
92
95
  'like',
93
96
  'noLogColors',
94
97
  'noLogFile',
95
- 'noMidSuffix',
98
+ 'noUpdate',
99
+ 'autoMidSuffix',
100
+ 'publish',
96
101
  'referenceFrom',
97
102
  'referenceTo',
98
103
  'refresh',
99
- 'skipDeploy',
100
- 'skipRetrieve',
104
+ 'retrieve',
101
105
  'schedule',
106
+ 'skipDeploy',
102
107
  'skipInteraction',
108
+ 'skipRetrieve',
109
+ 'skipStatusCheck',
103
110
  '_runningTest',
111
+ '_welcomeMessageShown',
104
112
  ];
105
113
  for (const option of knownOptions) {
106
114
  if (argv[option] !== undefined) {
@@ -139,16 +147,20 @@ class Mcdev {
139
147
  return null;
140
148
  }
141
149
 
142
- return argv.filter
143
- ? // get source market and source BU from config
144
- DevOps.getDeltaList(properties, argv.range, true, argv.filter, argv.commitHistory)
145
- : // If no custom filter was provided, use deployment marketLists & templating
146
- DevOps.buildDeltaDefinitions(
147
- properties,
148
- argv.range,
149
- argv.diffArr,
150
- argv.commitHistory
151
- );
150
+ try {
151
+ return await (argv.filter
152
+ ? // get source market and source BU from config
153
+ DevOps.getDeltaList(properties, argv.range, true, argv.filter, argv.commitHistory)
154
+ : // If no custom filter was provided, use deployment marketLists & templating
155
+ DevOps.buildDeltaDefinitions(
156
+ properties,
157
+ argv.range,
158
+ argv.diffArr,
159
+ argv.commitHistory
160
+ ));
161
+ } catch (ex) {
162
+ Util.logger.error(ex.message);
163
+ }
152
164
  }
153
165
 
154
166
  /**
@@ -189,6 +201,12 @@ class Mcdev {
189
201
  * helper to show an off-the-logs message to users
190
202
  */
191
203
  static #welcomeMessage() {
204
+ if (Util.OPTIONS._welcomeMessageShown) {
205
+ // ensure we don't spam the user in case methods are called multiple times
206
+ return;
207
+ }
208
+ Util.OPTIONS._welcomeMessageShown = true;
209
+
192
210
  const color = Util.isRunViaVSCodeExtension
193
211
  ? { reset: '', bgWhite: '', fgBlue: '' }
194
212
  : Util.color;
@@ -352,6 +370,9 @@ class Mcdev {
352
370
  * @returns {Promise.<object>} ensure that BUs are worked on sequentially
353
371
  */
354
372
  static async #retrieveBU(cred, bu, selectedTypesArr, keys, changelogOnly) {
373
+ // ensure changes to the selectedTypesArr on one BU do not affect other BUs called in the same go
374
+ selectedTypesArr = structuredClone(selectedTypesArr);
375
+
355
376
  const properties = await config.getProperties();
356
377
  if (!(await config.checkProperties(properties))) {
357
378
  return null;
@@ -482,7 +503,11 @@ class Mcdev {
482
503
  Util.startLogger();
483
504
  Util.logger.info('mcdev:: Setting up project');
484
505
  const properties = await config.getProperties(!!credentialsName, true);
485
- await Init.initProject(properties, credentialsName);
506
+ try {
507
+ await Init.initProject(properties, credentialsName);
508
+ } catch (ex) {
509
+ Util.logger.error(ex.message);
510
+ }
486
511
  }
487
512
  /**
488
513
  * Clones an existing project from git repository and installs it
@@ -492,7 +517,11 @@ class Mcdev {
492
517
  static async joinProject() {
493
518
  Util.startLogger();
494
519
  Util.logger.info('mcdev:: Joining an existing project');
495
- await Init.joinProject();
520
+ try {
521
+ await Init.joinProject();
522
+ } catch (ex) {
523
+ Util.logger.error(ex.message);
524
+ }
496
525
  }
497
526
 
498
527
  /**
@@ -706,6 +735,54 @@ class Mcdev {
706
735
  }
707
736
  }
708
737
  }
738
+ /**
739
+ * method for contributors to get details on SOAP objects
740
+ *
741
+ * @param {string} type references credentials from properties.json
742
+ * @param {string} [businessUnit] defaults to first credential's ParentBU
743
+ * @returns {Promise.<void>} -
744
+ */
745
+ static async describeSoap(type, businessUnit) {
746
+ Util.startLogger();
747
+ Util.logger.info('mcdev:: describe SOAP');
748
+ const properties = await config.getProperties();
749
+ if (!(await config.checkProperties(properties))) {
750
+ return null;
751
+ }
752
+ const credential = Object.keys(properties.credentials)[0];
753
+ businessUnit ||=
754
+ credential + '/' + Object.keys(properties.credentials[credential].businessUnits)[0];
755
+ const buObject = await Cli.getCredentialObject(properties, businessUnit);
756
+ if (!buObject) {
757
+ return;
758
+ }
759
+ try {
760
+ const client = auth.getSDK(buObject);
761
+ const response = await client.soap.describe(type);
762
+ if (response?.ObjectDefinition?.Properties) {
763
+ Util.logger.info(
764
+ `Properties for SOAP object ${response.ObjectDefinition.ObjectType}:`
765
+ );
766
+ const properties = response.ObjectDefinition.Properties.map((prop) => {
767
+ delete prop.PartnerKey;
768
+ delete prop.ObjectID;
769
+ return prop;
770
+ });
771
+ if (Util.OPTIONS.json) {
772
+ console.log(JSON.stringify(properties, null, 2)); // eslint-disable-line no-console
773
+ } else {
774
+ console.table(properties); // eslint-disable-line no-console
775
+ }
776
+ return properties;
777
+ } else {
778
+ throw new Error(
779
+ `Soap object ${type} not found. Please check the spelling and retry`
780
+ );
781
+ }
782
+ } catch (ex) {
783
+ Util.logger.error(ex.message);
784
+ }
785
+ }
709
786
 
710
787
  /**
711
788
  * Converts metadata to legacy format. Output is saved in 'converted' directory
@@ -821,6 +898,172 @@ class Mcdev {
821
898
  }
822
899
  }
823
900
  }
901
+ /**
902
+ * @param {string} businessUnit references credentials from properties.json
903
+ * @param {TypeKeyCombo} selectedTypes limit retrieval to given metadata type
904
+ * @returns {Promise.<TypeKeyCombo>} selected types including dependencies
905
+ */
906
+ static async addDependentCbReferences(businessUnit, selectedTypes) {
907
+ if (!Util.OPTIONS.dependencies) {
908
+ return;
909
+ }
910
+ const initialAssetNumber = selectedTypes['asset']?.length || 0;
911
+ const properties = await config.getProperties();
912
+ const buObject = await Cli.getCredentialObject(properties, businessUnit);
913
+ Util.logger.info(
914
+ 'Searching for additional dependencies that were linked via ContentBlockByKey, ContentBlockByName and ContentBlockById'
915
+ );
916
+
917
+ await ReplaceContentBlockReference.createCacheMap(properties, buObject, true);
918
+
919
+ // because we re-use the replaceReference logic here we need to manually set this value
920
+ /** @type {ContentBlockConversionTypes[]} */
921
+ Util.OPTIONS.referenceFrom = ['key', 'name', 'id'];
922
+ /** @type {ContentBlockConversionTypes} */
923
+ Util.OPTIONS.referenceTo = 'key';
924
+
925
+ /** @type {Set.<string>} */
926
+ const assetDependencies = new Set();
927
+ const retrieveDir = File.filterIllegalPathChars(
928
+ File.normalizePath([
929
+ properties.directories.retrieve,
930
+ buObject.credential,
931
+ buObject.businessUnit,
932
+ ])
933
+ );
934
+ // check all non-asset types for dependencies
935
+ for (const depType in selectedTypes) {
936
+ if (
937
+ !Object.prototype.hasOwnProperty.call(
938
+ MetadataTypeInfo[depType],
939
+ 'replaceCbReference'
940
+ ) ||
941
+ depType === 'asset'
942
+ ) {
943
+ continue;
944
+ }
945
+ MetadataTypeInfo[depType].properties = properties;
946
+ MetadataTypeInfo[depType].buObject = buObject;
947
+ await MetadataTypeInfo[depType].getCbReferenceKeys(
948
+ selectedTypes[depType],
949
+ retrieveDir,
950
+ assetDependencies
951
+ );
952
+ }
953
+ // add dependencies to selectedTypes
954
+ if (assetDependencies.size) {
955
+ const depType = 'asset';
956
+ if (selectedTypes[depType]) {
957
+ selectedTypes[depType].push(...assetDependencies);
958
+ } else {
959
+ selectedTypes[depType] = [...assetDependencies];
960
+ }
961
+ // remove duplicates in main object after adding dependencies
962
+ selectedTypes[depType] = [...new Set(selectedTypes[depType])];
963
+ }
964
+
965
+ // check all assets for dependencies recursively
966
+ if (selectedTypes.asset?.length) {
967
+ const depType = 'asset';
968
+ const Asset = MetadataTypeInfo[depType];
969
+ Asset.properties = properties;
970
+ Asset.buObject = buObject;
971
+ const additionalAssetDependencies = [
972
+ ...(await Asset.getCbReferenceKeys(
973
+ selectedTypes[depType],
974
+ retrieveDir,
975
+ new Set(selectedTypes[depType])
976
+ )),
977
+ ];
978
+ if (additionalAssetDependencies.length) {
979
+ Util.logger.info(
980
+ `Found ${additionalAssetDependencies.length - initialAssetNumber} additional assets linked via ContentBlockByX.`
981
+ );
982
+ }
983
+ // reset cache in case this is used progammatically somehow
984
+ Asset.getJsonFromFSCache = null;
985
+
986
+ // remove duplicates in main object after adding dependencies
987
+ selectedTypes[depType] = [...new Set(selectedTypes[depType])];
988
+ }
989
+
990
+ return selectedTypes;
991
+ }
992
+
993
+ /**
994
+ *
995
+ * @param {string} businessUnit references credentials from properties.json
996
+ * @param {TypeKeyCombo} selectedTypes limit retrieval to given metadata type
997
+ * @returns {Promise.<TypeKeyCombo>} dependencies
998
+ */
999
+ static async addDependencies(businessUnit, selectedTypes) {
1000
+ if (!Util.OPTIONS.dependencies) {
1001
+ return;
1002
+ }
1003
+ Util.logger.info(
1004
+ 'You might see warnings about items not being found if you have not re-retrieved everything lately.'
1005
+ );
1006
+
1007
+ // try re-retrieve without passing selectedTypes to ensure we find all dependencies
1008
+ await this._reRetrieve(businessUnit, true);
1009
+
1010
+ Util.logger.info(
1011
+ 'Searching for selected items and their dependencies in your project folder'
1012
+ );
1013
+ /** @type {TypeKeyCombo} */
1014
+ const dependencies = {};
1015
+ /** @type {TypeKeyCombo} */
1016
+ const notFoundList = {};
1017
+ const initiallySelectedTypesArr = Object.keys(selectedTypes);
1018
+
1019
+ const properties = await config.getProperties();
1020
+ const buObject = await Cli.getCredentialObject(properties, businessUnit);
1021
+ for (const type of initiallySelectedTypesArr) {
1022
+ MetadataTypeInfo[type].properties = properties;
1023
+ MetadataTypeInfo[type].buObject = buObject;
1024
+ await MetadataTypeInfo[type].getDependentFiles(
1025
+ selectedTypes[type],
1026
+ dependencies,
1027
+ notFoundList,
1028
+ true
1029
+ );
1030
+ }
1031
+ if (Util.getTypeKeyCount(notFoundList)) {
1032
+ // if we have missing items, we need to retrieve them
1033
+ Util.logger.warn(
1034
+ `We recommend you retrieve the missing items with the following command and then re-run buildDefinition:`
1035
+ );
1036
+ Util.logger.warn(
1037
+ ` mcdev retrieve ${businessUnit} ${Util.convertTypeKeyToCli(notFoundList)}`
1038
+ );
1039
+ }
1040
+
1041
+ // remove duplicates & empty types
1042
+ for (const type in dependencies) {
1043
+ if (dependencies[type].length) {
1044
+ dependencies[type] = [...new Set(dependencies[type])];
1045
+ } else {
1046
+ delete dependencies[type];
1047
+ }
1048
+ }
1049
+
1050
+ // add dependencies to selectedTypes
1051
+ if (Object.keys(dependencies).length) {
1052
+ Util.logger.info(
1053
+ `Found ${Util.getTypeKeyCount(dependencies)} items across ${Object.keys(dependencies).length} types.`
1054
+ );
1055
+ for (const type in dependencies) {
1056
+ if (selectedTypes[type]) {
1057
+ selectedTypes[type].push(...dependencies[type]);
1058
+ } else {
1059
+ selectedTypes[type] = dependencies[type];
1060
+ }
1061
+ // remove duplicates in main object after adding dependencies
1062
+ selectedTypes[type] = [...new Set(selectedTypes[type])];
1063
+ }
1064
+ }
1065
+ return dependencies;
1066
+ }
824
1067
 
825
1068
  /**
826
1069
  * Build a template based on a list of metadata files in the retrieve folder.
@@ -847,6 +1090,20 @@ class Mcdev {
847
1090
  );
848
1091
  return;
849
1092
  }
1093
+ const properties = await config.getProperties();
1094
+ if (!Util.checkMarket(marketTemplate, properties)) {
1095
+ return;
1096
+ }
1097
+ // check if types are valid
1098
+ for (const type of Object.keys(typeKeyCombo)) {
1099
+ if (!Util._isValidType(type)) {
1100
+ return;
1101
+ }
1102
+ if (!Array.isArray(typeKeyCombo[type])) {
1103
+ // we need an array of keys here
1104
+ return;
1105
+ }
1106
+ }
850
1107
 
851
1108
  Util.logger.info('mcdev:: Build Template & Build Definition');
852
1109
  await this.buildTemplate(businessUnitTemplate, typeKeyCombo, null, marketTemplate);
@@ -864,37 +1121,86 @@ class Mcdev {
864
1121
  * @returns {Promise.<MultiMetadataTypeList>} -
865
1122
  */
866
1123
  static async buildTemplate(businessUnit, selectedTypes, keyArr, market) {
1124
+ this.#welcomeMessage();
1125
+
867
1126
  Util.startLogger();
868
1127
  Util.logger.info('mcdev:: Build Template from retrieved files');
869
- let selectedTypesArr;
1128
+ const properties = await config.getProperties();
1129
+ if (!Util.checkMarket(market, properties)) {
1130
+ return;
1131
+ }
870
1132
  if ('string' === typeof selectedTypes) {
871
- selectedTypesArr = [selectedTypes];
872
- } else {
873
- selectedTypesArr = Object.keys(selectedTypes);
874
- // check if types are valid
875
- for (const selectedType of selectedTypesArr) {
876
- if (!Util._isValidType(selectedType)) {
877
- return;
878
- }
879
- if (!Array.isArray(selectedTypes[selectedType])) {
880
- // we need an array of keys here
881
- return;
882
- }
1133
+ // ensure we have TypeKeyCombo here
1134
+ selectedTypes = Util.createTypeKeyCombo(selectedTypes, keyArr);
1135
+ }
1136
+ // check if types are valid
1137
+ for (const type of Object.keys(selectedTypes)) {
1138
+ if (!Util._isValidType(type)) {
1139
+ return;
1140
+ }
1141
+ if (!Array.isArray(selectedTypes[type])) {
1142
+ // we need an array of keys here
1143
+ return;
883
1144
  }
884
1145
  }
1146
+
1147
+ if (!Util.OPTIONS.dependencies) {
1148
+ await this._reRetrieve(businessUnit, false, selectedTypes);
1149
+ }
1150
+
1151
+ // if dependencies are enabled, we need to search for them and add them to our
1152
+ await this.addDependencies(businessUnit, selectedTypes);
1153
+ await this.addDependentCbReferences(businessUnit, selectedTypes);
1154
+
885
1155
  /** @type {MultiMetadataTypeList} */
886
1156
  const returnObj = {};
887
- for (const selectedType of selectedTypesArr) {
1157
+ for (const type of Object.keys(selectedTypes)) {
888
1158
  const result = await Builder.buildTemplate(
889
1159
  businessUnit,
890
- selectedType,
891
- 'string' === typeof selectedTypes ? keyArr : selectedTypes[selectedType],
1160
+ type,
1161
+ selectedTypes[type],
892
1162
  market
893
1163
  );
894
- returnObj[selectedType] = result[selectedType];
1164
+ returnObj[type] = result[type];
1165
+ }
1166
+ Util.logger.info(`Templated ${Util.getTypeKeyCount(returnObj)} items`);
1167
+ if (Util.OPTIONS.dependencies) {
1168
+ Util.logger.info(
1169
+ `You can now run buildDefinition to create the deployment package. Don't forget to adjust the BU and market!`
1170
+ );
1171
+ Util.logger.info(
1172
+ ` mcdev bd ${businessUnit} ${Util.convertTypeKeyToCli(selectedTypes)} --market ${market}`
1173
+ );
895
1174
  }
896
1175
  return returnObj;
897
1176
  }
1177
+
1178
+ /**
1179
+ * Build a specific metadata file based on a template.
1180
+ *
1181
+ * @param {string} businessUnit references credentials from properties.json
1182
+ * @param {boolean} [alwaysAsk] by default this code only runs if --retrieve is set; this flag allows to always ask
1183
+ * @param {TypeKeyCombo} [selectedTypes] limit retrieval to given metadata type
1184
+ * @returns {Promise.<void>} -
1185
+ */
1186
+ static async _reRetrieve(businessUnit, alwaysAsk = false, selectedTypes) {
1187
+ let runRetrieveNow;
1188
+ if (!Util.OPTIONS.skipInteraction && !Util.OPTIONS.retrieve && alwaysAsk) {
1189
+ runRetrieveNow = await confirm({
1190
+ message: `Do you want to re-retrieve ${selectedTypes ? Util.convertTypeKeyToString(selectedTypes) : 'all metadata'} for ${businessUnit} now?`,
1191
+ default: false,
1192
+ });
1193
+ }
1194
+ if (runRetrieveNow || Util.OPTIONS.retrieve) {
1195
+ Util.logger.info(
1196
+ `Re-retrieving ${businessUnit}: ${selectedTypes ? Util.convertTypeKeyToString(selectedTypes) : 'all metadata'}`
1197
+ );
1198
+ // we need to work with a clone here because retrieve() modifies the object passed in as 2nd parameter
1199
+ const retrieveTypes = structuredClone(selectedTypes);
1200
+ await this.retrieve(businessUnit, retrieveTypes);
1201
+ }
1202
+ }
1203
+
898
1204
  /**
899
1205
  * Build a specific metadata file based on a template.
900
1206
  *
@@ -905,35 +1211,41 @@ class Mcdev {
905
1211
  * @returns {Promise.<MultiMetadataTypeList>} -
906
1212
  */
907
1213
  static async buildDefinition(businessUnit, selectedTypes, nameArr, market) {
1214
+ this.#welcomeMessage();
1215
+
908
1216
  Util.startLogger();
909
1217
  Util.logger.info('mcdev:: Build Definition from Template');
910
- let selectedTypesArr;
1218
+ const properties = await config.getProperties();
1219
+ if (!Util.checkMarket(market, properties)) {
1220
+ return;
1221
+ }
911
1222
  if ('string' === typeof selectedTypes) {
912
- selectedTypesArr = [selectedTypes];
913
- } else {
914
- selectedTypesArr = Object.keys(selectedTypes);
915
- // check if types are valid
916
- for (const selectedType of selectedTypesArr) {
917
- if (!Util._isValidType(selectedType)) {
918
- return;
919
- }
920
- if (!Array.isArray(selectedTypes[selectedType])) {
921
- // we need an array of keys here
922
- return;
923
- }
1223
+ // ensure we have TypeKeyCombo here
1224
+ selectedTypes = Util.createTypeKeyCombo(selectedTypes, nameArr);
1225
+ }
1226
+
1227
+ // check if types are valid
1228
+ for (const type of Object.keys(selectedTypes)) {
1229
+ if (!Util._isValidType(type)) {
1230
+ return;
1231
+ }
1232
+ if (!Array.isArray(selectedTypes[type])) {
1233
+ // we need an array of keys here
1234
+ return;
924
1235
  }
925
1236
  }
926
1237
  /** @type {MultiMetadataTypeList} */
927
1238
  const returnObj = {};
928
- for (const selectedType of selectedTypesArr) {
1239
+ for (const type of Object.keys(selectedTypes)) {
929
1240
  const result = await Builder.buildDefinition(
930
1241
  businessUnit,
931
- selectedType,
932
- 'string' === typeof selectedTypes ? nameArr : selectedTypes[selectedType],
1242
+ type,
1243
+ selectedTypes[type],
933
1244
  market
934
1245
  );
935
- returnObj[selectedType] = result[selectedType];
1246
+ returnObj[type] = result[type];
936
1247
  }
1248
+ Util.logger.info('Done');
937
1249
  return returnObj;
938
1250
  }
939
1251
 
@@ -946,6 +1258,8 @@ class Mcdev {
946
1258
  * @returns {Promise.<object>} -
947
1259
  */
948
1260
  static async buildDefinitionBulk(listName, selectedTypes, nameArr) {
1261
+ this.#welcomeMessage();
1262
+
949
1263
  Util.startLogger();
950
1264
  Util.logger.info('mcdev:: Build Definition from Template Bulk');
951
1265
  let selectedTypesArr;
@@ -977,6 +1291,7 @@ class Mcdev {
977
1291
  );
978
1292
  returnObj[selectedType] = result;
979
1293
  }
1294
+ Util.logger.info('Done');
980
1295
  return returnObj;
981
1296
  }
982
1297
  /**
@@ -1011,35 +1326,46 @@ class Mcdev {
1011
1326
  * Schedule an item (shortcut for execute --schedule)
1012
1327
  *
1013
1328
  * @param {string} businessUnit name of BU
1014
- * @param {string} [selectedType] limit to given metadata types
1329
+ * @param {string[] | TypeKeyCombo} [selectedTypes] limit to given metadata types
1015
1330
  * @param {string[]} [keys] customerkey of the metadata
1016
- * @returns {Promise.<Object.<string, string[]>>} key: business unit name, value: list of scheduled item keys
1331
+ * @returns {Promise.<Object.<string, Object.<string, string[]>>>} key: business unit name, key2: type, value: list of affected item keys
1017
1332
  */
1018
- static async schedule(businessUnit, selectedType, keys) {
1333
+ static async schedule(businessUnit, selectedTypes, keys) {
1019
1334
  this.setOptions({ schedule: true });
1020
- return this.#runMethod('execute', businessUnit, selectedType, keys);
1335
+ return this.#runMethod('execute', businessUnit, selectedTypes, keys);
1336
+ }
1337
+ /**
1338
+ * Publish an item
1339
+ *
1340
+ * @param {string} businessUnit name of BU
1341
+ * @param {string[] | TypeKeyCombo} selectedTypes limit to given metadata types
1342
+ * @param {string[]} [keys] customerkey of the metadata
1343
+ * @returns {Promise.<Object.<string, Object.<string, string[]>>>} key: business unit name, key2: type, value: list of affected item keys
1344
+ */
1345
+ static async publish(businessUnit, selectedTypes, keys) {
1346
+ return this.#runMethod('publish', businessUnit, selectedTypes, keys);
1021
1347
  }
1022
1348
  /**
1023
1349
  * Start/execute an item
1024
1350
  *
1025
1351
  * @param {string} businessUnit name of BU
1026
- * @param {string} [selectedType] limit to given metadata types
1352
+ * @param {string[] | TypeKeyCombo} [selectedTypes] limit to given metadata types
1027
1353
  * @param {string[]} [keys] customerkey of the metadata
1028
- * @returns {Promise.<Object.<string, string[]>>} key: business unit name, value: list of executed item keys
1354
+ * @returns {Promise.<Object.<string, Object.<string, string[]>>>} key: business unit name, key2: type, value: list of affected item keys
1029
1355
  */
1030
- static async execute(businessUnit, selectedType, keys) {
1031
- return this.#runMethod('execute', businessUnit, selectedType, keys);
1356
+ static async execute(businessUnit, selectedTypes, keys) {
1357
+ return this.#runMethod('execute', businessUnit, selectedTypes, keys);
1032
1358
  }
1033
1359
  /**
1034
1360
  * pause an item
1035
1361
  *
1036
1362
  * @param {string} businessUnit name of BU
1037
- * @param {string} [selectedType] limit to given metadata types
1363
+ * @param {string[] | TypeKeyCombo} [selectedTypes] limit to given metadata types
1038
1364
  * @param {string[]} [keys] customerkey of the metadata
1039
- * @returns {Promise.<Object.<string, string[]>>} key: business unit name, value: list of paused item keys
1365
+ * @returns {Promise.<Object.<string, Object.<string, string[]>>>} key: business unit name, key2: type, value: list of affected item keys
1040
1366
  */
1041
- static async pause(businessUnit, selectedType, keys) {
1042
- return this.#runMethod('pause', businessUnit, selectedType, keys);
1367
+ static async pause(businessUnit, selectedTypes, keys) {
1368
+ return this.#runMethod('pause', businessUnit, selectedTypes, keys);
1043
1369
  }
1044
1370
  /**
1045
1371
  * Updates the key to match the name field
@@ -1121,19 +1447,11 @@ class Mcdev {
1121
1447
  ).join(', ')}`
1122
1448
  );
1123
1449
 
1124
- const response = {};
1125
- for (const selectedType of Array.isArray(selectedTypesArr)
1126
- ? selectedTypesArr
1127
- : Object.keys(selectedTypesObj)) {
1128
- const temp = await this.#runMethod(
1129
- 'replaceCbReference',
1130
- businessUnit,
1131
- selectedType,
1132
- Array.isArray(selectedTypesArr) ? null : selectedTypesObj[selectedType]
1133
- );
1134
- response[businessUnit] ||= {};
1135
- response[businessUnit][selectedType] = temp[businessUnit];
1136
- }
1450
+ const response = await this.#runMethod(
1451
+ 'replaceCbReference',
1452
+ businessUnit,
1453
+ selectedTypesArr || selectedTypesObj
1454
+ );
1137
1455
 
1138
1456
  return response;
1139
1457
  }
@@ -1192,30 +1510,20 @@ class Mcdev {
1192
1510
  skipInteraction: { fixKeysReretrieve: false },
1193
1511
  });
1194
1512
  }
1195
-
1196
- const response = {};
1197
- for (const selectedType of selectedTypesArr || Object.keys(selectedTypesObj)) {
1198
- if (selectedType === 'event') {
1199
- Util.logger.warn(
1200
- `Type 'event' is not supported for fixKeys for compatibility reasons. Draft Journeys would otherwise be broken after the key change. If you do need to update an event key, use deploy --changeKeyValue or --changeKeyField instead.`
1201
- );
1202
- if (Array.isArray(selectedTypes)) {
1203
- selectedTypes = selectedTypes.filter((type) => type !== 'event');
1204
- } else {
1205
- delete selectedTypes.event;
1206
- }
1207
- continue;
1208
- }
1209
- const temp = await this.#runMethod(
1210
- 'fixKeys',
1211
- businessUnit,
1212
- selectedType,
1213
- selectedTypesArr ? keys : selectedTypesObj[selectedType]
1214
- );
1215
- response[businessUnit] ||= {};
1216
- response[businessUnit][selectedType] = temp[businessUnit];
1513
+ // `Type 'event' is not supported for fixKeys for compatibility reasons. Draft Journeys would otherwise be broken after the key change. If you do need to update an event key, use deploy --changeKeyValue or --changeKeyField instead.`;
1514
+ if (Array.isArray(selectedTypes) && selectedTypes.includes('event')) {
1515
+ selectedTypesArr = selectedTypes.filter((type) => type !== 'event');
1516
+ } else if (selectedTypesObj && selectedTypesObj.event) {
1517
+ delete selectedTypesObj.event;
1217
1518
  }
1218
1519
 
1520
+ const response = await this.#runMethod(
1521
+ 'fixKeys',
1522
+ businessUnit,
1523
+ selectedTypesArr || selectedTypesObj,
1524
+ keys
1525
+ );
1526
+
1219
1527
  if (reRetrieveAll) {
1220
1528
  // only done if selectedTypesArr is set as fallback
1221
1529
  Util.logger.info(
@@ -1230,19 +1538,19 @@ class Mcdev {
1230
1538
  /**
1231
1539
  * run a method across BUs
1232
1540
  *
1233
- * @param {'execute'|'pause'|'fixKeys'|'replaceCbReference'} methodName what to run
1541
+ * @param {'execute'|'pause'|'publish'|'fixKeys'|'replaceCbReference'} methodName what to run
1234
1542
  * @param {string} businessUnit name of BU
1235
- * @param {string} [selectedType] limit to given metadata types
1543
+ * @param {string[] | TypeKeyCombo} [selectedTypes] limit to given metadata types
1236
1544
  * @param {string[]} [keys] customerkey of the metadata
1237
- * @returns {Promise.<Object.<string, string[]>>} key: business unit name, value: list of affected item keys
1545
+ * @returns {Promise.<Object.<string, Object.<string, string[]>>>} key: business unit name, key2: type, value: list of affected item keys
1238
1546
  */
1239
- static async #runMethod(methodName, businessUnit, selectedType, keys) {
1547
+ static async #runMethod(methodName, businessUnit, selectedTypes, keys) {
1240
1548
  Util.startLogger();
1241
1549
  let lang_past;
1242
1550
  let lang_present;
1243
1551
  let requireKeyOrLike;
1244
1552
  let checkMetadataSupport;
1245
- /** @type {Object.<string, string[]>} */
1553
+ /** @type {Object.<string, Object.<string, string[]>>} */
1246
1554
  const resultObj = {};
1247
1555
 
1248
1556
  switch (methodName) {
@@ -1260,6 +1568,13 @@ class Mcdev {
1260
1568
  checkMetadataSupport = true;
1261
1569
  break;
1262
1570
  }
1571
+ case 'publish': {
1572
+ lang_past = 'published';
1573
+ lang_present = 'publishing';
1574
+ requireKeyOrLike = true;
1575
+ checkMetadataSupport = true;
1576
+ break;
1577
+ }
1263
1578
  case 'fixKeys': {
1264
1579
  lang_past = 'fixed keys';
1265
1580
  lang_present = 'fixing keys';
@@ -1275,125 +1590,148 @@ class Mcdev {
1275
1590
  break;
1276
1591
  }
1277
1592
  }
1278
-
1279
- Util.logger.info(`mcdev:: ${methodName} ${selectedType}`);
1593
+ /** @typedef {string[]} */
1594
+ let selectedTypesArr;
1595
+ /** @typedef {TypeKeyCombo} */
1596
+ let selectedTypesObj;
1597
+ if (selectedTypes) {
1598
+ // check if types are valid
1599
+ for (const selectedType of Array.isArray(selectedTypes)
1600
+ ? selectedTypes
1601
+ : Object.keys(selectedTypes)) {
1602
+ if (!Util._isValidType(selectedType)) {
1603
+ return resultObj;
1604
+ }
1605
+ if (
1606
+ checkMetadataSupport &&
1607
+ !Object.prototype.hasOwnProperty.call(
1608
+ MetadataTypeInfo[selectedType],
1609
+ methodName
1610
+ )
1611
+ ) {
1612
+ Util.logger.error(
1613
+ ` ☇ skipping ${selectedType}: ${methodName} is not supported yet for ${selectedType}`
1614
+ );
1615
+ return resultObj;
1616
+ }
1617
+ }
1618
+ if (Array.isArray(selectedTypes)) {
1619
+ selectedTypesArr = selectedTypes;
1620
+ } else {
1621
+ selectedTypesObj = selectedTypes;
1622
+ }
1623
+ }
1280
1624
  const properties = await config.getProperties();
1281
- let counter_credBu = 0;
1282
- let counter_credKeys = 0;
1283
1625
  if (!(await config.checkProperties(properties))) {
1284
1626
  // return null here to avoid seeing 2 error messages for the same issue
1285
1627
  return resultObj;
1286
1628
  }
1287
- if (!Util._isValidType(selectedType)) {
1288
- return resultObj;
1289
- }
1290
- if (
1291
- checkMetadataSupport &&
1292
- !Object.prototype.hasOwnProperty.call(MetadataTypeInfo[selectedType], methodName)
1293
- ) {
1294
- Util.logger.error(
1295
- ` skipping ${selectedType}: ${methodName} is not supported yet for ${selectedType}`
1296
- );
1297
- return resultObj;
1298
- }
1299
-
1300
- if (
1301
- requireKeyOrLike &&
1302
- (!Array.isArray(keys) || !keys.length) &&
1303
- (!Util.OPTIONS.like || !Object.keys(Util.OPTIONS.like).length)
1304
- ) {
1305
- Util.logger.error('At least one key or a --like filter is required.');
1306
- return resultObj;
1307
- } else if (
1308
- Array.isArray(keys) &&
1309
- keys.length &&
1310
- Util.OPTIONS.like &&
1311
- Object.keys(Util.OPTIONS.like).length
1312
- ) {
1313
- Util.logger.error('You can either specify keys OR a --like filter.');
1314
- return resultObj;
1315
- }
1629
+ for (const selectedType of selectedTypesArr || Object.keys(selectedTypesObj)) {
1630
+ Util.logger.info(`mcdev:: ${methodName} ${selectedType}`);
1631
+ let counter_credBu = 0;
1632
+ let counter_credKeys = 0;
1633
+ const keyArr = selectedTypesArr ? keys : selectedTypesObj[selectedType];
1634
+ if (
1635
+ requireKeyOrLike &&
1636
+ (!Array.isArray(keyArr) || !keyArr.length) &&
1637
+ (!Util.OPTIONS.like || !Object.keys(Util.OPTIONS.like).length)
1638
+ ) {
1639
+ Util.logger.error('At least one key or a --like filter is required.');
1640
+ return resultObj;
1641
+ } else if (
1642
+ Array.isArray(keyArr) &&
1643
+ keyArr.length &&
1644
+ Util.OPTIONS.like &&
1645
+ Object.keys(Util.OPTIONS.like).length
1646
+ ) {
1647
+ Util.logger.error('You can either specify keys OR a --like filter.');
1648
+ return resultObj;
1649
+ }
1316
1650
 
1317
- if (businessUnit === '*') {
1318
- Util.OPTIONS._multiBuExecution = true;
1319
- Util.logger.info(
1320
- `:: ${lang_present} the ${selectedType} on all BUs for all credentials`
1321
- );
1322
- let counter_credTotal = 0;
1323
- for (const cred in properties.credentials) {
1324
- Util.logger.info(`:: ${lang_present} ${selectedType} on all BUs for ${cred}`);
1325
- // reset counter per cred
1326
- counter_credKeys = 0;
1327
- counter_credBu = 0;
1328
- for (const bu in properties.credentials[cred].businessUnits) {
1329
- resultObj[cred + '/' + bu] = await this.#runOnBU(
1330
- methodName,
1331
- cred,
1332
- bu,
1333
- selectedType,
1334
- keys
1651
+ if (businessUnit === '*') {
1652
+ Util.OPTIONS._multiBuExecution = true;
1653
+ Util.logger.info(
1654
+ `:: ${lang_present} the ${selectedType} on all BUs for all credentials`
1655
+ );
1656
+ let counter_credTotal = 0;
1657
+ for (const cred in properties.credentials) {
1658
+ Util.logger.info(`:: ${lang_present} ${selectedType} on all BUs for ${cred}`);
1659
+ // reset counter per cred
1660
+ counter_credKeys = 0;
1661
+ counter_credBu = 0;
1662
+ for (const bu in properties.credentials[cred].businessUnits) {
1663
+ resultObj[cred + '/' + bu] ||= {};
1664
+ resultObj[cred + '/' + bu][selectedType] = await this.#runOnBU(
1665
+ methodName,
1666
+ cred,
1667
+ bu,
1668
+ selectedType,
1669
+ keyArr
1670
+ );
1671
+ counter_credBu++;
1672
+ counter_credKeys += resultObj[cred + '/' + bu][selectedType].length;
1673
+ Util.startLogger(true);
1674
+ }
1675
+ counter_credTotal += counter_credBu;
1676
+ Util.logger.info(
1677
+ `:: ${lang_past} for ${counter_credKeys} ${selectedType}s on ${counter_credBu} BUs for ${cred}`
1335
1678
  );
1336
- counter_credBu++;
1337
- counter_credKeys += resultObj[cred + '/' + bu].length;
1338
- Util.startLogger(true);
1339
1679
  }
1340
- counter_credTotal += counter_credBu;
1341
1680
  Util.logger.info(
1342
- `:: ${lang_past} for ${counter_credKeys} ${selectedType}s on ${counter_credBu} BUs for ${cred}`
1681
+ `:: ${lang_past} ${selectedType} on ${counter_credTotal} BUs in total\n`
1343
1682
  );
1344
- }
1345
- Util.logger.info(
1346
- `:: ${lang_past} ${selectedType} on ${counter_credTotal} BUs in total\n`
1347
- );
1348
- } else {
1349
- let [cred, bu] = businessUnit ? businessUnit.split('/') : [null, null];
1350
- // to allow all-BU via user selection we need to run this here already
1351
- if (
1352
- properties.credentials &&
1353
- (!properties.credentials[cred] ||
1354
- (bu !== '*' && !properties.credentials[cred].businessUnits[bu]))
1355
- ) {
1356
- const buObject = await Cli.getCredentialObject(
1357
- properties,
1358
- cred === null ? null : cred + '/' + bu,
1359
- null,
1360
- true
1361
- );
1362
- if (buObject === null) {
1363
- return resultObj;
1364
- } else {
1365
- cred = buObject.credential;
1366
- bu = buObject.businessUnit;
1683
+ } else {
1684
+ let [cred, bu] = businessUnit ? businessUnit.split('/') : [null, null];
1685
+ // to allow all-BU via user selection we need to run this here already
1686
+ if (
1687
+ properties.credentials &&
1688
+ (!properties.credentials[cred] ||
1689
+ (bu !== '*' && !properties.credentials[cred].businessUnits[bu]))
1690
+ ) {
1691
+ const buObject = await Cli.getCredentialObject(
1692
+ properties,
1693
+ cred === null ? null : cred + '/' + bu,
1694
+ null,
1695
+ true
1696
+ );
1697
+ if (buObject === null) {
1698
+ return resultObj;
1699
+ } else {
1700
+ cred = buObject.credential;
1701
+ bu = buObject.businessUnit;
1702
+ }
1367
1703
  }
1368
- }
1369
- if (bu === '*' && properties.credentials && properties.credentials[cred]) {
1370
- Util.OPTIONS._multiBuExecution = true;
1371
- Util.logger.info(`:: ${lang_present} ${selectedType} on all BUs for ${cred}`);
1372
- for (const bu in properties.credentials[cred].businessUnits) {
1373
- resultObj[cred + '/' + bu] = await this.#runOnBU(
1704
+ if (bu === '*' && properties.credentials && properties.credentials[cred]) {
1705
+ Util.OPTIONS._multiBuExecution = true;
1706
+ Util.logger.info(`:: ${lang_present} ${selectedType} on all BUs for ${cred}`);
1707
+ for (const bu in properties.credentials[cred].businessUnits) {
1708
+ resultObj[cred + '/' + bu] ||= {};
1709
+ resultObj[cred + '/' + bu][selectedType] = await this.#runOnBU(
1710
+ methodName,
1711
+ cred,
1712
+ bu,
1713
+ selectedType,
1714
+ keyArr
1715
+ );
1716
+ counter_credBu++;
1717
+ counter_credKeys += resultObj[cred + '/' + bu][selectedType].length;
1718
+ Util.startLogger(true);
1719
+ }
1720
+ Util.logger.info(
1721
+ `:: ${lang_past} for ${counter_credKeys} ${selectedType}s on ${counter_credBu} BUs for ${cred}`
1722
+ );
1723
+ } else {
1724
+ // execute runMethod for the entity on one BU only
1725
+ resultObj[cred + '/' + bu] ||= {};
1726
+ resultObj[cred + '/' + bu][selectedType] = await this.#runOnBU(
1374
1727
  methodName,
1375
1728
  cred,
1376
1729
  bu,
1377
1730
  selectedType,
1378
- keys
1731
+ keyArr
1379
1732
  );
1380
- counter_credBu++;
1381
- counter_credKeys += resultObj[cred + '/' + bu].length;
1382
- Util.startLogger(true);
1733
+ Util.logger.info(`:: Done`);
1383
1734
  }
1384
- Util.logger.info(
1385
- `:: ${lang_past} for ${counter_credKeys} ${selectedType}s on ${counter_credBu} BUs for ${cred}`
1386
- );
1387
- } else {
1388
- // execute runMethod for the entity on one BU only
1389
- resultObj[cred + '/' + bu] = await this.#runOnBU(
1390
- methodName,
1391
- cred,
1392
- bu,
1393
- selectedType,
1394
- keys
1395
- );
1396
- Util.logger.info(`:: Done`);
1397
1735
  }
1398
1736
  }
1399
1737
  return resultObj;
@@ -1401,7 +1739,7 @@ class Mcdev {
1401
1739
  /**
1402
1740
  * helper for Mcdev.#runMethod
1403
1741
  *
1404
- * @param {'execute'|'pause'|'fixKeys'|'replaceCbReference'} methodName what to run
1742
+ * @param {'execute'|'pause'|'publish'|'fixKeys'|'replaceCbReference'} methodName what to run
1405
1743
  * @param {string} cred name of Credential
1406
1744
  * @param {string} bu name of BU
1407
1745
  * @param {string} [type] limit execution to given metadata type