mcdev 7.6.3 → 7.7.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.
- package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
- package/.github/ISSUE_TEMPLATE/task.md +1 -1
- package/.github/workflows/coverage-base-update.yml +2 -2
- package/.github/workflows/coverage-develop-branch.yml +3 -1
- package/.github/workflows/coverage-main-branch.yml +3 -1
- package/.github/workflows/coverage.yml +5 -3
- package/.mcdev-validations.js +0 -0
- package/@types/lib/Builder.d.ts +14 -0
- package/@types/lib/Builder.d.ts.map +1 -1
- package/@types/lib/MetadataTypeDefinitions.d.ts +2 -0
- package/@types/lib/MetadataTypeDefinitions.d.ts.map +1 -1
- package/@types/lib/MetadataTypeInfo.d.ts +2 -0
- package/@types/lib/MetadataTypeInfo.d.ts.map +1 -1
- package/@types/lib/index.d.ts +17 -8
- package/@types/lib/index.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Asset.d.ts +11 -3
- package/@types/lib/metadataTypes/Asset.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DomainVerification.d.ts +180 -0
- package/@types/lib/metadataTypes/DomainVerification.d.ts.map +1 -0
- package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Journey.d.ts +7 -4
- package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MetadataType.d.ts +15 -7
- package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MobileKeyword.d.ts +2 -10
- package/@types/lib/metadataTypes/MobileKeyword.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MobileMessage.d.ts +2 -10
- package/@types/lib/metadataTypes/MobileMessage.d.ts.map +1 -1
- package/@types/lib/metadataTypes/SendClassification.d.ts.map +1 -1
- package/@types/lib/metadataTypes/SenderProfile.d.ts +7 -0
- package/@types/lib/metadataTypes/SenderProfile.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TransactionalEmail.d.ts +2 -2
- package/@types/lib/metadataTypes/TransactionalEmail.d.ts.map +1 -1
- package/@types/lib/metadataTypes/TriggeredSend.d.ts +8 -0
- package/@types/lib/metadataTypes/TriggeredSend.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Verification.d.ts +0 -9
- package/@types/lib/metadataTypes/Verification.d.ts.map +1 -1
- package/@types/lib/metadataTypes/definitions/DomainVerification.definition.d.ts +100 -0
- package/@types/lib/metadataTypes/definitions/DomainVerification.definition.d.ts.map +1 -0
- package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +1 -1
- package/@types/lib/util/devops.d.ts.map +1 -1
- package/@types/lib/util/replaceContentBlockReference.d.ts +2 -1
- package/@types/lib/util/replaceContentBlockReference.d.ts.map +1 -1
- package/@types/lib/util/util.d.ts +42 -1
- package/@types/lib/util/util.d.ts.map +1 -1
- package/@types/lib/util/validations.d.ts.map +1 -1
- package/@types/types/mcdev.d.d.ts +34 -0
- package/@types/types/mcdev.d.d.ts.map +1 -1
- package/boilerplate/config.json +11 -0
- package/boilerplate/files/eslint.config.js +98 -3
- package/boilerplate/forcedUpdates.json +4 -0
- package/boilerplate/gitignore-template +1 -1
- package/boilerplate/npm-dependencies.json +1 -0
- package/eslint.config.js +4 -3
- package/lib/Builder.js +114 -54
- package/lib/Deployer.js +2 -2
- package/lib/MetadataTypeDefinitions.js +2 -0
- package/lib/MetadataTypeInfo.js +2 -0
- package/lib/cli.js +127 -3
- package/lib/index.js +217 -164
- package/lib/metadataTypes/Asset.js +76 -22
- package/lib/metadataTypes/DataExtension.js +10 -2
- package/lib/metadataTypes/DomainVerification.js +246 -0
- package/lib/metadataTypes/Event.js +21 -9
- package/lib/metadataTypes/Journey.js +339 -223
- package/lib/metadataTypes/MetadataType.js +153 -106
- package/lib/metadataTypes/MobileKeyword.js +5 -2
- package/lib/metadataTypes/MobileMessage.js +5 -2
- package/lib/metadataTypes/SendClassification.js +5 -0
- package/lib/metadataTypes/SenderProfile.js +102 -3
- package/lib/metadataTypes/TransactionalEmail.js +3 -1
- package/lib/metadataTypes/Verification.js +3 -1
- package/lib/metadataTypes/definitions/DomainVerification.definition.js +71 -0
- package/lib/metadataTypes/definitions/Journey.definition.js +7 -1
- package/lib/metadataTypes/definitions/SendClassification.definition.js +2 -2
- package/lib/metadataTypes/definitions/SenderProfile.definition.js +1 -1
- package/lib/util/config.js +6 -0
- package/lib/util/devops.js +130 -154
- package/lib/util/file.js +3 -3
- package/lib/util/replaceContentBlockReference.js +10 -3
- package/lib/util/util.js +96 -14
- package/lib/util/validations.js +34 -14
- package/package.json +10 -10
- package/test/general.test.js +339 -96
- package/test/mockRoot/.mcdev-validations.js +66 -0
- package/test/mockRoot/.mcdevrc.json +30 -2
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_htmlblock.asset-block-meta.html +1 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_htmlblock.asset-block-meta.json +39 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_withCBBK_notexisting.asset-block-meta.html +4 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_withCBBK_notexisting.asset-block-meta.json +39 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_withCBBK_preexisting.asset-block-meta.html +4 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/testNew_asset_withCBBK_preexisting.asset-block-meta.json +39 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/message/testNew_assetMessage/testNew_assetMessage.asset-message-meta.json +435 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/message/testNew_assetMessage/views.html.content.asset-message-meta.html +150 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/message/testNew_asset_templatebasedemail/testNew_asset_templatebasedemail.asset-message-meta.json +305 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/message/testNew_asset_templatebasedemail/views.html.content.asset-message-meta.html +150 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/template/testNew_asset_template/content.asset-template-meta.html +150 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/template/testNew_asset_template/testNew_asset_template.asset-template-meta.json +116 -0
- package/test/mockRoot/deploy/testInstance/testBU/domainVerification/joern.berkefeld.New@accenture.com.domainVerification-meta.json +6 -0
- package/test/mockRoot/deploy/testInstance/testBU/domainVerification/joern.berkefeld@accenture.com.domainVerification-meta.json +6 -0
- package/test/mockRoot/deploy/testInstance/testBU/domainVerification/mcdev.accenture.com.domainVerification-meta.json +6 -0
- package/test/mockRoot/deploy/testInstance/testBU/journey/testNew_temail_notPublished.journey-meta.json +213 -0
- package/test/mockRoot/deploy/testInstance/testBU/senderProfile/testExisting_senderProfile.senderProfile-meta.json +1 -0
- package/test/mockRoot/deploy/testInstance/testBU/senderProfile/testNew_senderProfile.senderProfile-meta.json +1 -0
- package/test/resourceFactory.js +7 -24
- package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_assetMessage.json +441 -0
- package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_htmlblock.json +59 -0
- package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_template.json +147 -0
- package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_templatebasedemail.json +322 -0
- package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_withCBBK_notexisting.json +59 -0
- package/test/resources/9999999/asset/v1/content/assets/post-response-key=testNew_asset_withCBBK_preexisting.json +59 -0
- package/test/resources/9999999/asset-deploy2/block/testBlacklist_asset_htmlblock.asset-block-meta.html +1 -0
- package/test/resources/9999999/asset-deploy2/block/testBlacklist_asset_htmlblock.asset-block-meta.json +39 -0
- package/test/resources/9999999/automation/clone-expected.json +61 -0
- package/test/resources/9999999/dataExtension/retrieve-CustomerKey=testExisting_dataExtension-response.xml +52 -0
- package/test/resources/9999999/dataExtension-deploy/testBlacklist_dataExtension.dataExtension-meta.json +20 -0
- package/test/resources/9999999/dataFolder/retrieve-ContentTypeINasset,asset-shared,dataextension,hidden,salesforcedataextension,shared_data,shared_dataextension,shared_salesforcedataextension,synchronizeddataextension-response.xml +137 -0
- package/test/resources/9999999/domainVerification/create-expected.json +3 -0
- package/test/resources/9999999/domainVerification/get-sap-expected.json +6 -0
- package/test/resources/9999999/domainVerification/update-expected.json +6 -0
- package/test/resources/9999999/interaction/v1/interactions/key_testExisting_temail/put-response-paused.json +219 -0
- package/test/resources/9999999/interaction/v1/interactions/key_testNew_temail_notPublished/get-response.json +218 -0
- package/test/resources/9999999/interaction/v1/interactions/post-response.json +216 -0
- package/test/resources/9999999/journey/create-transactionaEmail-publish-expected.json +217 -0
- package/test/resources/9999999/messaging/v1/domainverification/delete/post-response.txt +1 -0
- package/test/resources/9999999/messaging/v1/domainverification/get-response.json +43 -0
- package/test/resources/9999999/messaging/v1/domainverification/post-response.txt +1 -0
- package/test/resources/9999999/messaging/v1/domainverification/update/post-response.txt +1 -0
- package/test/resources/9999999/messaging/v1/email/definitions/get-response.json +7 -0
- package/test/resources/9999999/messaging/v1/email/definitions/testNew_temail_notPublished/get-response.json +26 -0
- package/test/resources/9999999/query/clone-expected.json +8 -0
- package/test/resources/9999999/query/clone-expected.sql +7 -0
- package/test/resources/9999999/senderProfile/create-response.xml +1 -1
- package/test/resources/9999999/senderProfile/post-expected.json +1 -1
- package/test/resources/9999999/transactionalEmail/create-publish-expected.json +20 -0
- package/test/type.asset.test.js +216 -9
- package/test/type.automation.test.js +1 -1
- package/test/type.domainVerification.test.js +169 -0
- package/test/type.journey.test.js +107 -21
- package/test/type.script.test.js +1 -1
- package/test/type.sendClassification.test.js +3 -3
- package/test/type.senderProfile.test.js +26 -6
- package/test/type.transactionalEmail.test.js +5 -5
- package/test/type.triggeredSend.test.js +1 -1
- package/test/utils.js +8 -0
- package/types/mcdev.d.js +12 -0
|
@@ -142,8 +142,8 @@ class MetadataType {
|
|
|
142
142
|
* Deploys metadata
|
|
143
143
|
*
|
|
144
144
|
* @param {MetadataTypeMap} metadataMap metadata mapped by their keyField
|
|
145
|
-
* @param {string} deployDir directory where deploy metadata are saved
|
|
146
|
-
* @param {string} retrieveDir directory where metadata after deploy should be saved
|
|
145
|
+
* @param {string} deployDir directory where deploy metadata are saved, ending on cred/bu
|
|
146
|
+
* @param {string} retrieveDir directory where metadata after deploy should be saved, ending on cred/bu
|
|
147
147
|
* @returns {Promise.<MetadataTypeMap>} Promise of keyField => metadata map
|
|
148
148
|
*/
|
|
149
149
|
static async deploy(metadataMap, deployDir, retrieveDir) {
|
|
@@ -173,24 +173,36 @@ class MetadataType {
|
|
|
173
173
|
*/
|
|
174
174
|
static async postDeployTasks(upsertResults, originalMetadata, createdUpdated) {}
|
|
175
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Gets executed before deleting a list of keys for the current type
|
|
178
|
+
*
|
|
179
|
+
* @param {string} keyArr metadata keys
|
|
180
|
+
* @returns {Promise.<void>} -
|
|
181
|
+
*/
|
|
182
|
+
static async preDeleteTasks(keyArr) {}
|
|
183
|
+
|
|
176
184
|
/**
|
|
177
185
|
* helper for {@link MetadataType.createREST}
|
|
178
186
|
*
|
|
179
187
|
* @param {MetadataTypeItem} metadataEntry a single metadata Entry
|
|
180
188
|
* @param {object} apiResponse varies depending on the API call
|
|
181
189
|
* @param {MetadataTypeItem} metadataEntryWithAllFields like metadataEntry but before non-creatable fields were stripped
|
|
182
|
-
* @returns {
|
|
190
|
+
* @returns {Promise.<object>} apiResponse, potentially modified
|
|
183
191
|
*/
|
|
184
|
-
static postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) {
|
|
192
|
+
static async postCreateTasks(metadataEntry, apiResponse, metadataEntryWithAllFields) {
|
|
193
|
+
return apiResponse;
|
|
194
|
+
}
|
|
185
195
|
|
|
186
196
|
/**
|
|
187
197
|
* helper for {@link MetadataType.updateREST}
|
|
188
198
|
*
|
|
189
199
|
* @param {MetadataTypeItem} metadataEntry a single metadata Entry
|
|
190
200
|
* @param {object} apiResponse varies depending on the API call
|
|
191
|
-
* @returns {
|
|
201
|
+
* @returns {Promise.<object>} apiResponse, potentially modified
|
|
192
202
|
*/
|
|
193
|
-
static postUpdateTasks(metadataEntry, apiResponse) {
|
|
203
|
+
static postUpdateTasks(metadataEntry, apiResponse) {
|
|
204
|
+
return apiResponse;
|
|
205
|
+
}
|
|
194
206
|
|
|
195
207
|
/**
|
|
196
208
|
* helper for {@link MetadataType.createREST} when legacy API endpoints as these do not return the created item but only their new id
|
|
@@ -252,9 +264,8 @@ class MetadataType {
|
|
|
252
264
|
delete metadata[this.definition.folderIdField];
|
|
253
265
|
} catch (ex) {
|
|
254
266
|
Util.logger.warn(
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}): Could not find folder (${ex.message})`
|
|
267
|
+
Util.getMsgPrefix(this.definition, metadata) +
|
|
268
|
+
`: Could not find folder (${ex.message})`
|
|
258
269
|
);
|
|
259
270
|
}
|
|
260
271
|
}
|
|
@@ -437,7 +448,7 @@ class MetadataType {
|
|
|
437
448
|
// write to file
|
|
438
449
|
await File.writeJSONToFile([templateDir, ...typeDirArr], fileName, metadata);
|
|
439
450
|
Util.logger.info(
|
|
440
|
-
|
|
451
|
+
` - templated ${this.definition.type}: ${key} (${
|
|
441
452
|
metadata[this.definition.nameField]
|
|
442
453
|
})`
|
|
443
454
|
);
|
|
@@ -495,9 +506,7 @@ class MetadataType {
|
|
|
495
506
|
*/
|
|
496
507
|
static async create(metadata, deployDir) {
|
|
497
508
|
Util.logger.error(
|
|
498
|
-
` ☇ skipping ${this.definition
|
|
499
|
-
metadata[this.definition.nameField]
|
|
500
|
-
}: create is not supported yet for ${this.definition.type}`
|
|
509
|
+
` ☇ skipping ${Util.getTypeKeyName(this.definition, metadata)}: create is not supported yet for ${this.definition.type}`
|
|
501
510
|
);
|
|
502
511
|
return;
|
|
503
512
|
}
|
|
@@ -511,9 +520,7 @@ class MetadataType {
|
|
|
511
520
|
*/
|
|
512
521
|
static async update(metadata, metadataBefore) {
|
|
513
522
|
Util.logger.error(
|
|
514
|
-
` ☇ skipping ${this.definition
|
|
515
|
-
metadata[this.definition.nameField]
|
|
516
|
-
}: update is not supported yet for ${this.definition.type}`
|
|
523
|
+
` ☇ skipping ${Util.getTypeKeyName(this.definition, metadata)}: update is not supported yet for ${this.definition.type}`
|
|
517
524
|
);
|
|
518
525
|
return;
|
|
519
526
|
}
|
|
@@ -523,9 +530,10 @@ class MetadataType {
|
|
|
523
530
|
*
|
|
524
531
|
* @param {string[]} [keyArr] metadata keys
|
|
525
532
|
* @param {boolean} [checkKey] whether to check if the key is valid
|
|
533
|
+
* @param {MetadataTypeMap} [upsertResults] metadata mapped by their keyField as returned by update/create; needs to be refreshed after publish
|
|
526
534
|
* @returns {Promise.<string[]>} Returns list of keys that were refreshed
|
|
527
535
|
*/
|
|
528
|
-
static async refresh(keyArr, checkKey = true) {
|
|
536
|
+
static async refresh(keyArr, checkKey = true, upsertResults) {
|
|
529
537
|
Util.logger.error(
|
|
530
538
|
` ☇ skipping ${this.definition.type}: refresh is not supported yet for ${this.definition.type}`
|
|
531
539
|
);
|
|
@@ -610,9 +618,7 @@ class MetadataType {
|
|
|
610
618
|
if (!findAssetKeys) {
|
|
611
619
|
Util.logger.info(
|
|
612
620
|
Util.getGrayMsg(
|
|
613
|
-
` ☇ skipping ${this.definition
|
|
614
|
-
item[this.definition.keyField]
|
|
615
|
-
}: no ${fromDescription} found`
|
|
621
|
+
` ☇ skipping ${Util.getTypeKeyName(this.definition, item)}: no ${fromDescription} found`
|
|
616
622
|
)
|
|
617
623
|
);
|
|
618
624
|
}
|
|
@@ -774,24 +780,38 @@ class MetadataType {
|
|
|
774
780
|
// preDeployTasks parsing
|
|
775
781
|
let deployableMetadata;
|
|
776
782
|
try {
|
|
777
|
-
await this.validation(
|
|
778
|
-
|
|
783
|
+
metadataMap[metadataKey] = await this.validation(
|
|
784
|
+
'deploy',
|
|
779
785
|
metadataMap[metadataKey],
|
|
780
786
|
deployDir
|
|
781
787
|
);
|
|
788
|
+
if (metadataMap[metadataKey]) {
|
|
789
|
+
// only run unless we encountered a situation in our validation that made us want to filter this record
|
|
790
|
+
deployableMetadata = await this.preDeployTasks(
|
|
791
|
+
metadataMap[metadataKey],
|
|
792
|
+
deployDir
|
|
793
|
+
);
|
|
794
|
+
}
|
|
782
795
|
} catch (ex) {
|
|
783
796
|
// do this in case something went wrong during pre-deploy steps to ensure the total counter is correct
|
|
784
797
|
hasError = true;
|
|
785
798
|
deployableMetadata = metadataMap[metadataKey];
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
799
|
+
if (deployableMetadata) {
|
|
800
|
+
// * include ": ${ex.message}" in the error if this is ever turned back into Util.logger.error()
|
|
801
|
+
Util.logger.errorStack(
|
|
802
|
+
ex,
|
|
803
|
+
` ☇ skipping ${this.definition.type} ${
|
|
804
|
+
deployableMetadata[this.definition.keyField]
|
|
805
|
+
} / ${deployableMetadata[this.definition.nameField]}`
|
|
806
|
+
);
|
|
807
|
+
} else {
|
|
808
|
+
Util.logger.errorStack(
|
|
809
|
+
ex,
|
|
810
|
+
` ☇ skipping ${this.definition.type} ${metadataKey}`
|
|
811
|
+
);
|
|
812
|
+
}
|
|
794
813
|
}
|
|
814
|
+
|
|
795
815
|
// if preDeploy returns nothing then it cannot be deployed so skip deployment
|
|
796
816
|
if (deployableMetadata) {
|
|
797
817
|
metadataMap[metadataKey] = deployableMetadata;
|
|
@@ -809,8 +829,14 @@ class MetadataType {
|
|
|
809
829
|
const result = await this.create(metadataMap[metadataKey], deployDir);
|
|
810
830
|
if (result) {
|
|
811
831
|
createResults.push(result);
|
|
832
|
+
if (result[this.definition.idField]) {
|
|
833
|
+
// ensure we have the ID in the cache
|
|
834
|
+
metadataMap[metadataKey][this.definition.idField] =
|
|
835
|
+
result[this.definition.idField];
|
|
836
|
+
}
|
|
812
837
|
|
|
813
838
|
// make this newly created item available in cache for other itmes that might reference it
|
|
839
|
+
/** @type {MetadataTypeMap} */
|
|
814
840
|
const newObject = {};
|
|
815
841
|
newObject[metadataKey] = metadataMap[metadataKey];
|
|
816
842
|
cache.mergeMetadata(this.definition.type, newObject);
|
|
@@ -1174,24 +1200,18 @@ class MetadataType {
|
|
|
1174
1200
|
this.removeNotCreateableFields(metadataEntry);
|
|
1175
1201
|
try {
|
|
1176
1202
|
// set to empty object in case API returned nothing to be able to update it in helper classes
|
|
1177
|
-
|
|
1178
|
-
await this.postCreateTasks(metadataEntry, response, metadataClone);
|
|
1203
|
+
let response = (await this.client.rest.post(uri, metadataEntry)) || {};
|
|
1204
|
+
response = await this.postCreateTasks(metadataEntry, response, metadataClone);
|
|
1179
1205
|
if (!handleOutside) {
|
|
1180
1206
|
Util.logger.info(
|
|
1181
|
-
` - created ${this.definition
|
|
1182
|
-
metadataEntry[this.definition.keyField] ||
|
|
1183
|
-
metadataEntry[this.definition.nameField]
|
|
1184
|
-
} / ${metadataEntry[this.definition.nameField]}`
|
|
1207
|
+
` - created ${Util.getTypeKeyName(this.definition, metadataEntry)}`
|
|
1185
1208
|
);
|
|
1186
1209
|
}
|
|
1187
1210
|
return response;
|
|
1188
1211
|
} catch (ex) {
|
|
1189
1212
|
const parsedErrors = this.getErrorsREST(ex);
|
|
1190
1213
|
Util.logger.error(
|
|
1191
|
-
` ☇ error creating ${this.definition
|
|
1192
|
-
metadataEntry[this.definition.keyField] ||
|
|
1193
|
-
metadataEntry[this.definition.nameField]
|
|
1194
|
-
} / ${metadataEntry[this.definition.nameField]}:`
|
|
1214
|
+
` ☇ error creating ${Util.getTypeKeyName(this.definition, metadataEntry)}:`
|
|
1195
1215
|
);
|
|
1196
1216
|
if (parsedErrors.length) {
|
|
1197
1217
|
for (const msg of parsedErrors) {
|
|
@@ -1223,9 +1243,7 @@ class MetadataType {
|
|
|
1223
1243
|
|
|
1224
1244
|
if (!handleOutside) {
|
|
1225
1245
|
Util.logger.info(
|
|
1226
|
-
` - created ${this.definition
|
|
1227
|
-
metadataEntry[this.definition.keyField]
|
|
1228
|
-
} / ${metadataEntry[this.definition.nameField]}`
|
|
1246
|
+
` - created ${Util.getTypeKeyName(this.definition, metadataEntry)}`
|
|
1229
1247
|
);
|
|
1230
1248
|
}
|
|
1231
1249
|
return response;
|
|
@@ -1247,25 +1265,17 @@ class MetadataType {
|
|
|
1247
1265
|
this.removeNotUpdateableFields(metadataEntry);
|
|
1248
1266
|
try {
|
|
1249
1267
|
// set to empty object in case API returned nothing to be able to update it in helper classes
|
|
1250
|
-
|
|
1268
|
+
let response = (await this.client.rest[httpMethod](uri, metadataEntry)) || {};
|
|
1251
1269
|
await this._postChangeKeyTasks(metadataEntry);
|
|
1252
1270
|
this.getErrorsREST(response);
|
|
1253
|
-
await this.postUpdateTasks(metadataEntry, response);
|
|
1271
|
+
response = await this.postUpdateTasks(metadataEntry, response);
|
|
1254
1272
|
// some times, e.g. automation dont return a key in their update response and hence we need to fall back to name
|
|
1255
|
-
Util.logger.info(
|
|
1256
|
-
` - updated ${this.definition.type}: ${
|
|
1257
|
-
metadataEntry[this.definition.keyField] ||
|
|
1258
|
-
metadataEntry[this.definition.nameField]
|
|
1259
|
-
} / ${metadataEntry[this.definition.nameField]}`
|
|
1260
|
-
);
|
|
1273
|
+
Util.logger.info(` - updated ${Util.getTypeKeyName(this.definition, metadataEntry)}`);
|
|
1261
1274
|
return response;
|
|
1262
1275
|
} catch (ex) {
|
|
1263
1276
|
const parsedErrors = this.getErrorsREST(ex);
|
|
1264
1277
|
Util.logger.error(
|
|
1265
|
-
` ☇ error updating ${this.definition
|
|
1266
|
-
metadataEntry[this.definition.keyField] ||
|
|
1267
|
-
metadataEntry[this.definition.nameField]
|
|
1268
|
-
} / ${metadataEntry[this.definition.nameField]}:`
|
|
1278
|
+
` ☇ error updating ${Util.getTypeKeyName(this.definition, metadataEntry)}:`
|
|
1269
1279
|
);
|
|
1270
1280
|
for (const msg of parsedErrors) {
|
|
1271
1281
|
Util.logger.error(' • ' + msg);
|
|
@@ -1326,9 +1336,7 @@ class MetadataType {
|
|
|
1326
1336
|
);
|
|
1327
1337
|
if (!handleOutside) {
|
|
1328
1338
|
Util.logger.info(
|
|
1329
|
-
` - updated ${this.definition
|
|
1330
|
-
metadataEntry[this.definition.keyField]
|
|
1331
|
-
} / ${metadataEntry[this.definition.nameField]}`
|
|
1339
|
+
` - updated ${Util.getTypeKeyName(this.definition, metadataEntry)}`
|
|
1332
1340
|
);
|
|
1333
1341
|
}
|
|
1334
1342
|
await this._postChangeKeyTasks(metadataEntry);
|
|
@@ -1559,9 +1567,7 @@ class MetadataType {
|
|
|
1559
1567
|
);
|
|
1560
1568
|
if (response?.OverallStatus === 'OK') {
|
|
1561
1569
|
Util.logger.info(
|
|
1562
|
-
` - executed ${this.definition
|
|
1563
|
-
metadataEntry[this.definition.keyField]
|
|
1564
|
-
}`
|
|
1570
|
+
` - executed ${Util.getTypeKeyName(this.definition, metadataEntry)}`
|
|
1565
1571
|
);
|
|
1566
1572
|
} else {
|
|
1567
1573
|
throw new Error(response?.OverallStatus);
|
|
@@ -1799,9 +1805,7 @@ class MetadataType {
|
|
|
1799
1805
|
);
|
|
1800
1806
|
if (includeByDefinition === false || includeByConfig === false) {
|
|
1801
1807
|
Util.logger.debug(
|
|
1802
|
-
`Filtered ${this.definition
|
|
1803
|
-
metadataEntry[this.definition.nameField]
|
|
1804
|
-
}' (${metadataEntry[this.definition.keyField]}): not matching include filter`
|
|
1808
|
+
`Filtered ${Util.getTypeKeyName(this.definition, metadataEntry)}: not matching include filter`
|
|
1805
1809
|
);
|
|
1806
1810
|
|
|
1807
1811
|
return true;
|
|
@@ -1815,9 +1819,7 @@ class MetadataType {
|
|
|
1815
1819
|
);
|
|
1816
1820
|
if (excludeByDefinition || excludeByConfig) {
|
|
1817
1821
|
Util.logger.debug(
|
|
1818
|
-
`Filtered ${this.definition
|
|
1819
|
-
metadataEntry[this.definition.nameField]
|
|
1820
|
-
}' (${metadataEntry[this.definition.keyField]}): matching exclude filter`
|
|
1822
|
+
`Filtered ${Util.getTypeKeyName(this.definition, metadataEntry)}: matching exclude filter`
|
|
1821
1823
|
);
|
|
1822
1824
|
return true;
|
|
1823
1825
|
}
|
|
@@ -1846,11 +1848,10 @@ class MetadataType {
|
|
|
1846
1848
|
// r__folder_Path found
|
|
1847
1849
|
|
|
1848
1850
|
if (include) {
|
|
1849
|
-
const errorMsg = `Filtered ${
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
}): not matching include filter for folder`;
|
|
1851
|
+
const errorMsg = `Filtered ${Util.getTypeKeyName(
|
|
1852
|
+
this.definition,
|
|
1853
|
+
metadataEntry
|
|
1854
|
+
)}: not matching include filter for folder`;
|
|
1854
1855
|
// check include-only filters (== discard rest)
|
|
1855
1856
|
const includeByDefinition = this._filterFolder(
|
|
1856
1857
|
this.definition.include,
|
|
@@ -1870,9 +1871,7 @@ class MetadataType {
|
|
|
1870
1871
|
return true;
|
|
1871
1872
|
}
|
|
1872
1873
|
} else {
|
|
1873
|
-
const errorMsg = `Filtered ${this.definition
|
|
1874
|
-
metadataEntry[this.definition.nameField]
|
|
1875
|
-
}' (${metadataEntry[this.definition.keyField]}): matching exclude filter for folder`;
|
|
1874
|
+
const errorMsg = `Filtered ${Util.getTypeKeyName(this.definition, metadataEntry)}: matching exclude filter for folder`;
|
|
1876
1875
|
// check exclude-only filters (== keep rest)
|
|
1877
1876
|
const excludeByDefinition = this._filterFolder(
|
|
1878
1877
|
this.definition.filter,
|
|
@@ -2017,8 +2016,17 @@ class MetadataType {
|
|
|
2017
2016
|
filterCounter++;
|
|
2018
2017
|
continue;
|
|
2019
2018
|
}
|
|
2020
|
-
await this.validation(
|
|
2021
|
-
|
|
2019
|
+
results[originalKey] = await this.validation(
|
|
2020
|
+
'retrieve',
|
|
2021
|
+
results[originalKey],
|
|
2022
|
+
retrieveDir
|
|
2023
|
+
);
|
|
2024
|
+
if (!results[originalKey]) {
|
|
2025
|
+
// we encountered a situation in our validation that made us want to filter this record
|
|
2026
|
+
delete results[originalKey];
|
|
2027
|
+
filterCounter++;
|
|
2028
|
+
continue;
|
|
2029
|
+
}
|
|
2022
2030
|
savedResults[originalKey] = await this.saveToDisk(
|
|
2023
2031
|
results,
|
|
2024
2032
|
originalKey,
|
|
@@ -2321,11 +2329,16 @@ class MetadataType {
|
|
|
2321
2329
|
);
|
|
2322
2330
|
|
|
2323
2331
|
try {
|
|
2324
|
-
await this.validation(
|
|
2332
|
+
metadata = await this.validation(
|
|
2325
2333
|
'buildDefinition',
|
|
2326
2334
|
metadata,
|
|
2327
2335
|
Array.isArray(targetDir) ? targetDir[0] : targetDir
|
|
2328
2336
|
);
|
|
2337
|
+
if (!metadata) {
|
|
2338
|
+
// we encountered a situation in our validation that made us want to filter this record
|
|
2339
|
+
return;
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2329
2342
|
// write to file
|
|
2330
2343
|
const targetDirArr = Array.isArray(targetDir) ? targetDir : [targetDir];
|
|
2331
2344
|
for (const targetDir of targetDirArr) {
|
|
@@ -2336,9 +2349,10 @@ class MetadataType {
|
|
|
2336
2349
|
);
|
|
2337
2350
|
}
|
|
2338
2351
|
Util.logger.info(
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2352
|
+
` - prepared deployment definition of ${Util.getTypeKeyName(
|
|
2353
|
+
this.definition,
|
|
2354
|
+
metadata
|
|
2355
|
+
)}`
|
|
2342
2356
|
);
|
|
2343
2357
|
if (
|
|
2344
2358
|
metadata.r__folder_Path &&
|
|
@@ -2346,16 +2360,15 @@ class MetadataType {
|
|
|
2346
2360
|
metadata.r__folder_Path.startsWith('Shared Items/'))
|
|
2347
2361
|
) {
|
|
2348
2362
|
Util.logger.warn(
|
|
2349
|
-
|
|
2350
|
-
metadata
|
|
2351
|
-
} is in a shared folder: ${metadata.r__folder_Path}`
|
|
2363
|
+
Util.getMsgPrefix(this.definition, metadata) +
|
|
2364
|
+
` is in a shared folder: ${metadata.r__folder_Path}`
|
|
2352
2365
|
);
|
|
2353
2366
|
}
|
|
2354
2367
|
|
|
2355
2368
|
return { metadata: metadata, type: this.definition.type };
|
|
2356
2369
|
} catch (ex) {
|
|
2357
2370
|
Util.logger.error(
|
|
2358
|
-
` ☇ skipped ${
|
|
2371
|
+
` ☇ skipped ${Util.getTypeKeyName(this.definition, metadata)}: ${ex.message}`
|
|
2359
2372
|
);
|
|
2360
2373
|
}
|
|
2361
2374
|
}
|
|
@@ -2775,9 +2788,10 @@ class MetadataType {
|
|
|
2775
2788
|
maxKeyLength)
|
|
2776
2789
|
) {
|
|
2777
2790
|
Util.logger.warn(
|
|
2778
|
-
`Name of the item ${
|
|
2779
|
-
|
|
2780
|
-
|
|
2791
|
+
`Name of the item ${Util.getKeyName(
|
|
2792
|
+
this.definition,
|
|
2793
|
+
item
|
|
2794
|
+
)} is too long for a key${Util.OPTIONS.keySuffix.length ? ' (including the suffix ' + Util.OPTIONS.keySuffix + ')' : ''}. Consider renaming your item. Key will be equal first ${maxKeyLength} characters of the name`
|
|
2781
2795
|
);
|
|
2782
2796
|
}
|
|
2783
2797
|
const newKey = this.getNewKey(this.definition.nameField, item, maxKeyLength);
|
|
@@ -2785,16 +2799,18 @@ class MetadataType {
|
|
|
2785
2799
|
// add key but make sure to turn it into string or else numeric keys will be filtered later
|
|
2786
2800
|
keysForDeploy.push(item[this.definition.keyField] + '');
|
|
2787
2801
|
Util.logger.info(
|
|
2788
|
-
` - added ${this.definition.type} to fixKey queue: ${
|
|
2789
|
-
|
|
2790
|
-
|
|
2802
|
+
` - added ${this.definition.type} to fixKey queue: ${Util.getKeyName(
|
|
2803
|
+
this.definition,
|
|
2804
|
+
item
|
|
2805
|
+
)} >> ${newKey}`
|
|
2791
2806
|
);
|
|
2792
2807
|
} else {
|
|
2793
2808
|
Util.logger.info(
|
|
2794
2809
|
Util.getGrayMsg(
|
|
2795
|
-
` ☇ skipping ${
|
|
2796
|
-
|
|
2797
|
-
|
|
2810
|
+
` ☇ skipping ${Util.getTypeKeyName(
|
|
2811
|
+
this.definition,
|
|
2812
|
+
item
|
|
2813
|
+
)}: key does not need to be updated`
|
|
2798
2814
|
)
|
|
2799
2815
|
);
|
|
2800
2816
|
}
|
|
@@ -2841,15 +2857,17 @@ class MetadataType {
|
|
|
2841
2857
|
* Gets executed before deploying metadata
|
|
2842
2858
|
*
|
|
2843
2859
|
* @param {'retrieve'|'buildDefinition'|'deploy'} method used to select the right config
|
|
2844
|
-
* @param {MetadataTypeItem | CodeExtractItem}
|
|
2860
|
+
* @param {MetadataTypeItem | CodeExtractItem} originalItem a single metadata item
|
|
2845
2861
|
* @param {string} targetDir folder where files for deployment are stored
|
|
2846
2862
|
* @returns {Promise.<MetadataTypeItem | CodeExtractItem>} Promise of a single metadata item
|
|
2847
2863
|
*/
|
|
2848
|
-
static async validation(method,
|
|
2849
|
-
item = structuredClone(item);
|
|
2864
|
+
static async validation(method, originalItem, targetDir) {
|
|
2850
2865
|
if (!this.properties.options?.validation?.[method]) {
|
|
2851
|
-
return
|
|
2866
|
+
return originalItem;
|
|
2852
2867
|
}
|
|
2868
|
+
// if the fix parameter was set, allow validation rules to override the metadata
|
|
2869
|
+
/** @type {MetadataTypeItem | CodeExtractItem} */
|
|
2870
|
+
let item = Util.OPTIONS.fix ? originalItem : structuredClone(originalItem);
|
|
2853
2871
|
/** @type {MetadataTypeItem} */
|
|
2854
2872
|
const metadataItem = item.json && item.codeArr ? item.json : item;
|
|
2855
2873
|
const codeArr = item.codeArr || null;
|
|
@@ -2884,26 +2902,55 @@ class MetadataType {
|
|
|
2884
2902
|
|
|
2885
2903
|
// run validation rules
|
|
2886
2904
|
const warnings = [];
|
|
2905
|
+
let fixed = false;
|
|
2887
2906
|
for (const rule of Object.keys(validationRules)) {
|
|
2888
2907
|
if (
|
|
2889
2908
|
validationConfig[rule] &&
|
|
2890
2909
|
validationConfig[rule] !== 'off' &&
|
|
2891
|
-
!this.definition.skipValidation?.[rule]
|
|
2892
|
-
!(await validationRules[rule].passed())
|
|
2910
|
+
!this.definition.skipValidation?.[rule]
|
|
2893
2911
|
) {
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2912
|
+
const mode = Util.OPTIONS.fix ? 'fix' : validationConfig[rule];
|
|
2913
|
+
const passed = await validationRules[rule].passed(mode);
|
|
2914
|
+
if (mode === 'fix') {
|
|
2915
|
+
// potentially fixed really
|
|
2916
|
+
fixed = true;
|
|
2917
|
+
}
|
|
2918
|
+
if (!passed) {
|
|
2919
|
+
if (mode === 'fix') {
|
|
2920
|
+
if (passed === false) {
|
|
2921
|
+
warnings.push(validationRules[rule].failedMsg);
|
|
2922
|
+
} else if (passed === null) {
|
|
2923
|
+
// ensure this item no longer exists outside of the validation rule
|
|
2924
|
+
item = null;
|
|
2925
|
+
warnings.push(
|
|
2926
|
+
` ☇ filtered item via validation rule fix: ` +
|
|
2927
|
+
validationRules[rule].failedMsg
|
|
2928
|
+
);
|
|
2929
|
+
break;
|
|
2930
|
+
}
|
|
2931
|
+
} else if (
|
|
2932
|
+
!Util.OPTIONS.skipValidation &&
|
|
2933
|
+
validationConfig[rule] === 'error' &&
|
|
2934
|
+
passed === false
|
|
2935
|
+
) {
|
|
2936
|
+
throw new Error(validationRules[rule].failedMsg);
|
|
2937
|
+
} else if (
|
|
2938
|
+
(Util.OPTIONS.skipValidation || validationConfig[rule] === 'warn') &&
|
|
2939
|
+
passed === false
|
|
2940
|
+
) {
|
|
2941
|
+
warnings.push(validationRules[rule].failedMsg);
|
|
2942
|
+
}
|
|
2898
2943
|
}
|
|
2899
2944
|
}
|
|
2900
2945
|
}
|
|
2901
2946
|
if (warnings.length) {
|
|
2902
2947
|
Util.logger.warn(
|
|
2903
|
-
|
|
2948
|
+
Util.getMsgPrefix(this.definition, metadataItem) +
|
|
2949
|
+
`:${warnings.length > 1 ? '\n ·' : ''} ${warnings.join('\n · ')}`
|
|
2904
2950
|
);
|
|
2905
2951
|
}
|
|
2906
|
-
return item
|
|
2952
|
+
// only return "fixed" item if --fix is set, otherwise return the original item
|
|
2953
|
+
return Util.OPTIONS.fix || fixed ? item : originalItem;
|
|
2907
2954
|
}
|
|
2908
2955
|
}
|
|
2909
2956
|
|
|
@@ -481,10 +481,12 @@ class MobileKeyword extends MetadataType {
|
|
|
481
481
|
*
|
|
482
482
|
* @param {MetadataTypeItem} metadataEntry a single metadata Entry
|
|
483
483
|
* @param {object} apiResponse varies depending on the API call
|
|
484
|
-
* @returns {Promise.<
|
|
484
|
+
* @returns {Promise.<object>} apiResponse
|
|
485
485
|
*/
|
|
486
486
|
static async postCreateTasks(metadataEntry, apiResponse) {
|
|
487
487
|
await super.postDeployTasks_legacyApi(metadataEntry, apiResponse);
|
|
488
|
+
|
|
489
|
+
return apiResponse;
|
|
488
490
|
}
|
|
489
491
|
|
|
490
492
|
/**
|
|
@@ -492,10 +494,11 @@ class MobileKeyword extends MetadataType {
|
|
|
492
494
|
*
|
|
493
495
|
* @param {MetadataTypeItem} metadataEntry a single metadata Entry
|
|
494
496
|
* @param {object} apiResponse varies depending on the API call
|
|
495
|
-
* @returns {Promise.<
|
|
497
|
+
* @returns {Promise.<object>} apiResponse, potentially modified
|
|
496
498
|
*/
|
|
497
499
|
static async postUpdateTasks(metadataEntry, apiResponse) {
|
|
498
500
|
await super.postDeployTasks_legacyApi(metadataEntry, apiResponse);
|
|
501
|
+
return apiResponse;
|
|
499
502
|
}
|
|
500
503
|
|
|
501
504
|
/**
|
|
@@ -338,10 +338,12 @@ class MobileMessage extends MetadataType {
|
|
|
338
338
|
*
|
|
339
339
|
* @param {MetadataTypeItem} metadataEntry a single metadata Entry
|
|
340
340
|
* @param {object} apiResponse varies depending on the API call
|
|
341
|
-
* @returns {Promise.<
|
|
341
|
+
* @returns {Promise.<object>} apiResponse
|
|
342
342
|
*/
|
|
343
343
|
static async postCreateTasks(metadataEntry, apiResponse) {
|
|
344
344
|
await super.postDeployTasks_legacyApi(metadataEntry, apiResponse);
|
|
345
|
+
|
|
346
|
+
return apiResponse;
|
|
345
347
|
}
|
|
346
348
|
|
|
347
349
|
/**
|
|
@@ -349,10 +351,11 @@ class MobileMessage extends MetadataType {
|
|
|
349
351
|
*
|
|
350
352
|
* @param {MetadataTypeItem} metadataEntry a single metadata Entry
|
|
351
353
|
* @param {object} apiResponse varies depending on the API call
|
|
352
|
-
* @returns {Promise.<
|
|
354
|
+
* @returns {Promise.<object>} apiResponse, potentially modified
|
|
353
355
|
*/
|
|
354
356
|
static async postUpdateTasks(metadataEntry, apiResponse) {
|
|
355
357
|
await super.postDeployTasks_legacyApi(metadataEntry, apiResponse);
|
|
358
|
+
return apiResponse;
|
|
356
359
|
}
|
|
357
360
|
|
|
358
361
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
import MetadataType from './MetadataType.js';
|
|
4
|
+
import SenderProfile from './SenderProfile.js';
|
|
4
5
|
import { Util } from '../util/util.js';
|
|
5
6
|
import cache from '../util/cache.js';
|
|
6
7
|
|
|
@@ -110,6 +111,8 @@ class SendClassification extends MetadataType {
|
|
|
110
111
|
'CustomerKey',
|
|
111
112
|
'ObjectID'
|
|
112
113
|
);
|
|
114
|
+
const sp = cache.getByKey('senderProfile', metadata.r__senderProfile_key);
|
|
115
|
+
SenderProfile.verifySenderEmailAddresses(sp, metadata, this.definition);
|
|
113
116
|
metadata.SenderProfile = {
|
|
114
117
|
ObjectID: spId,
|
|
115
118
|
CustomerKey: metadata.r__senderProfile_key,
|
|
@@ -173,6 +176,8 @@ class SendClassification extends MetadataType {
|
|
|
173
176
|
'CustomerKey'
|
|
174
177
|
);
|
|
175
178
|
delete metadata.SenderProfile;
|
|
179
|
+
const sp = cache.getByKey('senderProfile', metadata.r__senderProfile_key);
|
|
180
|
+
SenderProfile.verifySenderEmailAddresses(sp, metadata, this.definition);
|
|
176
181
|
} catch (ex) {
|
|
177
182
|
Util.logger.warn(` - ${this.definition.type} ${metadata.CustomerKey}: ${ex.message}`);
|
|
178
183
|
}
|