mcdev 3.1.3 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/.eslintrc.json +67 -7
  2. package/.github/ISSUE_TEMPLATE/bug.yml +2 -1
  3. package/.github/PULL_REQUEST_TEMPLATE.md +5 -3
  4. package/.github/dependabot.yml +14 -0
  5. package/.github/workflows/code-analysis.yml +57 -0
  6. package/.husky/commit-msg +10 -0
  7. package/.husky/post-checkout +5 -0
  8. package/.husky/pre-commit +2 -1
  9. package/.prettierrc +8 -0
  10. package/.vscode/settings.json +1 -1
  11. package/LICENSE +2 -2
  12. package/README.md +134 -45
  13. package/boilerplate/config.json +5 -11
  14. package/boilerplate/files/.prettierrc +8 -0
  15. package/boilerplate/files/.vscode/extensions.json +0 -1
  16. package/boilerplate/files/.vscode/settings.json +30 -2
  17. package/boilerplate/files/README.md +2 -2
  18. package/boilerplate/forcedUpdates.json +10 -0
  19. package/boilerplate/npm-dependencies.json +5 -5
  20. package/docs/dist/documentation.md +2807 -1730
  21. package/jsconfig.json +1 -1
  22. package/lib/Builder.js +171 -74
  23. package/lib/Deployer.js +244 -96
  24. package/lib/MetadataTypeDefinitions.js +2 -0
  25. package/lib/MetadataTypeInfo.js +2 -0
  26. package/lib/Retriever.js +61 -84
  27. package/lib/cli.js +116 -11
  28. package/lib/index.js +241 -561
  29. package/lib/metadataTypes/AccountUser.js +117 -103
  30. package/lib/metadataTypes/Asset.js +705 -255
  31. package/lib/metadataTypes/AttributeGroup.js +23 -12
  32. package/lib/metadataTypes/Automation.js +489 -392
  33. package/lib/metadataTypes/Campaign.js +33 -93
  34. package/lib/metadataTypes/ContentArea.js +31 -11
  35. package/lib/metadataTypes/DataExtension.js +387 -372
  36. package/lib/metadataTypes/DataExtensionField.js +131 -54
  37. package/lib/metadataTypes/DataExtensionTemplate.js +22 -4
  38. package/lib/metadataTypes/DataExtract.js +61 -48
  39. package/lib/metadataTypes/DataExtractType.js +14 -8
  40. package/lib/metadataTypes/Discovery.js +21 -16
  41. package/lib/metadataTypes/Email.js +32 -12
  42. package/lib/metadataTypes/EmailSendDefinition.js +85 -80
  43. package/lib/metadataTypes/EventDefinition.js +61 -43
  44. package/lib/metadataTypes/FileTransfer.js +72 -52
  45. package/lib/metadataTypes/Filter.js +11 -4
  46. package/lib/metadataTypes/Folder.js +149 -117
  47. package/lib/metadataTypes/FtpLocation.js +14 -8
  48. package/lib/metadataTypes/ImportFile.js +61 -64
  49. package/lib/metadataTypes/Interaction.js +19 -4
  50. package/lib/metadataTypes/List.js +54 -13
  51. package/lib/metadataTypes/MetadataType.js +664 -454
  52. package/lib/metadataTypes/MobileCode.js +46 -0
  53. package/lib/metadataTypes/MobileKeyword.js +114 -0
  54. package/lib/metadataTypes/Query.js +206 -105
  55. package/lib/metadataTypes/Role.js +76 -61
  56. package/lib/metadataTypes/Script.js +147 -83
  57. package/lib/metadataTypes/SetDefinition.js +20 -8
  58. package/lib/metadataTypes/TriggeredSendDefinition.js +78 -58
  59. package/lib/metadataTypes/definitions/Asset.definition.js +21 -10
  60. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +12 -0
  61. package/lib/metadataTypes/definitions/Automation.definition.js +10 -5
  62. package/lib/metadataTypes/definitions/Campaign.definition.js +44 -1
  63. package/lib/metadataTypes/definitions/DataExtension.definition.js +4 -0
  64. package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +6 -0
  65. package/lib/metadataTypes/definitions/DataExtract.definition.js +18 -14
  66. package/lib/metadataTypes/definitions/Discovery.definition.js +12 -0
  67. package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +4 -0
  68. package/lib/metadataTypes/definitions/EventDefinition.definition.js +22 -0
  69. package/lib/metadataTypes/definitions/FileTransfer.definition.js +4 -0
  70. package/lib/metadataTypes/definitions/Filter.definition.js +4 -0
  71. package/lib/metadataTypes/definitions/Folder.definition.js +6 -0
  72. package/lib/metadataTypes/definitions/FtpLocation.definition.js +4 -0
  73. package/lib/metadataTypes/definitions/ImportFile.definition.js +10 -5
  74. package/lib/metadataTypes/definitions/Interaction.definition.js +4 -0
  75. package/lib/metadataTypes/definitions/MobileCode.definition.js +163 -0
  76. package/lib/metadataTypes/definitions/MobileKeyword.definition.js +253 -0
  77. package/lib/metadataTypes/definitions/Query.definition.js +4 -0
  78. package/lib/metadataTypes/definitions/Role.definition.js +5 -0
  79. package/lib/metadataTypes/definitions/Script.definition.js +4 -0
  80. package/lib/metadataTypes/definitions/SetDefinition.definition.js +28 -0
  81. package/lib/metadataTypes/definitions/TriggeredSendDefinition.definition.js +4 -0
  82. package/lib/retrieveChangelog.js +7 -6
  83. package/lib/util/auth.js +117 -0
  84. package/lib/util/businessUnit.js +55 -66
  85. package/lib/util/cache.js +194 -0
  86. package/lib/util/cli.js +90 -116
  87. package/lib/util/config.js +302 -0
  88. package/lib/util/devops.js +250 -50
  89. package/lib/util/file.js +141 -201
  90. package/lib/util/init.config.js +208 -75
  91. package/lib/util/init.git.js +45 -50
  92. package/lib/util/init.js +72 -59
  93. package/lib/util/init.npm.js +48 -39
  94. package/lib/util/util.js +280 -564
  95. package/package.json +45 -34
  96. package/test/dataExtension.test.js +152 -0
  97. package/test/mockRoot/.mcdev-auth.json +8 -0
  98. package/test/mockRoot/.mcdevrc.json +67 -0
  99. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/childBU_dataextension_test.dataExtension-meta.json +39 -0
  100. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/testDataExtension.dataExtension-meta.json +23 -0
  101. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +11 -0
  102. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.sql +4 -0
  103. package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.json +11 -0
  104. package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.sql +4 -0
  105. package/test/query.test.js +149 -0
  106. package/test/resourceFactory.js +142 -0
  107. package/test/resources/1111111/dataFolder/retrieve-response.xml +43 -0
  108. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +18 -0
  109. package/test/resources/9999999/automation/v1/queries/get-response.json +24 -0
  110. package/test/resources/9999999/automation/v1/queries/post-response.json +18 -0
  111. package/test/resources/9999999/dataExtension/build-expected.json +51 -0
  112. package/test/resources/9999999/dataExtension/create-expected.json +23 -0
  113. package/test/resources/9999999/dataExtension/create-response.xml +54 -0
  114. package/test/resources/9999999/dataExtension/retrieve-expected.json +51 -0
  115. package/test/resources/9999999/dataExtension/retrieve-response.xml +47 -0
  116. package/test/resources/9999999/dataExtension/template-expected.json +51 -0
  117. package/test/resources/9999999/dataExtension/update-expected.json +55 -0
  118. package/test/resources/9999999/dataExtension/update-response.xml +52 -0
  119. package/test/resources/9999999/dataExtensionField/retrieve-response.xml +93 -0
  120. package/test/resources/9999999/dataExtensionTemplate/retrieve-response.xml +303 -0
  121. package/test/resources/9999999/dataFolder/retrieve-response.xml +65 -0
  122. package/test/resources/9999999/query/build-expected.json +8 -0
  123. package/test/resources/9999999/query/get-expected.json +11 -0
  124. package/test/resources/9999999/query/patch-expected.json +11 -0
  125. package/test/resources/9999999/query/post-expected.json +11 -0
  126. package/test/resources/9999999/query/template-expected.json +8 -0
  127. package/test/resources/auth.json +32 -0
  128. package/test/resources/rest404-response.json +5 -0
  129. package/test/resources/retrieve-response.xml +21 -0
  130. package/test/utils.js +107 -0
  131. package/types/mcdev.d.js +301 -0
  132. package/CHANGELOG.md +0 -126
  133. package/PULL_REQUEST_TEMPLATE.md +0 -19
  134. package/test/util/file.js +0 -51
