mcdev 4.3.0 → 4.3.2

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 (29) hide show
  1. package/.fork/custom-commands.json +14 -0
  2. package/.github/ISSUE_TEMPLATE/bug.yml +2 -0
  3. package/boilerplate/gitignore-template +1 -0
  4. package/docs/dist/documentation.md +2 -40
  5. package/lib/Retriever.js +22 -19
  6. package/lib/metadataTypes/AccountUser.js +42 -13
  7. package/lib/metadataTypes/Asset.js +37 -42
  8. package/lib/metadataTypes/Automation.js +1 -1
  9. package/lib/metadataTypes/DataExtensionField.js +5 -3
  10. package/lib/metadataTypes/EmailSendDefinition.js +84 -44
  11. package/lib/metadataTypes/Interaction.js +74 -9
  12. package/lib/metadataTypes/List.js +17 -15
  13. package/lib/metadataTypes/MetadataType.js +1 -1
  14. package/lib/metadataTypes/TriggeredSendDefinition.js +6 -5
  15. package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +52 -31
  16. package/lib/metadataTypes/definitions/Interaction.definition.js +1 -1
  17. package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +2 -2
  18. package/lib/metadataTypes/definitions/TransactionalPush.definition.js +2 -2
  19. package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +2 -2
  20. package/lib/util/auth.js +8 -3
  21. package/lib/util/devops.js +8 -4
  22. package/lib/util/util.js +51 -9
  23. package/package.json +2 -1
  24. package/test/interaction.test.js +2 -2
  25. package/test/mockRoot/.mcdevrc.json +1 -1
  26. package/test/resourceFactory.js +20 -9
  27. package/test/resources/9999999/interaction/v1/interactions/key_0b76dccf-594c-b6dc-1acf-10c4493dcb84/get-response.json +219 -0
  28. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/get-response.json +280 -0
  29. package/test/resources/9999999/triggeredSendDefinition/retrieve-response.xml +68 -0
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "name": "Create PR to develop branch",
4
+ "target": "ref",
5
+ "refTargets": [
6
+ "localbranch",
7
+ "remotebranch"
8
+ ],
9
+ "action": {
10
+ "type": "url",
11
+ "url": "https://github.com/Accenture/sfmc-devtools/compare/develop...$shortname?expand=1"
12
+ }
13
+ }
14
+ ]
@@ -39,6 +39,8 @@ body:
39
39
  label: Version
40
40
  description: What version of our software are you running? (mcdev --version)
41
41
  options:
42
+ - 4.3.2
43
+ - 4.3.1
42
44
  - 4.3.0
43
45
  - 4.2.1
44
46
  - 4.2.0
@@ -7,3 +7,4 @@ node_modules/
7
7
  /template/
8
8
  **/QueryStudioResults at*
9
9
  .mcdev-auth.json
