mcdev 7.7.1 → 7.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
- package/.github/workflows/coverage-base-update.yml +2 -2
- package/.github/workflows/coverage.yml +1 -1
- package/@types/lib/Builder.d.ts.map +1 -1
- package/@types/lib/index.d.ts +1 -0
- package/@types/lib/index.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Asset.d.ts +1 -0
- package/@types/lib/metadataTypes/Asset.d.ts.map +1 -1
- package/@types/lib/metadataTypes/AttributeGroup.d.ts +1 -0
- package/@types/lib/metadataTypes/AttributeGroup.d.ts.map +1 -1
- package/@types/lib/metadataTypes/AttributeSet.d.ts +1 -0
- package/@types/lib/metadataTypes/AttributeSet.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Automation.d.ts +1 -0
- package/@types/lib/metadataTypes/Automation.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Campaign.d.ts +1 -0
- package/@types/lib/metadataTypes/Campaign.d.ts.map +1 -1
- package/@types/lib/metadataTypes/ContentArea.d.ts +1 -0
- package/@types/lib/metadataTypes/ContentArea.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtension.d.ts +1 -0
- package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtensionField.d.ts +1 -0
- package/@types/lib/metadataTypes/DataExtensionField.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtensionTemplate.d.ts +1 -0
- package/@types/lib/metadataTypes/DataExtensionTemplate.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtract.d.ts +1 -0
- package/@types/lib/metadataTypes/DataExtract.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtractType.d.ts +1 -0
- package/@types/lib/metadataTypes/DataExtractType.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DeliveryProfile.d.ts +1 -0
- package/@types/lib/metadataTypes/DeliveryProfile.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Discovery.d.ts +1 -0
- package/@types/lib/metadataTypes/Discovery.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DomainVerification.d.ts +1 -0
- package/@types/lib/metadataTypes/DomainVerification.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Email.d.ts +1 -0
- package/@types/lib/metadataTypes/Email.d.ts.map +1 -1
- package/@types/lib/metadataTypes/EmailSend.d.ts +1 -0
- package/@types/lib/metadataTypes/EmailSend.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Event.d.ts +1 -0
- package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
- package/@types/lib/metadataTypes/FileLocation.d.ts +1 -0
- package/@types/lib/metadataTypes/FileLocation.d.ts.map +1 -1
- package/@types/lib/metadataTypes/FileTransfer.d.ts +1 -0
- package/@types/lib/metadataTypes/FileTransfer.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Filter.d.ts +1 -0
- package/@types/lib/metadataTypes/Filter.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Folder.d.ts +1 -0
- package/@types/lib/metadataTypes/Folder.d.ts.map +1 -1
- package/@types/lib/metadataTypes/ImportFile.d.ts +1 -0
- package/@types/lib/metadataTypes/ImportFile.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Journey.d.ts +7 -1
- package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
- package/@types/lib/metadataTypes/List.d.ts +1 -0
- package/@types/lib/metadataTypes/List.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MetadataType.d.ts +3 -3
- package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MobileCode.d.ts +1 -0
- package/@types/lib/metadataTypes/MobileCode.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MobileKeyword.d.ts +1 -0
- package/@types/lib/metadataTypes/MobileKeyword.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MobileMessage.d.ts +1 -0
- package/@types/lib/metadataTypes/MobileMessage.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Query.d.ts +1 -0
- package/@types/lib/metadataTypes/Query.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Role.d.ts +1 -0
- package/@types/lib/metadataTypes/Role.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Script.d.ts +1 -0
- package/@types/lib/metadataTypes/Script.d.ts.map +1 -1
- package/@types/lib/metadataTypes/SendClassification.d.ts +1 -0
- package/@types/lib/metadataTypes/SendClassification.d.ts.map +1 -1
- package/@types/lib/metadataTypes/SenderProfile.d.ts +1 -0
- package/@types/lib/metadataTypes/SenderProfile.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TransactionalEmail.d.ts +1 -0
- package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TransactionalMessage.d.ts +1 -0
- package/@types/lib/metadataTypes/TransactionalMessage.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TransactionalPush.d.ts +1 -0
- package/@types/lib/metadataTypes/TransactionalPush.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TransactionalSMS.d.ts +1 -0
- package/@types/lib/metadataTypes/TransactionalSMS.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TriggeredSend.d.ts +1 -0
- package/@types/lib/metadataTypes/TriggeredSend.d.ts.map +1 -1
- package/@types/lib/metadataTypes/User.d.ts +1 -0
- package/@types/lib/metadataTypes/User.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Verification.d.ts +1 -0
- package/@types/lib/metadataTypes/Verification.d.ts.map +1 -1
- package/@types/lib/metadataTypes/definitions/Asset.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/AttributeGroup.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/AttributeSet.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Automation.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Campaign.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/ContentArea.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/DataExtension.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/DataExtensionField.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/DataExtensionTemplate.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/DataExtract.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/DataExtractType.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/DeliveryProfile.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Discovery.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/DomainVerification.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Email.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/EmailSend.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Event.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/FileLocation.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/FileTransfer.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Filter.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Folder.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/ImportFile.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +7 -0
- package/@types/lib/metadataTypes/definitions/List.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/MobileCode.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/MobileKeyword.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/MobileMessage.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Query.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Role.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Script.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/SendClassification.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/SenderProfile.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/TransactionalEmail.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/TransactionalMessage.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/TransactionalPush.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/TransactionalSMS.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/TriggeredSend.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/User.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/Verification.definition.d.ts +1 -0
- package/@types/lib/util/config.d.ts.map +1 -1
- package/@types/lib/util/devops.d.ts +9 -0
- package/@types/lib/util/devops.d.ts.map +1 -1
- package/@types/lib/util/util.d.ts +2 -2
- package/@types/lib/util/util.d.ts.map +1 -1
- package/@types/lib/util/validations.d.ts +3 -2
- package/@types/lib/util/validations.d.ts.map +1 -1
- package/@types/types/mcdev.d.d.ts +6 -0
- package/@types/types/mcdev.d.d.ts.map +1 -1
- package/boilerplate/config.json +2 -1
- package/boilerplate/files/.vscode/extensions.json +1 -0
- package/boilerplate/forcedUpdates.json +4 -0
- package/lib/Builder.js +7 -0
- package/lib/cli.js +5 -0
- package/lib/index.js +57 -44
- package/lib/metadataTypes/Asset.js +32 -1
- package/lib/metadataTypes/Automation.js +5 -2
- package/lib/metadataTypes/DataExtension.js +5 -1
- package/lib/metadataTypes/Event.js +1 -0
- package/lib/metadataTypes/ImportFile.js +1 -0
- package/lib/metadataTypes/Journey.js +3 -1
- package/lib/metadataTypes/MetadataType.js +45 -9
- package/lib/metadataTypes/MobileKeyword.js +1 -0
- package/lib/metadataTypes/MobileMessage.js +1 -0
- package/lib/metadataTypes/TransactionalMessage.js +3 -0
- package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
- package/lib/metadataTypes/definitions/AttributeGroup.definition.js +1 -0
- package/lib/metadataTypes/definitions/AttributeSet.definition.js +1 -0
- package/lib/metadataTypes/definitions/Automation.definition.js +1 -0
- package/lib/metadataTypes/definitions/Campaign.definition.js +1 -0
- package/lib/metadataTypes/definitions/ContentArea.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtension.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtensionField.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtract.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtractType.definition.js +1 -0
- package/lib/metadataTypes/definitions/DeliveryProfile.definition.js +1 -0
- package/lib/metadataTypes/definitions/Discovery.definition.js +1 -0
- package/lib/metadataTypes/definitions/DomainVerification.definition.js +1 -0
- package/lib/metadataTypes/definitions/Email.definition.js +1 -0
- package/lib/metadataTypes/definitions/EmailSend.definition.js +1 -0
- package/lib/metadataTypes/definitions/Event.definition.js +1 -0
- package/lib/metadataTypes/definitions/FileLocation.definition.js +1 -0
- package/lib/metadataTypes/definitions/FileTransfer.definition.js +1 -0
- package/lib/metadataTypes/definitions/Filter.definition.js +1 -0
- package/lib/metadataTypes/definitions/Folder.definition.js +1 -0
- package/lib/metadataTypes/definitions/ImportFile.definition.js +1 -0
- package/lib/metadataTypes/definitions/Journey.definition.js +1 -0
- package/lib/metadataTypes/definitions/List.definition.js +1 -0
- package/lib/metadataTypes/definitions/MobileCode.definition.js +1 -0
- package/lib/metadataTypes/definitions/MobileKeyword.definition.js +1 -0
- package/lib/metadataTypes/definitions/MobileMessage.definition.js +1 -0
- package/lib/metadataTypes/definitions/Query.definition.js +1 -0
- package/lib/metadataTypes/definitions/Role.definition.js +1 -0
- package/lib/metadataTypes/definitions/Script.definition.js +1 -0
- package/lib/metadataTypes/definitions/SendClassification.definition.js +1 -0
- package/lib/metadataTypes/definitions/SenderProfile.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalMessage.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalPush.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +1 -0
- package/lib/metadataTypes/definitions/TriggeredSend.definition.js +1 -0
- package/lib/metadataTypes/definitions/User.definition.js +1 -0
- package/lib/metadataTypes/definitions/Verification.definition.js +1 -0
- package/lib/util/config.js +3 -1
- package/lib/util/devops.js +131 -1
- package/lib/util/util.js +4 -3
- package/lib/util/validations.js +25 -3
- package/package.json +9 -9
- package/test/general.test.js +28 -0
- package/test/mockRoot/.mcdev-validations.js +40 -12
- package/test/mockRoot/.mcdevrc.json +23 -1
- package/test/utils.js +10 -38
- package/types/mcdev.d.js +7 -4
package/lib/util/devops.js
CHANGED
|
@@ -266,7 +266,22 @@ const DevOps = {
|
|
|
266
266
|
'Please note that deletions have to be done manually on the SFMC website.'
|
|
267
267
|
);
|
|
268
268
|
}
|
|
269
|
-
Util.logger.info(
|
|
269
|
+
Util.logger.info(
|
|
270
|
+
`Saved report in ./${directoryDeltaPkg}${Util.logFileName}-delta_package.md`
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// const deletedTypeKeys = {};
|
|
274
|
+
// for (const file of delta.filter((file) => file.gitAction === 'delete')) {
|
|
275
|
+
// if (deletedTypeKeys[file.type]) {
|
|
276
|
+
// deletedTypeKeys[file.type].add(file.externalKey);
|
|
277
|
+
// } else {
|
|
278
|
+
// deletedTypeKeys[file.type] = new Set([file.externalKey]);
|
|
279
|
+
// }
|
|
280
|
+
// }
|
|
281
|
+
// for (const deletedType in deletedTypeKeys) {
|
|
282
|
+
// const keyArr = [...deletedTypeKeys[deletedType]];
|
|
283
|
+
// Util.logger.warn(`Found deleted ${deletedType} keys: ${keyArr.join(', ')}`);
|
|
284
|
+
// }
|
|
270
285
|
|
|
271
286
|
// Copy filtered list of files into deploy directory
|
|
272
287
|
// only do that if we do not use templating
|
|
@@ -506,6 +521,17 @@ const DevOps = {
|
|
|
506
521
|
}
|
|
507
522
|
}
|
|
508
523
|
for (const buFrom in buTypeDelta) {
|
|
524
|
+
for (const type of Object.keys(buTypeDelta[buFrom])) {
|
|
525
|
+
if (
|
|
526
|
+
Array.isArray(properties.metaDataTypes.createDeltaPkg) &&
|
|
527
|
+
!properties.metaDataTypes.createDeltaPkg.includes(type)
|
|
528
|
+
) {
|
|
529
|
+
Util.logger.warn(
|
|
530
|
+
`Skipping ${type} for build based on config.metaDataTypes.createDeltaPkg: ${buTypeDelta[buFrom][type].join(', ')}`
|
|
531
|
+
);
|
|
532
|
+
delete buTypeDelta[buFrom][type];
|
|
533
|
+
}
|
|
534
|
+
}
|
|
509
535
|
// Run buildTemplate for each business unit for each type
|
|
510
536
|
await mcdev.build(
|
|
511
537
|
buFrom,
|
|
@@ -516,6 +542,7 @@ const DevOps = {
|
|
|
516
542
|
true
|
|
517
543
|
);
|
|
518
544
|
}
|
|
545
|
+
this._generateDeleteInstructions(delta, sourceMarket, properties, targetMlName);
|
|
519
546
|
}
|
|
520
547
|
if (!deltaDeployAll.length) {
|
|
521
548
|
Util.logger.error(
|
|
@@ -575,6 +602,109 @@ const DevOps = {
|
|
|
575
602
|
MetadataType[metadataType].buObject = buObject;
|
|
576
603
|
return MetadataType[metadataType].getFilesToCommit(keyArr);
|
|
577
604
|
},
|
|
605
|
+
/**
|
|
606
|
+
* helper for {@link DevOps.buildDeltaDefinitions}
|
|
607
|
+
*
|
|
608
|
+
* @param {DeltaPkgItem[]} delta git delta
|
|
609
|
+
* @param {string} sourceMarket market for the source BU
|
|
610
|
+
* @param {Mcdevrc} properties mcdev config
|
|
611
|
+
* @param {string} targetMlName marketList used to build for the target BU
|
|
612
|
+
*/
|
|
613
|
+
_generateDeleteInstructions(delta, sourceMarket, properties, targetMlName) {
|
|
614
|
+
const deltaDelete = delta
|
|
615
|
+
.filter((file) => file.gitAction === 'delete')
|
|
616
|
+
.filter(
|
|
617
|
+
// in case of assets we need to be careful because extracted code files might get deleted but that doesnt mean the asset was
|
|
618
|
+
(file) =>
|
|
619
|
+
file.type !== 'asset' || (file.type === 'asset' && file.file.endsWith('.json'))
|
|
620
|
+
);
|
|
621
|
+
const buTypeDeltaDelete = {}; // for bt, with BU info
|
|
622
|
+
|
|
623
|
+
for (const file of deltaDelete) {
|
|
624
|
+
const buFrom = `${file._credential}/${file._businessUnit}`;
|
|
625
|
+
if (!buTypeDeltaDelete[buFrom]) {
|
|
626
|
+
// init object
|
|
627
|
+
/** @type {TypeKeyCombo} */
|
|
628
|
+
buTypeDeltaDelete[buFrom] = {};
|
|
629
|
+
}
|
|
630
|
+
if (!buTypeDeltaDelete[buFrom][file.type]) {
|
|
631
|
+
// init array
|
|
632
|
+
buTypeDeltaDelete[buFrom][file.type] = [];
|
|
633
|
+
}
|
|
634
|
+
if (!buTypeDeltaDelete[buFrom][file.type].includes(file.externalKey)) {
|
|
635
|
+
buTypeDeltaDelete[buFrom][file.type].push(file.externalKey);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
const deleteByBU = {};
|
|
639
|
+
for (const buFrom in buTypeDeltaDelete) {
|
|
640
|
+
/** @type {TemplateMap} */
|
|
641
|
+
const sourceVariables = {};
|
|
642
|
+
if (Util.checkMarket(sourceMarket, properties)) {
|
|
643
|
+
Object.assign(sourceVariables, properties.markets[sourceMarket]);
|
|
644
|
+
}
|
|
645
|
+
const typeKeyFrom = {};
|
|
646
|
+
const typeKeyDelete = {};
|
|
647
|
+
for (const type of Object.keys(buTypeDeltaDelete[buFrom])) {
|
|
648
|
+
if (
|
|
649
|
+
Array.isArray(properties.metaDataTypes.createDeltaPkg) &&
|
|
650
|
+
!properties.metaDataTypes.createDeltaPkg.includes(type)
|
|
651
|
+
) {
|
|
652
|
+
Util.logger.warn(
|
|
653
|
+
`Skipping ${type} for delete based on config.metaDataTypes.createDeltaPkg: ${buTypeDeltaDelete[buFrom][type].join(', ')}`
|
|
654
|
+
);
|
|
655
|
+
delete buTypeDeltaDelete[buFrom][type];
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
typeKeyFrom[type] = new Set();
|
|
659
|
+
if (Object.keys(sourceVariables).length > 0) {
|
|
660
|
+
for (let i = 0; i < buTypeDeltaDelete[buFrom][type].length; i++) {
|
|
661
|
+
// add templating variables to keys
|
|
662
|
+
typeKeyFrom[type].add(
|
|
663
|
+
Util.replaceByObject(
|
|
664
|
+
buTypeDeltaDelete[buFrom][type][i],
|
|
665
|
+
sourceVariables
|
|
666
|
+
)
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
typeKeyFrom[type] = Array.from(typeKeyFrom[type]);
|
|
671
|
+
for (const targetBu in properties.marketList[targetMlName]) {
|
|
672
|
+
typeKeyDelete[targetBu] ||= {};
|
|
673
|
+
typeKeyDelete[targetBu][type] ||= [];
|
|
674
|
+
deleteByBU[targetBu] || {};
|
|
675
|
+
const market = properties.marketList[targetMlName][targetBu];
|
|
676
|
+
const markets = 'string' === typeof market ? [market] : market;
|
|
677
|
+
for (const marketArr of markets) {
|
|
678
|
+
const templateVariables = {};
|
|
679
|
+
for (const market of Array.isArray(marketArr) ? marketArr : [marketArr]) {
|
|
680
|
+
if (Util.checkMarket(market, properties)) {
|
|
681
|
+
Object.assign(templateVariables, properties.markets[market]);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
typeKeyDelete[targetBu][type].push(
|
|
685
|
+
...typeKeyFrom[type].map((key) =>
|
|
686
|
+
MetadataType[type].applyTemplateValues(key, templateVariables)
|
|
687
|
+
)
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
for (const targetBu in typeKeyDelete) {
|
|
693
|
+
const metadataList = [];
|
|
694
|
+
for (const type in typeKeyDelete[targetBu]) {
|
|
695
|
+
for (const key of typeKeyDelete[targetBu][type]) {
|
|
696
|
+
metadataList.push(type + ':"' + key + '"');
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
if (metadataList.length) {
|
|
700
|
+
Util.logger.warn(
|
|
701
|
+
`Run the following to delete ${metadataList.length} potentially existing old files in ${targetBu}`
|
|
702
|
+
);
|
|
703
|
+
Util.logger.warn(`mcdev delete ${targetBu} -m ${metadataList.join(' ')}`);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
},
|
|
578
708
|
};
|
|
579
709
|
|
|
580
710
|
export default DevOps;
|
package/lib/util/util.js
CHANGED
|
@@ -309,14 +309,15 @@ export const Util = {
|
|
|
309
309
|
/**
|
|
310
310
|
* helper for getDefaultProperties()
|
|
311
311
|
*
|
|
312
|
+
* @param {string} field relevant field in type definition
|
|
312
313
|
* @returns {string[]} type choices
|
|
313
314
|
*/
|
|
314
|
-
|
|
315
|
+
getTypeChoices(field) {
|
|
315
316
|
const typeChoices = [];
|
|
316
317
|
for (const el in MetadataDefinitions) {
|
|
317
318
|
if (
|
|
318
|
-
Array.isArray(MetadataDefinitions[el]
|
|
319
|
-
MetadataDefinitions[el]
|
|
319
|
+
Array.isArray(MetadataDefinitions[el][field]) ||
|
|
320
|
+
MetadataDefinitions[el][field] === true
|
|
320
321
|
) {
|
|
321
322
|
// complex types like assets are saved as array but to ease upgradability we
|
|
322
323
|
// save the main type only unless the user deviates from our pre-selection.
|
package/lib/util/validations.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Util } from './util.js';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @typedef {import('../../types/mcdev.d.js').validationRuleList} validationRuleList
|
|
7
|
+
* @typedef {import('../../types/mcdev.d.js').validationRuleFix} validationRuleFix
|
|
7
8
|
* @typedef {import('../../types/mcdev.d.js').validationRuleTest} validationRuleTest
|
|
8
9
|
* @typedef {import('../../types/mcdev.d.js').CodeExtract} CodeExtract
|
|
9
10
|
*/
|
|
@@ -40,7 +41,7 @@ async function loadCustomRules() {
|
|
|
40
41
|
* @param {any} item MetadataItem
|
|
41
42
|
* @param {string} targetDir folder in which the MetadataItem is deployed from (deploy/cred/bu)
|
|
42
43
|
* @param {CodeExtract[]} [codeExtractItemArr] array of code snippets
|
|
43
|
-
* @returns {Promise.<
|
|
44
|
+
* @returns {Promise.<validationRuleList>} MetadataItem
|
|
44
45
|
*/
|
|
45
46
|
export default async function validation(definition, item, targetDir, codeExtractItemArr) {
|
|
46
47
|
try {
|
|
@@ -53,8 +54,8 @@ export default async function validation(definition, item, targetDir, codeExtrac
|
|
|
53
54
|
definition,
|
|
54
55
|
item,
|
|
55
56
|
targetDir,
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
codeExtractItemArr,
|
|
58
|
+
Util
|
|
58
59
|
)
|
|
59
60
|
: {};
|
|
60
61
|
} catch (ex) {
|
|
@@ -67,6 +68,13 @@ export default async function validation(definition, item, targetDir, codeExtrac
|
|
|
67
68
|
const defaultRules = {
|
|
68
69
|
noGuidKeys: {
|
|
69
70
|
failedMsg: 'Please update the key to a readable value. Currently still in GUID format.',
|
|
71
|
+
/**
|
|
72
|
+
* @type {validationRuleFix}
|
|
73
|
+
*/
|
|
74
|
+
fix: function () {
|
|
75
|
+
// to fix we skip the component
|
|
76
|
+
return this.passed() || null;
|
|
77
|
+
},
|
|
70
78
|
/**
|
|
71
79
|
* @type {validationRuleTest}
|
|
72
80
|
*/
|
|
@@ -83,6 +91,13 @@ export default async function validation(definition, item, targetDir, codeExtrac
|
|
|
83
91
|
},
|
|
84
92
|
noRootFolder: {
|
|
85
93
|
failedMsg: 'Root folder not allowed. Current folder: ' + item.r__folder_Path,
|
|
94
|
+
/**
|
|
95
|
+
* @type {validationRuleFix}
|
|
96
|
+
*/
|
|
97
|
+
fix: function () {
|
|
98
|
+
// to fix we skip the component
|
|
99
|
+
return this.passed() || null;
|
|
100
|
+
},
|
|
86
101
|
/**
|
|
87
102
|
* @type {validationRuleTest}
|
|
88
103
|
*/
|
|
@@ -108,6 +123,13 @@ export default async function validation(definition, item, targetDir, codeExtrac
|
|
|
108
123
|
noAmpscriptHtmlTag: {
|
|
109
124
|
failedMsg:
|
|
110
125
|
'Please use %%[]%% instead of <script runat="server" language="ampscript"></script> for AMPscript',
|
|
126
|
+
/**
|
|
127
|
+
* @type {validationRuleFix}
|
|
128
|
+
*/
|
|
129
|
+
fix: function () {
|
|
130
|
+
// to fix we skip the component
|
|
131
|
+
return this.passed() || null;
|
|
132
|
+
},
|
|
111
133
|
/**
|
|
112
134
|
* @type {validationRuleTest}
|
|
113
135
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcdev",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.8.0",
|
|
4
4
|
"description": "Accenture Salesforce Marketing Cloud DevTools",
|
|
5
5
|
"author": "Accenture: joern.berkefeld, douglas.midgley, robert.zimmermann, maciej.barnas",
|
|
6
6
|
"license": "MIT",
|
|
@@ -74,11 +74,11 @@
|
|
|
74
74
|
"console.table": "0.10.0",
|
|
75
75
|
"deep-equal": "2.2.3",
|
|
76
76
|
"fs-extra": "11.3.0",
|
|
77
|
-
"inquirer": "12.4.
|
|
77
|
+
"inquirer": "12.4.2",
|
|
78
78
|
"json-to-table": "4.2.1",
|
|
79
79
|
"mustache": "4.2.0",
|
|
80
80
|
"p-limit": "6.2.0",
|
|
81
|
-
"prettier": "3.5.
|
|
81
|
+
"prettier": "3.5.3",
|
|
82
82
|
"prettier-plugin-sql": "0.18.1",
|
|
83
83
|
"semver": "7.7.1",
|
|
84
84
|
"sfmc-sdk": "2.1.2",
|
|
@@ -90,26 +90,26 @@
|
|
|
90
90
|
"yocto-spinner": "0.2.0"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
|
-
"@eslint/js": "9.
|
|
93
|
+
"@eslint/js": "9.21.0",
|
|
94
94
|
"@types/fs-extra": "11.0.4",
|
|
95
95
|
"@types/inquirer": "9.0.7",
|
|
96
96
|
"@types/mocha": "10.0.8",
|
|
97
|
-
"@types/node": "22.13.
|
|
97
|
+
"@types/node": "22.13.9",
|
|
98
98
|
"@types/yargs": "17.0.33",
|
|
99
99
|
"assert": "2.1.0",
|
|
100
100
|
"axios-mock-adapter": "2.0.0",
|
|
101
101
|
"c8": "10.1.3",
|
|
102
|
-
"chai": "5.
|
|
102
|
+
"chai": "5.2.0",
|
|
103
103
|
"chai-files": "1.4.0",
|
|
104
|
-
"eslint": "9.
|
|
104
|
+
"eslint": "9.21.0",
|
|
105
105
|
"eslint-config-prettier": "10.0.1",
|
|
106
106
|
"eslint-config-ssjs": "2.0.0",
|
|
107
107
|
"eslint-plugin-jsdoc": "50.6.3",
|
|
108
108
|
"eslint-plugin-mocha": "10.5.0",
|
|
109
109
|
"eslint-plugin-prettier": "5.2.3",
|
|
110
110
|
"eslint-plugin-unicorn": "56.0.1",
|
|
111
|
-
"fast-xml-parser": "
|
|
112
|
-
"globals": "
|
|
111
|
+
"fast-xml-parser": "5.0.8",
|
|
112
|
+
"globals": "16.0.0",
|
|
113
113
|
"husky": "9.1.7",
|
|
114
114
|
"lint-staged": "15.4.3",
|
|
115
115
|
"mocha": "11.1.0",
|
package/test/general.test.js
CHANGED
|
@@ -2212,6 +2212,34 @@ describe('GENERAL', () => {
|
|
|
2212
2212
|
);
|
|
2213
2213
|
});
|
|
2214
2214
|
|
|
2215
|
+
it('build but error after buildTemplate step because keys were not found', async () => {
|
|
2216
|
+
const buName = 'testInstance/testBU';
|
|
2217
|
+
const typeKeyCombo = {
|
|
2218
|
+
asset: ['404'],
|
|
2219
|
+
dataExtension: ['404'],
|
|
2220
|
+
};
|
|
2221
|
+
|
|
2222
|
+
// handler.setOptions({ skipInteraction: true, purge: false, fix: true });
|
|
2223
|
+
|
|
2224
|
+
await handler.build(
|
|
2225
|
+
buName,
|
|
2226
|
+
'ignored',
|
|
2227
|
+
typeKeyCombo,
|
|
2228
|
+
['testSourceMarket'],
|
|
2229
|
+
['parent'],
|
|
2230
|
+
true
|
|
2231
|
+
);
|
|
2232
|
+
|
|
2233
|
+
// THEN
|
|
2234
|
+
assert.equal(process.exitCode, 1, 'build should not have thrown an error');
|
|
2235
|
+
|
|
2236
|
+
assert.equal(
|
|
2237
|
+
testUtils.getAPIHistoryLength(),
|
|
2238
|
+
0,
|
|
2239
|
+
'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
|
|
2240
|
+
);
|
|
2241
|
+
});
|
|
2242
|
+
|
|
2215
2243
|
it('skip build based on validation rule "filterPrefixByBu" with --fix without error', async () => {
|
|
2216
2244
|
const buName = 'testInstance/testBU';
|
|
2217
2245
|
const typeKeyCombo = {
|
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* @typedef {Object.<string, any>} MetadataTypeItem generic metadata item
|
|
4
|
+
*
|
|
5
|
+
* @typedef {object} CodeExtract
|
|
6
|
+
* @property {string[]} subFolder mostly set to null, otherwise subfolders path split into elements
|
|
7
|
+
* @property {string} fileName name of file w/o extension
|
|
8
|
+
* @property {string} fileExt file extension
|
|
9
|
+
* @property {string} content file content
|
|
10
|
+
* @property {'base64'} [encoding] optional for binary files
|
|
11
|
+
*
|
|
12
|
+
* @callback validationRuleFix
|
|
13
|
+
* @returns {boolean|null} true = test passed; false = test failed & fixed; null = test failed & item removed to fix
|
|
14
|
+
*
|
|
15
|
+
* @callback validationRuleTest
|
|
16
|
+
* @returns {boolean} true = test passed; false = test failed
|
|
17
|
+
*
|
|
18
|
+
* @typedef {object} validationRule
|
|
19
|
+
* @property {string} failedMsg error message to display in case of a failed test
|
|
20
|
+
* @property {validationRuleTest} passed test to run
|
|
21
|
+
* @property {validationRuleFix} [fix] test to run
|
|
22
|
+
*
|
|
23
|
+
* @typedef {Object.<string, validationRule>} validationRuleList key=rule name
|
|
24
|
+
*/
|
|
2
25
|
|
|
3
26
|
/** @type {Object.<string, string[]>} */
|
|
4
27
|
const buPrefixBlacklistMap = {
|
|
@@ -8,14 +31,16 @@ const buPrefixBlacklistMap = {
|
|
|
8
31
|
|
|
9
32
|
/**
|
|
10
33
|
*
|
|
11
|
-
* @param {any} definition
|
|
12
|
-
* @param {
|
|
13
|
-
* @param {string} targetDir
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {
|
|
16
|
-
* @returns {
|
|
34
|
+
* @param {any} definition type definition
|
|
35
|
+
* @param {MetadataTypeItem} item MetadataItem
|
|
36
|
+
* @param {string} targetDir folder in which the MetadataItem is deployed from (deploy/cred/bu)
|
|
37
|
+
* @param {CodeExtract[]} codeExtractItemArr array of code snippets
|
|
38
|
+
* @param {any} Util utility functions
|
|
39
|
+
* @returns {validationRuleList} MetadataItem
|
|
17
40
|
*/
|
|
18
|
-
export function validation(definition, item, targetDir,
|
|
41
|
+
export function validation(definition, item, targetDir, codeExtractItemArr, Util) {
|
|
42
|
+
Util.logger.verbose('just here to not get a warning about the unused property Util');
|
|
43
|
+
|
|
19
44
|
const bu =
|
|
20
45
|
(targetDir.includes('/') ? targetDir.split('/').pop() : targetDir.split('\\').pop()) ||
|
|
21
46
|
'not-found';
|
|
@@ -31,9 +56,12 @@ export function validation(definition, item, targetDir, Util, codeExtractItemArr
|
|
|
31
56
|
get failedMsg() {
|
|
32
57
|
return `Prefix not allowed on this BU. Blacklisted prefixes: ${prefixBlacklist.join(', ')}`;
|
|
33
58
|
},
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
/** @type {validationRuleFix} */
|
|
60
|
+
fix: function () {
|
|
61
|
+
// to fix we skip the component
|
|
62
|
+
return this.passed() || null;
|
|
63
|
+
},
|
|
64
|
+
/** @type {validationRuleTest} */
|
|
37
65
|
passed: function () {
|
|
38
66
|
// this rule aims to prevent deploying things that dont belong on a BU
|
|
39
67
|
if (prefixBlacklist.length === 0) {
|
|
@@ -47,7 +75,7 @@ export function validation(definition, item, targetDir, Util, codeExtractItemArr
|
|
|
47
75
|
('' + item[definition.keyField]).startsWith(prefix)
|
|
48
76
|
) {
|
|
49
77
|
// return false to issue an error or null to skip the item entirely (which is the "fix" of this rule)
|
|
50
|
-
return
|
|
78
|
+
return false;
|
|
51
79
|
}
|
|
52
80
|
// some components have unreadable keys and hence only have the brand prefix in the name
|
|
53
81
|
if (
|
|
@@ -55,7 +83,7 @@ export function validation(definition, item, targetDir, Util, codeExtractItemArr
|
|
|
55
83
|
('' + item[definition.nameField]).startsWith(prefix)
|
|
56
84
|
) {
|
|
57
85
|
// return false to issue an error or null to skip the item entirely (which is the "fix" of this rule)
|
|
58
|
-
return
|
|
86
|
+
return false;
|
|
59
87
|
}
|
|
60
88
|
}
|
|
61
89
|
// not found
|
|
@@ -153,7 +153,29 @@
|
|
|
153
153
|
"transactionalSMS",
|
|
154
154
|
"triggeredSend",
|
|
155
155
|
"verification"
|
|
156
|
+
],
|
|
157
|
+
"createDeltaPkg": [
|
|
158
|
+
"asset",
|
|
159
|
+
"automation",
|
|
160
|
+
"dataExtension",
|
|
161
|
+
"dataExtract",
|
|
162
|
+
"emailSend",
|
|
163
|
+
"event",
|
|
164
|
+
"fileLocation",
|
|
165
|
+
"fileTransfer",
|
|
166
|
+
"importFile",
|
|
167
|
+
"journey",
|
|
168
|
+
"mobileCode",
|
|
169
|
+
"mobileKeyword",
|
|
170
|
+
"mobileMessage",
|
|
171
|
+
"query",
|
|
172
|
+
"script",
|
|
173
|
+
"sendClassification",
|
|
174
|
+
"senderProfile",
|
|
175
|
+
"transactionalPush",
|
|
176
|
+
"transactionalSMS",
|
|
177
|
+
"verification"
|
|
156
178
|
]
|
|
157
179
|
},
|
|
158
|
-
"version": "7.
|
|
180
|
+
"version": "7.8.0"
|
|
159
181
|
}
|
package/test/utils.js
CHANGED
|
@@ -192,44 +192,16 @@ export function mockSetup(isDeploy) {
|
|
|
192
192
|
// no need to execute this again if we ran it a 2nd time for deploy - already done in standard setup
|
|
193
193
|
if (!isDeploy) {
|
|
194
194
|
// reset all options to default
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
dependencies: undefined,
|
|
206
|
-
errorLog: undefined,
|
|
207
|
-
execute: undefined,
|
|
208
|
-
filter: undefined,
|
|
209
|
-
fix: undefined,
|
|
210
|
-
fixShared: undefined,
|
|
211
|
-
fromRetrieve: undefined,
|
|
212
|
-
json: undefined,
|
|
213
|
-
keySuffix: undefined,
|
|
214
|
-
like: undefined,
|
|
215
|
-
matchName: undefined,
|
|
216
|
-
noUpdate: undefined,
|
|
217
|
-
publish: undefined,
|
|
218
|
-
purge: undefined,
|
|
219
|
-
range: undefined,
|
|
220
|
-
referenceFrom: undefined,
|
|
221
|
-
referenceTo: undefined,
|
|
222
|
-
refresh: undefined,
|
|
223
|
-
retrieve: undefined,
|
|
224
|
-
schedule: undefined,
|
|
225
|
-
skipDeploy: undefined,
|
|
226
|
-
skipInteraction: undefined,
|
|
227
|
-
skipRetrieve: undefined,
|
|
228
|
-
skipStatusCheck: undefined,
|
|
229
|
-
skipValidation: undefined,
|
|
230
|
-
_runningTest: undefined,
|
|
231
|
-
_welcomeMessageShown: undefined,
|
|
232
|
-
});
|
|
195
|
+
const resetOptions = {};
|
|
196
|
+
// get known options and make sure none are set
|
|
197
|
+
for (const option in handler.knownOptions) {
|
|
198
|
+
resetOptions[option] = undefined;
|
|
199
|
+
}
|
|
200
|
+
// test config
|
|
201
|
+
resetOptions.debug = true;
|
|
202
|
+
resetOptions.noLogFile = true;
|
|
203
|
+
|
|
204
|
+
handler.setOptions(resetOptions);
|
|
233
205
|
}
|
|
234
206
|
apimock = new MockAdapter(axiosInstance, { onNoMatch: 'throwException' });
|
|
235
207
|
// set access_token to mid to allow for autorouting of mock to correct resources
|
package/types/mcdev.d.js
CHANGED
|
@@ -463,6 +463,7 @@ complex
|
|
|
463
463
|
* @property {object} marketList combination of markets and BUs for streamlined deployments
|
|
464
464
|
* @property {object} metaDataTypes templating variables grouped by markets
|
|
465
465
|
* @property {string[]} metaDataTypes.retrieve define what types shall be downloaded by default during retrieve
|
|
466
|
+
* @property {string[]} metaDataTypes.createDeltaPkg defines what types shall be passed to build() as part of running cdp
|
|
466
467
|
* @property {string[]} metaDataTypes.documentOnRetrieve which types should be parsed & documented after retrieve
|
|
467
468
|
* @property {string} version mcdev version that last updated the config file
|
|
468
469
|
*/
|
|
@@ -628,16 +629,18 @@ complex
|
|
|
628
629
|
* @property {string} text seems to be equal to name-attribute?; "Email"
|
|
629
630
|
*/
|
|
630
631
|
/**
|
|
632
|
+
*
|
|
633
|
+
* @callback validationRuleFix
|
|
634
|
+
* @returns {boolean|null} true = test passed; false = test failed & fixed; null = test failed & item removed to fix
|
|
631
635
|
*
|
|
632
636
|
* @callback validationRuleTest
|
|
633
637
|
* @returns {boolean} true = test passed; false = test failed
|
|
634
|
-
|
|
635
|
-
/**
|
|
638
|
+
*
|
|
636
639
|
* @typedef {object} validationRule
|
|
637
640
|
* @property {string} failedMsg error message to display in case of a failed test
|
|
638
641
|
* @property {validationRuleTest} passed test to run
|
|
639
|
-
|
|
640
|
-
|
|
642
|
+
* @property {validationRuleFix} [fix] test to run
|
|
643
|
+
*
|
|
641
644
|
* @typedef {Object.<string, validationRule>} validationRuleList key=rule name
|
|
642
645
|
*/
|
|
643
646
|
|