@@ -1,8 +1,10 @@
1
+ const TYPE = require('../../types/mcdev.d');
1
2
  const File = require('./file');
2
- const path = require('path');
3
+ const path = require('node:path');
3
4
  const inquirer = require('inquirer');
4
5
  const Util = require('./util');
5
- const git = require('simple-git/promise')();
6
+ const git = require('simple-git')();
7
+ const Builder = require('../Builder');
6
8
  const MetadataType = require('../MetadataTypeInfo');
7
9
  const jsonToTable = require('json-to-table');
8
10
  /**
@@ -13,25 +15,23 @@ const DevOps = {
13
15
  /**
14
16
  * Extracts the delta between a commit and the current state for deployment.
15
17
  * Interactive commit selection if no commits are passed.
16
- * @param {Object} properties central properties object
17
- * @param {String} [range] git commit range
18
+ *
19
+ * @param {TYPE.Mcdevrc} properties central properties object
20
+ * @param {string} [range] git commit range
18
21
  * @param {boolean} [saveToDeployDir] if true, copy metadata changes into deploy directory
19
- * @param {String} [filterPaths] filter file paths that start with any specified path (comma separated)
20
- * @returns {Promise<Object>} -
22
+ * @param {string} [filterPaths] filter file paths that start with any specified path (comma separated)
23
+ * @returns {Promise.<TYPE.DeltaPkgItem[]>} -
21
24
  */