10
+ *.error.log
@@ -736,10 +736,7 @@ MessageSendActivity MetadataType
736
736
  * [AccountUser](#AccountUser) ⇐ [<code>MetadataType</code>](#MetadataType)
737
737
  * [.retrieve(retrieveDir, _, [__], [key])](#AccountUser.retrieve) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
738
738
  * [.retrieveChangelog()](#AccountUser.retrieveChangelog) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
739
- * [.timeSinceDate(date)](#AccountUser.timeSinceDate) ⇒ <code>number</code>
740
- * [.getBuName(id)](#AccountUser.getBuName) ⇒ <code>string</code>
741
739
  * [.document([metadata])](#AccountUser.document) ⇒ <code>Promise.&lt;void&gt;</code>
742
- * [._generateDocMd(users, type, columnsToPrint)](#AccountUser._generateDocMd) ⇒ <code>string</code>
743
740
  * [.postRetrieveTasks(metadata)](#AccountUser.postRetrieveTasks) ⇒ <code>TYPE.MetadataTypeItem</code>
744
741
  * [.parseMetadata(metadata)](#AccountUser.parseMetadata) ⇒ <code>TYPE.MetadataTypeItem</code>
745
742
 
@@ -765,28 +762,6 @@ Retrieves SOAP based metadata of metadata type into local filesystem. executes c
765
762
 
766
763
  **Kind**: static method of [<code>AccountUser</code>](#AccountUser)
767
764
  **Returns**: <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code> - Promise of metadata
768
- <a name="AccountUser.timeSinceDate"></a>
769
-
770
- ### AccountUser.timeSinceDate(date) ⇒ <code>number</code>
771
- **Kind**: static method of [<code>AccountUser</code>](#AccountUser)
772
- **Returns**: <code>number</code> - time difference
773
-
774
- | Param | Type | Description |
775
- | --- | --- | --- |
776
- | date | <code>string</code> | first date |
777
-
778
- <a name="AccountUser.getBuName"></a>
779
-
780
- ### AccountUser.getBuName(id) ⇒ <code>string</code>
781
- helper to print bu names
782
-
783
- **Kind**: static method of [<code>AccountUser</code>](#AccountUser)
784
- **Returns**: <code>string</code> - "bu name (bu id)""
785
-
786
- | Param | Type | Description |
787
- | --- | --- | --- |
788
- | id | <code>number</code> | bu id |
789
-
790
765
  <a name="AccountUser.document"></a>
791
766
 
792
767
  ### AccountUser.document([metadata]) ⇒ <code>Promise.&lt;void&gt;</code>
@@ -799,18 +774,6 @@ Creates markdown documentation of all roles
799
774
  | --- | --- | --- |
800
775
  | [metadata] | <code>TYPE.MetadataTypeMap</code> | user list |
801
776
 
802
- <a name="AccountUser._generateDocMd"></a>
803
-
804
- ### AccountUser.\_generateDocMd(users, type, columnsToPrint) ⇒ <code>string</code>
805
- **Kind**: static method of [<code>AccountUser</code>](#AccountUser)
806
- **Returns**: <code>string</code> - markdown
807
-
808
- | Param | Type | Description |
809
- | --- | --- | --- |
810
- | users | <code>Array.&lt;object&gt;</code> | list of users and installed package |
811
- | type | <code>&#x27;Installed Package&#x27;</code> \| <code>&#x27;User&#x27;</code> | choose what sub type to print |
812
- | columnsToPrint | <code>Array.&lt;Array&gt;</code> | helper array |
813
-
814
777
  <a name="AccountUser.postRetrieveTasks"></a>
815
778
 
816
779
  ### AccountUser.postRetrieveTasks(metadata) ⇒ <code>TYPE.MetadataTypeItem</code>
@@ -849,7 +812,7 @@ FileTransfer MetadataType
849
812
  * [.retrieveAsTemplate(templateDir, name, templateVariables, [selectedSubType])](#Asset.retrieveAsTemplate) ⇒ <code>Promise.&lt;{metadata: TYPE.AssetItem, type: string}&gt;</code>
850
813
  * [.create(metadata)](#Asset.create) ⇒ <code>Promise</code>
851
814
  * [.update(metadata)](#Asset.update) ⇒ <code>Promise</code>
852
- * [.requestSubType(subType, subTypeArray, [retrieveDir], [templateName], [templateVariables], key)](#Asset.requestSubType) ⇒ <code>Promise</code>
815
+ * [.requestSubType(subType, [retrieveDir], [templateName], [templateVariables], key)](#Asset.requestSubType) ⇒ <code>Promise</code>
853
816
  * [.requestAndSaveExtended(items, subType, retrieveDir, [templateVariables])](#Asset.requestAndSaveExtended) ⇒ <code>Promise</code>
854
817
  * [._retrieveExtendedFile(metadata, subType, retrieveDir)](#Asset._retrieveExtendedFile) ⇒ <code>Promise.&lt;void&gt;</code>
855
818
  * [._readExtendedFileFromFS(metadata, subType, deployDir, [pathOnly])](#Asset._readExtendedFileFromFS) ⇒ <code>Promise.&lt;string&gt;</code>
@@ -939,7 +902,7 @@ Updates a single asset
939
902
 
940
903
  <a name="Asset.requestSubType"></a>
941
904
 
942
- ### Asset.requestSubType(subType, subTypeArray, [retrieveDir], [templateName], [templateVariables], key) ⇒ <code>Promise</code>
905
+ ### Asset.requestSubType(subType, [retrieveDir], [templateName], [templateVariables], key) ⇒ <code>Promise</code>
943
906
  Retrieves Metadata of a specific asset type
944
907
 
945
908
  **Kind**: static method of [<code>Asset</code>](#Asset)
@@ -948,7 +911,6 @@ Retrieves Metadata of a specific asset type
948
911
  | Param | Type | Description |
949
912
  | --- | --- | --- |
950
913
  | subType | <code>TYPE.AssetSubType</code> | group of similar assets to put in a folder (ie. images) |
951
- | subTypeArray | <code>Array.&lt;TYPE.AssetSubType&gt;</code> | list of all asset types within this subtype |
952
914
  | [retrieveDir] | <code>string</code> | target directory for saving assets |
953
915
  | [templateName] | <code>string</code> | name of the metadata file |
954
916
  | [templateVariables] | <code>TYPE.TemplateMap</code> | variables to be replaced in the metadata |
package/lib/Retriever.js CHANGED
@@ -62,29 +62,33 @@ class Retriever {
62
62
  // ensure we know which real dependencies we have to ensure we cache those completely
63
63
  const dependencies = this._getTypeDependencies(metadataTypes);
64
64
  const deployOrder = Util.getMetadataHierachy(metadataTypes);
65
- for (const metadataType in deployOrder) {
66
- const type = metadataType;
67
- const subTypeArr = deployOrder[metadataType];
65
+ for (const type in deployOrder) {
66
+ const subTypeArr = deployOrder[type];
68
67
  // if types were added by getMetadataHierachy() for caching, make sure the key-list is set to [null] for them which will retrieve all
69
- typeKeyMap[metadataType] = typeKeyMap[metadataType] || [null];
68
+ typeKeyMap[type] = typeKeyMap[type] || [null];
70
69
  // add client to metadata process class instead of passing every time
71
70
  MetadataTypeInfo[type].client = auth.getSDK(this.buObject);
72
71
  MetadataTypeInfo[type].properties = this.properties;
73
72
  MetadataTypeInfo[type].buObject = this.buObject;
74
73
  try {
75
74
  let result;
76
- if (!metadataTypes.includes(type) && !metadataTypes.includes(metadataType)) {
75
+ if (
76
+ !metadataTypes.includes(type) &&
77
+ (!Array.isArray(subTypeArr) ||
78
+ (Array.isArray(subTypeArr) &&
79
+ !metadataTypes.includes(`${type}-${subTypeArr?.[0]}`)))
80
+ ) {
77
81
  // type not in list of types to retrieve, but is a dependency of one of them
78
82
  if (changelogOnly && type !== 'folder') {
79
83
  // no extra caching needed for list view except for folders
80
84
  continue;
81
85
  }
82
- Util.logger.info(`Caching dependent Metadata: ${metadataType}`);
86
+ Util.logger.info(`Caching dependent Metadata: ${type}`);
83
87
  Util.logSubtypes(subTypeArr);
84
88
  result = await MetadataTypeInfo[type].retrieveForCache(null, subTypeArr);
85
89
  } else if (templateVariables) {
86
90
  // type is in list of types to retrieve and we have template variables
87
- Util.logger.info(`Retrieving as Template: ${metadataType}`);
91
+ Util.logger.info(`Retrieving as Template: ${type}`);
88
92
  if (subTypeArr?.length > 1) {
89
93
  Util.logger.warn(
90
94
  `retrieveAsTemplate only works with one subtype, ignoring all but first subtype from your list: ${subTypeArr.join(
@@ -93,7 +97,7 @@ class Retriever {
93
97
  );
94
98
  }
95
99
  result = await Promise.all(
96
- typeKeyMap[metadataType].map((name) =>
100
+ typeKeyMap[type].map((name) =>
97
101
  MetadataTypeInfo[type].retrieveAsTemplate(
98
102
  this.templateDir,
99
103
  name,
@@ -106,12 +110,11 @@ class Retriever {
106
110
  // type is in list of types to retrieve and we don't have template variables
107
111
  let cacheResult = null;
108
112
  if (
109
- (typeKeyMap[metadataType].length > 1 ||
110
- typeKeyMap[metadataType][0] !== null) &&
111
- (dependencies.includes(type) || dependencies.includes(metadataType))
113
+ (typeKeyMap[type].length > 1 || typeKeyMap[type][0] !== null) &&
114
+ (dependencies.includes(type) || dependencies.includes(type))
112
115
  ) {
113
116
  // if we have a key-list and the type is a dependency, we need to cache the whole type
114
- Util.logger.info(`Caching dependent Metadata: ${metadataType}`);
117
+ Util.logger.info(`Caching dependent Metadata: ${type}`);
115
118
  Util.logSubtypes(subTypeArr);
116
119
  cacheResult = await MetadataTypeInfo[type].retrieveForCache(
117
120
  null,
@@ -119,15 +122,15 @@ class Retriever {
119
122
  );
120
123
  }
121
124
  Util.logger.info(
122
- `Retrieving: ${metadataType}` +
123
- (typeKeyMap[metadataType][0] === null
125
+ `Retrieving: ${type}` +
126
+ (typeKeyMap[type][0] === null
124
127
  ? ''
125
- : Util.getKeysString(typeKeyMap[metadataType]))
128
+ : Util.getKeysString(typeKeyMap[type]))
126
129
  );
127
130
  result = await (changelogOnly
128
131
  ? MetadataTypeInfo[type].retrieveChangelog(null, subTypeArr)
129
132
  : Promise.all(
130
- typeKeyMap[metadataType].map((key) =>
133
+ typeKeyMap[type].map((key) =>
131
134
  MetadataTypeInfo[type].retrieve(
132
135
  this.savePath,
133
136
  null,
@@ -154,14 +157,14 @@ class Retriever {
154
157
  cache.mergeMetadata(type, result_i.metadata);
155
158
  }
156
159
  }
157
- if (metadataTypes.includes(type) || metadataTypes.includes(metadataType)) {
160
+ if (metadataTypes.includes(type) || metadataTypes.includes(type)) {
158
161
  retrieveChangelog[type] = result
159
162
  .filter((el) => !!el)
160
163
  .map((element) => element.metadata);
161
164
  }
162
165
  } else {
163
166
  cache.setMetadata(type, result.metadata);
164
- if (metadataTypes.includes(type) || metadataTypes.includes(metadataType)) {
167
+ if (metadataTypes.includes(type) || metadataTypes.includes(type)) {
165
168
  retrieveChangelog[type] = result.metadata;
166
169
  }
167
170
  }
@@ -175,7 +178,7 @@ class Retriever {
175
178
  Util.logger.error(ex.message);
176
179
  break;
177
180
  } else {
178
- Util.logger.errorStack(ex, ` - Retrieving ${metadataType} failed`);
181
+ Util.logger.errorStack(ex, ` - Retrieving ${type} failed`);
179
182
  }
180
183
  }
181
184
  }
@@ -60,10 +60,17 @@ class AccountUser extends MetadataType {
60
60
  for (const item of resultsBatch) {
61
61
  this.userIdBuMap[item.AccountUser.AccountUserID] =
62
62
  this.userIdBuMap[item.AccountUser.AccountUserID] || [];
63
- this.userIdBuMap[item.AccountUser.AccountUserID].push({
64
- ID: item.Account.ID,
65
- Name: item.Account.Name,
66
- });
63
+ // push to array if not already in array
64
+ if (
65
+ !this.userIdBuMap[item.AccountUser.AccountUserID].some(
66
+ (bu) => bu.ID === item.Account.ID
67
+ )
68
+ ) {
69
+ this.userIdBuMap[item.AccountUser.AccountUserID].push({
70
+ ID: item.Account.ID,
71
+ Name: item.Account.Name,
72
+ });
73
+ }
67
74
  }
68
75
  // get actual user details
69
76
  /** @type {TYPE.SoapRequestParams} */
@@ -114,10 +121,11 @@ class AccountUser extends MetadataType {
114
121
  }
115
122
  /**
116
123
  *
124
+ * @private
117
125
  * @param {string} date first date
118
126
  * @returns {number} time difference
119
127
  */
120
- static timeSinceDate(date) {
128
+ static _timeSinceDate(date) {
121
129
  const interval = 'days';
122
130
  const second = 1000,
123
131
  minute = second * 60,
@@ -172,13 +180,28 @@ class AccountUser extends MetadataType {
172
180
  /**
173
181
  * helper to print bu names
174
182
  *
183
+ * @private
175
184
  * @param {number} id bu id
176
185
  * @returns {string} "bu name (bu id)""
177
186
  */
178
- static getBuName(id) {
187
+ static _getBuName(id) {
179
188
  const name = this.buObject.eid == id ? '_ParentBU_' : this.buIdName[id];
180
189
  return `<nobr>${name} (${id})</nobr>`;
181
190
  }
191
+
192
+ /**
193
+ * helper that gets BU names from config
194
+ *
195
+ * @private
196
+ */
197
+ static _getBuNames() {
198
+ this.buIdName = {};
199
+ for (const cred in this.properties.credentials) {
200
+ for (const buName in this.properties.credentials[cred].businessUnits) {
201
+ this.buIdName[this.properties.credentials[cred].businessUnits[buName]] = buName;
202
+ }
203
+ }
204
+ }
182
205
  /**
183
206
  * Creates markdown documentation of all roles
184
207
  *
@@ -209,7 +232,7 @@ class AccountUser extends MetadataType {
209
232
  }
210
233
  }
211
234
  // init map of BU Ids > BU Name
212
- this.buIdName = {};
235
+ this._getBuNames();
213
236
 
214
237
  // initialize permission object
215
238
  this.allPermissions = {};
@@ -244,14 +267,19 @@ class AccountUser extends MetadataType {
244
267
  }
245
268
  let associatedBus = '';
246
269
  if (user.AssociatedBusinessUnits__c) {
247
- associatedBus = user.AssociatedBusinessUnits__c.map((item) => {
248
- this.buIdName[item.ID] = item.Name;
249
- return this.getBuName(item.ID);
250
- })
270
+ user.AssociatedBusinessUnits__c.push({
271
+ ID: user.DefaultBusinessUnit,
272
+ });
273
+ // ensure associatedBus have no duplicates
274
+ associatedBus = [
275
+ ...new Set(
276
+ user.AssociatedBusinessUnits__c.map((item) => this._getBuName(item.ID))
277
+ ),
278
+ ]
251
279
  .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
252
280
  .join(',<br> ');
253
281
  }
254
- const defaultBUName = this.getBuName(user.DefaultBusinessUnit);
282
+ const defaultBUName = this._getBuName(user.DefaultBusinessUnit);
255
283
  users.push({
256
284
  TYPE: user.type__c,
257
285
  UserID: user.UserID,
@@ -267,7 +295,7 @@ class AccountUser extends MetadataType {
267
295
  AssociatedBusinessUnits__c: associatedBus,
268
296
  Roles: roles,
269
297
  UserPermissions: userPermissions,
270
- LastSuccessfulLogin: this.timeSinceDate(user.LastSuccessfulLogin),
298
+ LastSuccessfulLogin: this._timeSinceDate(user.LastSuccessfulLogin),
271
299
  CreatedDate: user.CreatedDate.split('T').join(' '),
272
300
  ModifiedDate: user.ModifiedDate.split('T').join(' '),
273
301
  });
@@ -325,6 +353,7 @@ class AccountUser extends MetadataType {
325
353
  }
326
354
  /**
327
355
  *
356
+ * @private
328
357
  * @param {object[]} users list of users and installed package
329
358
  * @param {'Installed Package'|'User'} type choose what sub type to print
330
359
  * @param {Array[]} columnsToPrint helper array
@@ -31,16 +31,7 @@ class Asset extends MetadataType {
31
31
  for (const subType of subTypeArr) {
32
32
  // each subtype contains multiple different specific types (images contains jpg and png for example)
33
33
  // we use await here to limit the risk of too many concurrent api requests at time
34
- items.push(
35
- ...(await this.requestSubType(
36
- subType,
37
- this.definition.extendedSubTypes[subType],
38
- retrieveDir,
39
- null,
40
- null,
41
- key
42
- ))
43
- );
34
+ items.push(...(await this.requestSubType(subType, retrieveDir, null, null, key)));
44
35
  }
45
36
  const metadata = this.parseResponseBody({ items: items });
46
37
  if (retrieveDir) {
@@ -81,13 +72,7 @@ class Asset extends MetadataType {
81
72
  // each subtype contains multiple different specific types (images contains jpg and png for example)
82
73
  // we use await here to limit the risk of too many concurrent api requests at time
83
74
  items.push(
84
- ...(await this.requestSubType(
85
- subType,
86
- this.definition.extendedSubTypes[subType],
87
- templateDir,
88
- name,
89
- templateVariables
90
- ))
75
+ ...(await this.requestSubType(subType, templateDir, name, templateVariables))
91
76
  );
92
77
  }
93
78
  const metadata = this.parseResponseBody({ items: items });
@@ -146,27 +131,21 @@ class Asset extends MetadataType {
146
131
  * Retrieves Metadata of a specific asset type
147
132
  *
148
133
  * @param {TYPE.AssetSubType} subType group of similar assets to put in a folder (ie. images)
149
- * @param {TYPE.AssetSubType[]} subTypeArray list of all asset types within this subtype
150
134
  * @param {string} [retrieveDir] target directory for saving assets
151
135
  * @param {string} [templateName] name of the metadata file
152
136
  * @param {TYPE.TemplateMap} [templateVariables] variables to be replaced in the metadata
153
137
  * @param {string} key customer key to filter by
154
138
  * @returns {Promise} Promise
155
139
  */
156
- static async requestSubType(
157
- subType,
158
- subTypeArray,
159
- retrieveDir,
160
- templateName,
161
- templateVariables,
162
- key
163
- ) {
140
+ static async requestSubType(subType, retrieveDir, templateName, templateVariables, key) {
164
141
  if (retrieveDir) {
165
142
  Util.logger.info(`- Retrieving Subtype: ${subType}`);
166
143
  } else {
167
144
  Util.logger.info(` - Caching Subtype: ${subType}`);
168
145
  }
169
- const subtypeIds = subTypeArray?.map(
146
+ /** @type {TYPE.AssetSubType[]} */
147
+ const extendedSubTypeArr = this.definition.extendedSubTypes[subType];
148
+ const subtypeIds = extendedSubTypeArr?.map(
170
149
  (subTypeItemName) => Asset.definition.typeMapping[subTypeItemName]
171
150
  );
172
151
  const uri = '/asset/v1/content/assets/query';
@@ -338,22 +317,30 @@ class Asset extends MetadataType {
338
317
  } catch (ex) {
339
318
  failed.push({ item: item, error: ex });
340
319
  }
320
+ // even if the extended file failed, still save the metadata
341
321
  metadata[item.customerKey] = item;
342
322
  }
343
323
  // this is a complex type which stores data in the asset itself
344
324
  else if (!completed.includes(item.id)) {
345
- const extendedItem = await this.client.rest.get(
346
- 'asset/v1/content/assets/' + item.id
347
- );
348
- metadata[item.customerKey] = extendedItem;
325
+ try {
326
+ const extendedItem = await this.client.rest.get(
327
+ 'asset/v1/content/assets/' + item.id
328
+ );
329
+ // only save the metadata if we have extended content
330
+ metadata[item.customerKey] = extendedItem;
331
+ } catch (ex) {
332
+ failed.push({ item: item, error: ex });
333
+ }
349
334
  }
350
335
  completed.push(item.id);
351
- await this.saveResults(
352
- metadata,
353
- retrieveDir,
354
- 'asset-' + subType,
355
- templateVariables
356
- );
336
+ if (metadata[item.customerKey]) {
337
+ await this.saveResults(
338
+ metadata,
339
+ retrieveDir,
340
+ 'asset-' + subType,
341
+ templateVariables
342
+ );
343
+ }
357
344
  // update the current value in your application..
358
345
  extendedBar.increment();
359
346
  })
@@ -367,7 +354,7 @@ class Asset extends MetadataType {
367
354
  } catch (ex) {
368
355
  extendedBar.stop();
369
356
  Asset._resetLogLevel(loggerLevelBak, failed);
370
- // timeouts should be retried, others can be retried
357
+ // timeouts should be retried, others can be exited
371
358
  if (ex.code !== 'ETIMEDOUT') {
372
359
  throw ex;
373
360
  }
@@ -415,11 +402,17 @@ class Asset extends MetadataType {
415
402
  );
416
403
  for (const fail of failed) {
417
404
  Util.logger.warn(
418
- ` - "${fail.item.name}" (${fail.item.customerKey}) in ${fail.item.r__folder_Path}: ${fail.error.message}`
405
+ ` - "${fail.item.name}" (${fail.item.customerKey}): ${fail.error.message} (${
406
+ fail.error.code
407
+ })${
408
+ fail.error.endpoint
409
+ ? Util.getGrayMsg(
410
+ ' - ' +
411
+ fail.error.endpoint.split('rest.marketingcloudapis.com')[1]
412
+ )
413
+ : ''
414
+ }`
419
415
  );
420
- Util.logger.debug(`-- Error: ${fail.error.message}`);
421
- Util.logger.debug(`-- AssetType: ${fail.item.assetType.name}`);
422
- Util.logger.debug(`-- fileProperties: ${JSON.stringify(fail.item.fileProperties)}`);
423
416
  }
424
417
  Util.logger.info(
425
418
  ' - You will still find a JSON file for each of these in the download directory.'
@@ -977,6 +970,7 @@ class Asset extends MetadataType {
977
970
 
978
971
  break;
979
972
  }
973
+ case 'template': // template-template
980
974
  case 'buttonblock': // block - Button Block
981
975
  case 'freeformblock': // block
982
976
  case 'htmlblock': // block
@@ -1198,6 +1192,7 @@ class Asset extends MetadataType {
1198
1192
  subFolder: [customerKey],
1199
1193
  };
1200
1194
  }
1195
+ case 'template': // template-template
1201
1196
  case 'buttonblock': // block - Button Block
1202
1197
  case 'freeformblock': // block
1203
1198
  case 'htmlblock': // block
@@ -63,7 +63,7 @@ class Automation extends MetadataType {
63
63
  }
64
64
  // if we do get here, we should log the error and continue instead of failing to download all automations
65
65
  Util.logger.error(
66
- ` - skipping retrieving Automation ${a.ObjectID}: ${ex.message} ${ex.code}`
66
+ ` skipping Automation ${a.ObjectID}: ${ex.message} ${ex.code}`
67
67
  );
68
68
  return null;
69
69
  }
@@ -242,9 +242,11 @@ class DataExtensionField extends MetadataType {
242
242
  }
243
243
 
244
244
  Util.logger.info(
245
- ` - Found ${deployColumns.length} added/updated Fields for ${deKey}${
246
- deployColumns.length ? ': ' : ''
247
- }` + deployColumns.map((item) => item.Name).join(', ')
245
+ Util.getGrayMsg(
246
+ ` - Found ${deployColumns.length} added/updated Fields for ${deKey}${
247
+ deployColumns.length ? ': ' : ''
248
+ }` + deployColumns.map((item) => item.Name).join(', ')
249
+ )
248
250
  );
249
251
  return existingFieldByName;
250
252
  }