22
- async createDeltaPkg(properties, range, saveToDeployDir, filterPaths) {
25
+ async getDeltaList(properties, range, saveToDeployDir, filterPaths) {
23
26
  const rangeUserInput = range;
24
- Util.logger.info('Create Delta Package ::');
25
- if (filterPaths) {
26
- filterPaths = filterPaths.split(',').map((filePath) =>
27
- path
28
- .normalize(properties.directories.retrieve + filePath)
29
- .split('\\')
30
- .join('/')
31
- );
32
- } else {
33
- filterPaths = [properties.directories.retrieve];
34
- }
27
+ filterPaths = filterPaths
28
+ ? filterPaths.split(',').map((filePath) =>
29
+ path
30
+ .normalize(properties.directories.retrieve + filePath)
31
+ .split('\\')
32
+ .join('/')
33
+ )
34
+ : [properties.directories.retrieve];
35
35
  if (range) {
36
36
  if (!range.includes('..')) {
37
37
  // we limit the user here somewhat by always comparing to current branch if no range was given
@@ -54,7 +54,7 @@ const DevOps = {
54
54
  }));
55
55
  display.push(new inquirer.Separator(' ==== '));
56
56
 
57
- const questions = [
57
+ const responses = await inquirer.prompt([
58
58
  {
59
59
  type: 'list',
60
60
  message: 'Select base commit for comparison with current commit',
@@ -62,12 +62,7 @@ const DevOps = {
62
62
  pageSize: 10,
63
63
  choices: display,
64
64
  },
65
- ];
66
- const responses = await new Promise((resolve) => {
67
- inquirer.prompt(questions).then((answers) => {
68
- resolve(answers);
69
- });
70
- });
65
+ ]);
71
66
  range = `${responses.commit}..HEAD`;
72
67
  }
73
68
 
@@ -78,18 +73,22 @@ const DevOps = {
78
73
  'add/update': 0,
79
74
  move: 0,
80
75
  };
76
+ /**
77
+ * @type {TYPE.DeltaPkgItem[]}
78
+ */
81
79
  const delta = (await git.diffSummary([range])).files
82
80
  // populate additional info for all changed files
83
- .map((file) => {
81
+ .map((/** @type {TYPE.DeltaPkgItem} */ file) => {
84
82
  // If file was moved it's path needs to be parsed
85
83
  file.moved = file.file.includes('=>');
86
84
  if (file.moved) {
87
85
  const p = file.file;
86
+ // TODO: rewrite remaining substring() to slice()
88
87
  const paths = {
89
- base: p.substring(0, p.indexOf('{')),
90
- before: p.substring(p.indexOf('{') + 1, p.indexOf('=>') - 1),
91
- after: p.substring(p.indexOf('=>') + 3, p.indexOf('}')),
92
- end: p.substring(p.indexOf('}') + 1),
88
+ base: p.slice(0, Math.max(0, p.indexOf('{'))),
89
+ before: p.substring(p.indexOf('{') + 1, p.indexOf('=>') - 1), // eslint-disable-line unicorn/prefer-string-slice
90
+ after: p.substring(p.indexOf('=>') + 3, p.indexOf('}')), // eslint-disable-line unicorn/prefer-string-slice
91
+ end: p.slice(Math.max(0, p.indexOf('}') + 1)),
93
92
  };
94
93
  file.fromPath = path
95
94
  .normalize(`${paths.base}${paths.before}${paths.end}`)
@@ -113,7 +112,7 @@ const DevOps = {
113
112
  // ! Filter happens after initial parse, because if file was moved its new path has to be calculated
114
113
  .filter((file) => filterPaths.some((path) => file.file.startsWith(path)))
115
114
  // ensure badly named files on unsupported metadata types are not in our subset
116
- .filter((file) => {
115
+ .filter((/** @type {TYPE.DeltaPkgItem} */ file) => {
117
116
  if (!MetadataType[file.type]) {
118
117
  Util.logger.debug(
119
118
  `Unknown metadata-type found for (${file.file}): ` + file.type
@@ -123,7 +122,7 @@ const DevOps = {
123
122
  return true;
124
123
  }
125
124
  })
126
- .map((file) => {
125
+ .map((/** @type {TYPE.DeltaPkgItem} */ file) => {
127
126
  // Gets external key based on file name und the assumption that filename = externalKey
128
127
  if (file.type === 'folder') {
129
128
  file.externalKey = null;
@@ -135,7 +134,7 @@ const DevOps = {
135
134
 
136
135
  // Check if file doesn't exist in reported path, that means it was a git deletion
137
136
  // TODO: improve git action detection by switching from diffSummary to diff with --summary result parsing
138
- if (!File.existsSync(file.file)) {
137
+ if (!File.pathExistsSync(file.file)) {
139
138
  file.gitAction = 'delete';
140
139
  } else if (file.moved) {
141
140
  file.gitAction = 'move';
@@ -189,8 +188,12 @@ const DevOps = {
189
188
  return [];
190
189
  }
191
190
  // Write into delta.json to serve as documentation
192
- File.writeJSONToFile(properties.directories.deltaPackage, 'delta_package', delta);
193
- this.document(properties.directories.deltaPackage, delta);
191
+ const directoryDeltaPkg = File.normalizePath([
192
+ properties.directories.docs,
193
+ 'deltaPackage/',
194
+ ]);
195
+ await File.writeJSONToFile(directoryDeltaPkg, 'delta_package', delta);
196
+ this.document(directoryDeltaPkg, delta);
194
197
  Util.logger.info(
195
198
  `- ✔️ Identified changes: Add/Update=${gitActionsCounter['add/update']}, Move=${gitActionsCounter['move']}, Delete=${gitActionsCounter['delete']}`
196
199
  );
@@ -199,12 +202,11 @@ const DevOps = {
199
202
  'Please note that deletions have to be done manually on the SFMC website.'
200
203
  );
201
204
  }
202
- Util.logger.info(
203
- `Saved report in ${path.join(properties.directories.deltaPackage, 'delta_package.md')}`
204
- );
205
+ Util.logger.info(`Saved report in ${path.join(directoryDeltaPkg, 'delta_package.md')}`);
205
206
 
206
207
  // Copy filtered list of files into deploy directory
207
208
  if (saveToDeployDir) {
209
+ /** @type {TYPE.DeltaPkgItem} */
208
210
  const copied = delta.map((file) =>
209
211
  File.copyFile(
210
212
  file.file,
@@ -229,42 +231,225 @@ const DevOps = {
229
231
  } copied, ${skipped.length} skipped, ${failed.length} failed)`
230
232
  );
231
233
  if (skipped.length > 0) {
232
- skipped.forEach((file) =>
233
- Util.logger.debug(`Skipped - ${file.statusMessage} - ${file.file}`)
234
- );
234
+ for (const file of skipped) {
235
+ Util.logger.debug(`Skipped - ${file.statusMessage} - ${file.file}`);
236
+ }
235
237
  }
236
238
  if (failed.length > 0) {
237
- failed.forEach((file) =>
238
- Util.logger.error(`Failed - ${file.statusMessage} - ${file.file}`)
239
- );
239
+ for (const file of failed) {
240
+ Util.logger.error(`Failed - ${file.statusMessage} - ${file.file}`);
241
+ }
240
242
  }
241
243
  }
242
244
  return delta;
243
245
  },
246
+ /**
247
+ * wrapper around DevOps.getDeltaList, Builder.buildTemplate and M
248
+ *
249
+ * @param {TYPE.Mcdevrc} properties project config file
250
+ * @param {string} range git commit range
251
+ * @param {TYPE.SkipInteraction} [skipInteraction] allows to skip interactive wizard
252
+ * @returns {Promise.<TYPE.DeltaPkgItem[]>} -
253
+ */
254
+ async buildDeltaDefinitions(properties, range, skipInteraction) {
255
+ // check if sourceTargetMapping is valid
256
+ if (
257
+ !properties.options.deployment.sourceTargetMapping ||
258
+ !Object.keys(properties.options.deployment.sourceTargetMapping).length
259
+ ) {
260
+ Util.logger.error('Bad configuration of options.deployment.sourceTargetMapping');
261
+ return;
262
+ }
263
+ const sourceMarketListArr = Object.keys(properties.options.deployment.sourceTargetMapping);
264
+ /** @type {TYPE.DeltaPkgItem[]} */
265
+ const deltaDeployAll = [];
266
+ for (const sourceML of sourceMarketListArr) {
267
+ // check if sourceTargetMapping has valid values
268
+ // #1 check source marketlist
269
+ try {
270
+ Util.verifyMarketList(sourceML, properties);
271
+ // remove potentially existing "description"-entry
272
+ delete properties.marketList[sourceML].description;
273
+
274
+ const sourceMarketBuArr = Object.keys(properties.marketList[sourceML]);
275
+ if (sourceMarketBuArr.length !== 1) {
276
+ throw new Error('Only 1 BU is allowed per source marketList');
277
+ }
278
+ if ('string' !== typeof properties.marketList[sourceML][sourceMarketBuArr[0]]) {
279
+ throw new TypeError('Only 1 market per BU is allowed per source marketList');
280
+ }
281
+ } catch (ex) {
282
+ Util.logger.error('Deployment Source: ' + ex.message);
283
+ return;
284
+ }
285
+ // #2 check corresponding target marketList
286
+ let targetML;
287
+ try {
288
+ targetML = properties.options.deployment.sourceTargetMapping[sourceML];
289
+ if ('string' !== typeof targetML) {
290
+ throw new TypeError(
291
+ 'Please define one target marketList per source in deployment.sourceTargetMapping (No arrays allowed)'
292
+ );
293
+ }
294
+ Util.verifyMarketList(targetML, properties);
295
+ // remove potentially existing "description"-entry
296
+ delete properties.marketList[targetML].description;
297
+ } catch (ex) {
298
+ Util.logger.error('Deployment Target: ' + ex.message);
299
+ }
300
+ }
301
+ // all good let's loop a second time for actual execution
302
+ for (const sourceMlName of sourceMarketListArr) {
303
+ const targetMlName = properties.options.deployment.sourceTargetMapping[sourceMlName];
304
+ const sourceBU = Object.keys(properties.marketList[sourceMlName])[0];
305
+ const sourceMarket = Object.values(properties.marketList[sourceMlName])[0];
306
+
307
+ const delta = await DevOps.getDeltaList(properties, range, false, sourceBU);
308
+ // If only chaing templating and buildDefinition if required
309
+ if (!delta || delta.length === 0) {
310
+ // info/error messages was printed by DevOps.createDeltaPkg() already
311
+ return;
312
+ }
313
+ Util.logger.info('=============');
314
+
315
+ // Put files into maps. One map with BU -> type -> file (for retrieveAsTemplate)
316
+ // Other map only with type -> file (for buildDefinitionBulk)
317
+ const buTypeDelta = {}; // for bt, with BU info
318
+ const typeDelta = {}; // for bdb, without BU info - thats taken from the marketList
319
+ let deltaCounter = 0;
320
+ const deltaDeploy = delta
321
+ // Only template/build files that were added/updated/moved. no deletions
322
+ // ! doesn't work for folder, because their name parsing doesnt work at the moment
323
+ .filter((file) => file.gitAction !== 'delete' && file.name);
324
+ deltaDeployAll.push(...deltaDeploy);
325
+ for (const file of deltaDeploy) {
326
+ const buPath = `${file._credential}/${file._businessUnit}`;
327
+ if (!buTypeDelta[buPath]) {
328
+ // init object
329
+ buTypeDelta[buPath] = {};
330
+ }
331
+ if (!buTypeDelta[buPath][file.type]) {
332
+ // init array
333
+ buTypeDelta[buPath][file.type] = [];
334
+ }
335
+ buTypeDelta[buPath][file.type].push(file.externalKey);
336
+ }
337
+
338
+ // Run buildTemplate for each business unit for each type
339
+ Util.logger.info('Retrieve template from Git delta');
340
+ // ! needs to be for (.. in ..) loop so that it gets executed in series
341
+ for (const bu in buTypeDelta) {
342
+ for (const type in buTypeDelta[bu]) {
343
+ // get unique list (original search might include more than one entry for types with docs or extracted code)
344
+ const keyArr = [...new Set(buTypeDelta[bu][type])];
345
+ Util.logger.info(
346
+ `⚡ mcdev bt ${bu} ${type} "${keyArr.join(',')}" ${sourceMarket}`
347
+ );
348
+ await Builder.buildTemplate(bu, type, keyArr, sourceMarket);
349
+ // ensure we have the right key for bd/bdb that matches the name used for rt
350
+ if (keyArr.length) {
351
+ if (!typeDelta[type]) {
352
+ // init array
353
+ typeDelta[type] = [];
354
+ }
355
+ typeDelta[type].push(...keyArr);
356
+ deltaCounter += keyArr.length;
357
+ }
358
+ }
359
+ }
360
+ if (deltaCounter) {
361
+ Util.logger.info(`- ✔️ Templates created: ${deltaCounter}`);
362
+ } else {
363
+ Util.logger.warn(
364
+ `- No Templates or Deploy Definitions created for ${sourceMlName}`
365
+ );
366
+ continue;
367
+ }
368
+
369
+ // Run build definitions bulk for each type
370
+ Util.logger.info('=============');
371
+ Util.logger.info('Build deploy definitions from delta templates');
372
+ if (
373
+ properties.directories.templateBuilds == properties.directories.deploy ||
374
+ (Array.isArray(properties.directories.templateBuilds) &&
375
+ properties.directories.templateBuilds.includes(properties.directories.deploy))
376
+ ) {
377
+ let responses;
378
+ if (!skipInteraction) {
379
+ // deploy folder is in targets for definition creation
380
+ // recommend to purge their content first
381
+ responses = await inquirer.prompt([
382
+ {
383
+ type: 'confirm',
384
+ name: 'isPurgeDeployFolder',
385
+ message:
386
+ 'Do you want to empty the deploy folder (ensures no files from previous deployments remain)?',
387
+ default: true,
388
+ },
389
+ ]);
390
+ }
391
+ if (skipInteraction || responses.isPurgeDeployFolders) {
392
+ // Clear output folder structure for selected sub-type
393
+ await File.remove(File.normalizePath([properties.directories.deploy]));
394
+ }
395
+ }
396
+ const bdPromises = [];
397
+ for (const type in typeDelta) {
398
+ Util.logger.info(
399
+ `⚡ mcdev bdb ${targetMlName} ${type} "${typeDelta[type].join(',')}"`
400
+ );
401
+ // omitting "await" to speed up creation
402
+ bdPromises.push(
403
+ Builder.buildDefinitionBulk(targetMlName, type, typeDelta[type].join(','))
404
+ );
405
+ }
406
+ await Promise.all(bdPromises);
407
+ Util.logger.info(`- ✔️ Deploy defintions created`);
408
+ if (
409
+ properties.directories.templateBuilds == properties.directories.deploy ||
410
+ (Array.isArray(properties.directories.templateBuilds) &&
411
+ properties.directories.templateBuilds.includes(properties.directories.deploy))
412
+ ) {
413
+ Util.logger.info(`You can now run deploy on the prepared BUs`);
414
+ } else {
415
+ Util.logger.info(
416
+ `Your templated defintions are now ready to be copied into the deploy folder. Hint: You can have this auto-copied if you adjust directories.templateBuilds in your config.`
417
+ );
418
+ }
419
+ }
420
+ if (!deltaDeployAll.length) {
421
+ Util.logger.error(
422
+ '- ❌ No Templates or Deploy Definitions created. Check if you expected no changes.'
423
+ );
424
+ }
425
+ return deltaDeployAll;
426
+ },
427
+
244
428
  /**
245
429
  * create markdown file for deployment listing
246
- * @param {String} directory -
247
- * @param {Object} jsonReport -
430
+ *
431
+ * @param {string} directory -
432
+ * @param {object} jsonReport -
248
433
  * @returns {void}
249
434
  */
250
435
  document(directory, jsonReport) {
251
436
  const tabled = jsonToTable(jsonReport);
252
437
  let output = `# Deployment Report\n\n`;
253
438
  let tableSeparator = '';
254
- tabled[0].forEach((column) => {
439
+ for (const column of tabled[0]) {
255
440
  if (column !== '') {
256
441
  output += `| ${column} `;
257
442
  tableSeparator += '| --- ';
258
443
  }
259
- });
444
+ }
260
445
  output += `|\n${tableSeparator}|\n`;
261
446
  for (let i = 1; i < tabled.length; i++) {
262
- tabled[i].forEach((field) => {
447
+ for (let field of tabled[i]) {
263
448
  if (field !== '') {
264
449
  field = field === true ? '✓' : field === false ? '✗' : field;
265
450
  output += `| ${field} `;
266
451
  }
267
- });
452
+ }
268
453
  output += '|\n';
269
454
  }
270
455
  try {
@@ -274,6 +459,21 @@ const DevOps = {
274
459
  Util.logger.error(`DevOps.document():: error | ` + ex.message);
275
460
  }
276
461
  },
462
+ /**
463
+ * should return only the json for all but asset, query and script that are saved as multiple files
464
+ * additionally, the documentation for dataExtension and automation should be returned
465
+ *
466
+ * @param {TYPE.Mcdevrc} properties central properties object
467
+ * @param {TYPE.BuObject} buObject references credentials
468
+ * @param {string} metadataType metadata type to build
469
+ * @param {string[]} keyArr customerkey of the metadata
470
+ * @returns {Promise.<string[]>} list of all files that need to be committed in a flat array ['path/file1.ext', 'path/file2.ext']
471
+ */
472
+ getFilesToCommit(properties, buObject, metadataType, keyArr) {
473
+ MetadataType[metadataType].properties = properties;
474
+ MetadataType[metadataType].buObject = buObject;
475
+ return MetadataType[metadataType].getFilesToCommit(keyArr);
476
+ },
277
477
  };
278
478
 
279
479
  module.exports = DevOps;