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
package/lib/Deployer.js CHANGED
@@ -1,9 +1,14 @@
1
1
  'use strict';
2
2
 
3
+ const TYPE = require('../types/mcdev.d');
3
4
  const MetadataTypeInfo = require('./MetadataTypeInfo');
4
- const path = require('path');
5
+ const path = require('node:path');
6
+ const Cli = require('./util/cli');
5
7
  const Util = require('./util/util');
6
8
  const File = require('./util/file');
9
+ const config = require('./util/config');
10
+ const cache = require('./util/cache');
11
+ const auth = require('./util/auth');
7
12
 
8
13
  /**
9
14
  * Reads metadata from local directory and deploys it to specified target business unit.
@@ -14,21 +19,11 @@ class Deployer {
14
19
  * Creates a Deployer, uses v2 auth if v2AuthOptions are passed.
15
20
  *
16
21
  *
17
- * @param {Object} properties General configuration to be used in retrieve
18
- * @param {Object} properties.directories Directories to be used when interacting with FS
19
- * @param {Object} buObject properties for auth
20
- * @param {String} buObject.clientId clientId for FuelSDK auth
21
- * @param {String} buObject.clientSecret clientSecret for FuelSDK auth
22
- * @param {Object} buObject.credential clientId for FuelSDK auth
23
- * @param {String} buObject.tenant v2 Auth Tenant Information
24
- * @param {String} buObject.mid ID of Business Unit to authenticate with
25
- * @param {String} buObject.businessUnit name of Business Unit to authenticate with
26
- * @param {Util.ET_Client} client fuel client
27
- * @param {String} [type] limit deployment to given metadata type
22
+ * @param {TYPE.Mcdevrc} properties General configuration to be used in retrieve
23
+ * @param {TYPE.BuObject} buObject properties for auth
28
24
  */
29
- constructor(properties, buObject, client, type) {
25
+ constructor(properties, buObject) {
30
26
  this.buObject = buObject;
31
- this.client = client;
32
27
  this.properties = properties;
33
28
  this.deployDir = File.normalizePath([
34
29
  properties.directories.deploy,
@@ -41,70 +36,217 @@ class Deployer {
41
36
  buObject.businessUnit,
42
37
  ]);
43
38
  // prep folders for auto-creation
44
- MetadataTypeInfo.folder.cache = this.cache;
45
- MetadataTypeInfo.folder.client = this.client;
39
+ MetadataTypeInfo.folder.client = auth.getSDK(buObject);
46
40
  MetadataTypeInfo.folder.properties = this.properties;
47
41
  // Remove tmp folder of previous deploys
48
42
  File.removeSync('tmp');
49
- if (File.existsSync(this.deployDir)) {
50
- this.metadata = Deployer.readBUMetadata(this.deployDir, type);
51
- } else {
52
- this.metadata = null;
53
- Util.logger.warn(
54
- 'Deployer.constructor:: Please create a directory called deploy and include your metadata in it: ./' +
55
- this.deployDir
43
+ }
44
+ /**
45
+ * Deploys all metadata located in the 'deploy' directory to the specified business unit
46
+ *
47
+ * @param {string} businessUnit references credentials from properties.json
48
+ * @param {string[]} [selectedTypesArr] limit deployment to given metadata type
49
+ * @param {string[]} [keyArr] limit deployment to given metadata keys
50
+ * @param {boolean} [fromRetrieve] optionally deploy whats defined via selectedTypesArr + keyArr directly from retrieve folder instead of from deploy folder
51
+ * @returns {Promise.<void>} -
52
+ */
53
+ static async deploy(businessUnit, selectedTypesArr, keyArr, fromRetrieve) {
54
+ Util.logger.info('mcdev:: Deploy');
55
+ const properties = await config.getProperties();
56
+ if (!(await config.checkProperties(properties))) {
57
+ return null;
58
+ }
59
+ if (fromRetrieve) {
60
+ properties.directories.deploy = properties.directories.retrieve;
61
+ }
62
+ if (Array.isArray(selectedTypesArr)) {
63
+ // types and keys can be provided but for each type all provided keys are applied as filter
64
+ for (const selectedType of selectedTypesArr) {
65
+ if (!Util._isValidType(selectedType)) {
66
+ return;
67
+ }
68
+ }
69
+ }
70
+ if (
71
+ fromRetrieve &&
72
+ (!selectedTypesArr ||
73
+ !Array.isArray(selectedTypesArr) ||
74
+ !selectedTypesArr.length ||
75
+ !keyArr ||
76
+ !Array.isArray(keyArr) ||
77
+ !keyArr.length)
78
+ ) {
79
+ Util.logger.error('type & key need to be defined to deploy from retrieve folder');
80
+ return;
81
+ }
82
+ let counter_credBu = 0;
83
+ if (businessUnit === '*') {
84
+ // all credentials and all BUs shall be deployed to
85
+ const deployFolders = await File.readDirectories(
86
+ properties.directories.deploy,
87
+ 2,
88
+ false
56
89
  );
90
+ for (const buPath of deployFolders.filter((r) => r.includes(path.sep))) {
91
+ const [cred, bu] = buPath.split(path.sep);
92
+ await this._deployBU(cred, bu, properties, selectedTypesArr, keyArr, fromRetrieve);
93
+ counter_credBu++;
94
+ Util.logger.info('');
95
+ Util.restartLogger();
96
+ }
97
+ } else {
98
+ // anything but "*" passed in
99
+ let [cred, bu] = businessUnit ? businessUnit.split('/') : [null, null];
100
+
101
+ // to allow all-BU via user selection we need to run this here already
102
+ if (
103
+ properties.credentials &&
104
+ (!properties.credentials[cred] ||
105
+ (bu !== '*' && properties.credentials[cred].businessUnits[bu]))
106
+ ) {
107
+ const buObject = await Cli.getCredentialObject(
108
+ properties,
109
+ cred !== null ? cred + '/' + bu : null,
110
+ null,
111
+ true
112
+ );
113
+ if (buObject !== null) {
114
+ cred = buObject.credential;
115
+ bu = buObject.businessUnit;
116
+ } else {
117
+ return;
118
+ }
119
+ }
120
+
121
+ if (bu === '*' && properties.credentials && properties.credentials[cred]) {
122
+ // valid credential given and -all- BUs targeted
123
+ Util.logger.info(`\n :: Deploying all BUs for ${cred}`);
124
+ let counter_credBu = 0;
125
+ // for (const bu in properties.credentials[cred].businessUnits) {
126
+ const deployFolders = await File.readDirectories(
127
+ File.normalizePath([properties.directories.deploy, cred]),
128
+ 1,
129
+ false
130
+ );
131
+ for (const buPath of deployFolders) {
132
+ await this._deployBU(
133
+ cred,
134
+ buPath,
135
+ properties,
136
+ selectedTypesArr,
137
+ keyArr,
138
+ fromRetrieve
139
+ );
140
+ counter_credBu++;
141
+ Util.logger.info('');
142
+ Util.restartLogger();
143
+ }
144
+ Util.logger.info(`\n :: ${counter_credBu} BUs for ${cred}\n`);
145
+ } else {
146
+ // either bad credential or specific BU or no BU given
147
+ await this._deployBU(cred, bu, properties, selectedTypesArr, keyArr, fromRetrieve);
148
+ counter_credBu++;
149
+ }
150
+ }
151
+ if (counter_credBu !== 0) {
152
+ Util.logger.info(`\n :: Deployed ${counter_credBu} BUs\n`);
153
+ }
154
+ }
155
+ /**
156
+ * helper for deploy()
157
+ *
158
+ * @param {string} cred name of Credential
159
+ * @param {string} bu name of BU
160
+ * @param {TYPE.Mcdevrc} properties General configuration to be used in retrieve
161
+ * @param {string[]} [typeArr] limit deployment to given metadata type
162
+ * @param {string[]} [keyArr] limit deployment to given metadata keys
163
+ * @param {boolean} [fromRetrieve] optionally deploy whats defined via selectedTypesArr + keyArr directly from retrieve folder instead of from deploy folder
164
+ * @returns {Promise} ensure that BUs are worked on sequentially
165
+ */
166
+ static async _deployBU(cred, bu, properties, typeArr, keyArr, fromRetrieve) {
167
+ const buPath = `${cred}/${bu}`;
168
+ Util.logger.info(`::Deploying ${buPath}`);
169
+ const buObject = await Cli.getCredentialObject(properties, buPath, null, true);
170
+ if (buObject !== null) {
171
+ cache.initCache(buObject);
172
+ const deployer = new Deployer(properties, buObject);
173
+ try {
174
+ // await is required or the calls end up conflicting
175
+ await deployer._deploy(typeArr, keyArr, fromRetrieve);
176
+ } catch (ex) {
177
+ Util.logger.errorStack(ex, 'mcdev.deploy failed');
178
+ }
57
179
  }
58
- this.cache = {};
59
180
  }
181
+
60
182
  /**
61
183
  * Deploy all metadata that is located in the deployDir
184
+ *
185
+ * @param {string[]} [typeArr] limit deployment to given metadata type (can include subtype)
186
+ * @param {string[]} [keyArr] limit deployment to given metadata keys
187
+ * @param {boolean} [fromRetrieve] if true, no folders will be updated/created
62
188
  * @returns {Promise} Promise
63
189
  */
64
- async deploy() {
190
+ async _deploy(typeArr, keyArr, fromRetrieve) {
191
+ if (await File.pathExists(this.deployDir)) {
192
+ /** @type {TYPE.MultiMetadataTypeMap} */
193
+ this.metadata = Deployer.readBUMetadata(this.deployDir, typeArr);
194
+ if (typeArr) {
195
+ for (const selectedType of typeArr) {
196
+ const type = selectedType.split('-')[0];
197
+ this.metadata[type] = Util.filterObjByKeys(this.metadata[type], keyArr);
198
+ }
199
+ }
200
+ } else {
201
+ this.metadata = null;
202
+ Util.logger.error(
203
+ 'Deployer.constructor:: Please create a directory called deploy and include your metadata in it: ./' +
204
+ this.deployDir
205
+ );
206
+ }
65
207
  if (this.metadata === null || !Object.keys(this.metadata).length) {
66
- Util.logger.warn('No metadata found in deploy folder for selected BU');
208
+ Util.logger.error('No metadata found in deploy folder for selected BU');
67
209
  return null;
68
210
  }
69
- await Deployer.createFolderDefinitions(
70
- this.deployDir,
71
- this.metadata,
72
- Object.keys(this.metadata)
211
+ if (!fromRetrieve) {
212
+ await Deployer.createFolderDefinitions(
213
+ this.deployDir,
214
+ this.metadata,
215
+ Object.keys(this.metadata)
216
+ );
217
+ }
218
+ const foundDeployTypes = Object.keys(this.metadata).map((item) =>
219
+ item === 'asset' && Util.includesStartsWith(typeArr, item)
220
+ ? typeArr[Util.includesStartsWithIndex(typeArr, item)]
221
+ : item
73
222
  );
74
-
75
- const deployOrder = Util.getMetadataHierachy(Object.keys(this.metadata));
223
+ const deployOrder = Util.getMetadataHierachy(foundDeployTypes);
76
224
  // build cache, including all metadata types which will be deployed (Avoids retrieve later)
77
225
  for (const metadataType of deployOrder) {
78
226
  const [type, subType] = metadataType.split('-');
79
227
  // add metadata & client to metadata process class instead of passing cache/mapping every time
80
- MetadataTypeInfo[type].cache = this.cache;
81
- MetadataTypeInfo[type].client = this.client;
228
+ MetadataTypeInfo[type].client = auth.getSDK(this.buObject);
82
229
  MetadataTypeInfo[type].properties = this.properties;
230
+ MetadataTypeInfo[type].buObject = this.buObject;
83
231
  Util.logger.info('Caching dependent Metadata: ' + metadataType);
84
- let result;
85
- await Util.retryOnError(`Retrying ${type}`, async () => {
86
- result = await MetadataTypeInfo[type].retrieveForCache(this.buObject, subType);
87
- });
88
- this.cache[type] = result.metadata;
232
+ const result = await MetadataTypeInfo[type].retrieveForCache(this.buObject, subType);
233
+ cache.setMetadata(type, result.metadata);
89
234
  }
90
235
  // deploy metadata files, extending cache once deploys
91
236
  for (const metadataType of deployOrder) {
92
- let result;
93
237
  // TODO rewrite to allow deploying only a specific sub-type
94
238
  // const [type, subType] = metadataType.split('-');
95
239
  const type = metadataType.split('-')[0];
96
240
  if (this.metadata[type]) {
97
- MetadataTypeInfo[type].cache = this.cache;
98
241
  Util.logger.info('Deploying: ' + metadataType);
99
- await Util.retryOnError(`Retrying ${metadataType}`, async () => {
100
- result = await MetadataTypeInfo[type].deploy(
101
- this.metadata[type],
102
- this.deployDir,
103
- this.retrieveDir,
104
- this.buObject
105
- );
106
- });
107
- this.cache[type] = Object.assign(this.cache[type], result);
242
+
243
+ const result = await MetadataTypeInfo[type].deploy(
244
+ this.metadata[type],
245
+ this.deployDir,
246
+ this.retrieveDir,
247
+ this.buObject
248
+ );
249
+ cache.mergeMetadata(type, result);
108
250
  this.deployCallback(result, type);
109
251
  }
110
252
  }
@@ -112,8 +254,9 @@ class Deployer {
112
254
 
113
255
  /**
114
256
  * Gets called for every deployed metadata entry
115
- * @param {Object} result Deployment result
116
- * @param {String} metadataType Name of metadata type
257
+ *
258
+ * @param {object} result Deployment result
259
+ * @param {string} metadataType Name of metadata type
117
260
  * @returns {void}
118
261
  */
119
262
  deployCallback(result, metadataType) {
@@ -128,30 +271,35 @@ class Deployer {
128
271
 
129
272
  /**
130
273
  * Returns metadata of a business unit that is saved locally
131
- * @param {String} deployDir root directory of metadata.
132
- * @param {String} [type] limit deployment to given metadata type
274
+ *
275
+ * @param {string} deployDir root directory of metadata.
276
+ * @param {string[]} [typeArr] limit deployment to given metadata type
133
277
  * @param {boolean} [listBadKeys=false] do not print errors, used for badKeys()
134
- * @returns {Object} Metadata of BU in local directory
278
+ * @returns {TYPE.MultiMetadataTypeMap} Metadata of BU in local directory
135
279
  */
136
- static readBUMetadata(deployDir, type, listBadKeys) {
280
+ static readBUMetadata(deployDir, typeArr, listBadKeys) {
281
+ /** @type {TYPE.MultiMetadataTypeMap} */
137
282
  const buMetadata = {};
138
283
  try {
139
- if (File.existsSync(deployDir)) {
140
- const metadataTypes = File.readdirSync(deployDir);
141
- metadataTypes.forEach((metadataType) => {
142
- if (MetadataTypeInfo[metadataType] && (!type || type === metadataType)) {
143
- // check if folder name is a valid metadataType, then check if the user limited to a certain type in the command params
144
- buMetadata[metadataType] = MetadataTypeInfo[metadataType].getJsonFromFS(
145
- File.normalizePath([deployDir, metadataType]),
146
- listBadKeys
147
- );
148
- }
149
- });
150
-
151
- return buMetadata;
152
- } else {
153
- throw new Error(`Directory '${deployDir}' does not exist.`);
284
+ File.ensureDirSync(deployDir);
285
+ const metadataTypes = File.readdirSync(deployDir);
286
+ for (const metadataType of metadataTypes) {
287
+ if (
288
+ MetadataTypeInfo[metadataType] &&
289
+ (!typeArr || Util.includesStartsWith(typeArr, metadataType))
290
+ ) {
291
+ // check if folder name is a valid metadataType, then check if the user limited to a certain type in the command params
292
+ buMetadata[metadataType] = MetadataTypeInfo[metadataType].getJsonFromFS(
293
+ File.normalizePath([deployDir, metadataType]),
294
+ listBadKeys,
295
+ typeArr
296
+ );
297
+ }
298
+ }
299
+ if (Object.keys(buMetadata).length === 0) {
300
+ throw new Error('No metadata found in deploy folder for selected BU & type');
154
301
  }
302
+ return buMetadata;
155
303
  } catch (ex) {
156
304
  throw new Error(ex.message);
157
305
  }
@@ -159,24 +307,23 @@ class Deployer {
159
307
 
160
308
  /**
161
309
  * parses asset metadata to auto-create folders in target folder
162
- * @param {String} deployDir root directory of metadata.
163
- * @param {Object} metadata list of metadata
164
- * @param {String} metadataTypeArr list of metadata types
310
+ *
311
+ * @param {string} deployDir root directory of metadata.
312
+ * @param {TYPE.MultiMetadataTypeMap} metadata list of metadata
313
+ * @param {TYPE.SupportedMetadataTypes[]} metadataTypeArr list of metadata types
165
314
  * @returns {void}
166
315
  */
167
316
  static async createFolderDefinitions(deployDir, metadata, metadataTypeArr) {
168
317
  let i = 0;
169
318
  const folderMetadata = {};
170
- metadataTypeArr.forEach((metadataType) => {
319
+ for (const metadataType of metadataTypeArr) {
171
320
  if (!MetadataTypeInfo[metadataType].definition.dependencies.includes('folder')) {
172
- Util.logger.debug(
173
- `_createFolderDefinitions(${metadataType}) - folder not a dependency`
174
- );
175
- return;
321
+ Util.logger.debug(` ☇ skipping ${metadataType}: folder not a dependency`);
322
+ continue;
176
323
  }
177
324
  if (!MetadataTypeInfo[metadataType].definition.folderType) {
178
- Util.logger.debug(`_createFolderDefinitions(${metadataType}) - folderType not set`);
179
- return;
325
+ Util.logger.debug(` ☇ skipping ${metadataType}: folderType not set`);
326
+ continue;
180
327
  }
181
328
  if (
182
329
  !MetadataTypeInfo.folder.definition.deployFolderTypes.includes(
@@ -184,9 +331,9 @@ class Deployer {
184
331
  )
185
332
  ) {
186
333
  Util.logger.warn(
187
- `_createFolderDefinitions(${metadataType}: ${MetadataTypeInfo[metadataType].definition.folderType}) - folderType not supported for deployment`
334
+ ` ☇ skipping ${metadataType}: folderType ${MetadataTypeInfo[metadataType].definition.folderType} not supported for deployment`
188
335
  );
189
- return;
336
+ continue;
190
337
  }
191
338
  Util.logger.debug(`Creating relevant folders for ${metadataType} in deploy dir`);
192
339
 
@@ -194,6 +341,7 @@ class Deployer {
194
341
  // filter out root folders (which would not have a slash in their path)
195
342
  (key) => metadata[metadataType][key].r__folder_Path.includes('/')
196
343
  );
344
+ /* eslint-disable unicorn/prefer-ternary */
197
345
  if (metadataType === 'dataExtension') {
198
346
  allFolders = allFolders
199
347
  .filter(
@@ -205,44 +353,44 @@ class Deployer {
205
353
  } else {
206
354
  allFolders = allFolders.map((key) => metadata[metadataType][key].r__folder_Path);
207
355
  }
356
+ /* eslint-enable unicorn/prefer-ternary */
357
+
208
358
  // deduplicate
209
359
  const folderPathSet = new Set(allFolders);
210
- [...folderPathSet].sort().forEach((item) => {
360
+ for (const item of [...folderPathSet].sort()) {
211
361
  let aggregatedPath = '';
212
362
  const parts = item.split('/');
213
- parts.forEach((pathElement) => {
363
+ for (const pathElement of parts) {
214
364
  if (aggregatedPath) {
215
365
  aggregatedPath += '/';
216
366
  }
217
367
  aggregatedPath += pathElement;
218
368
  folderPathSet.add(aggregatedPath);
219
- });
220
- });
369
+ }
370
+ }
221
371
  const folderPathArrExtended = [...folderPathSet]
222
372
  // strip root folders
223
373
  .filter((folderName) => folderName.includes('/'))
224
374
  .sort();
225
375
 
226
- folderPathArrExtended.forEach((folder) => {
376
+ for (const folder of folderPathArrExtended) {
227
377
  i++;
228
378
  folderMetadata[`on-the-fly-${i}`] = {
229
379
  Path: folder,
230
380
  Name: folder.split('/').pop(),
231
381
  Description: '',
232
382
  ContentType: MetadataTypeInfo[metadataType].definition.folderType,
233
- IsActive: 'true',
234
- IsEditable: 'true',
235
- AllowChildren: 'true',
383
+ IsActive: true,
384
+ IsEditable: true,
385
+ AllowChildren: true,
236
386
  };
237
- });
238
- });
387
+ }
388
+ }
239
389
 
240
390
  if (i > 0) {
241
- Util.logger.info(`Saving folders to deploy dir (${i}) - please wait`);
242
-
243
391
  // await results to allow us to re-read it right after
244
392
  await MetadataTypeInfo.folder.saveResults(folderMetadata, deployDir, null);
245
- Util.logger.info(`Saved: folders in deploy dir`);
393
+ Util.logger.info(`Created folders in deploy dir: ${i}`);
246
394
 
247
395
  // reload from file system to ensure we use the same logic for building the temporary JSON
248
396
  metadata.folder = MetadataTypeInfo.folder.getJsonFromFS(
@@ -26,6 +26,8 @@ const MetadataTypeDefinitions = {
26
26
  importFile: require('./metadataTypes/definitions/ImportFile.definition'),
27
27
  interaction: require('./metadataTypes/definitions/Interaction.definition'),
28
28
  list: require('./metadataTypes/definitions/List.definition'),
29
+ mobileCode: require('./metadataTypes/definitions/MobileCode.definition'),
30
+ mobileKeyword: require('./metadataTypes/definitions/MobileKeyword.definition'),
29
31
  query: require('./metadataTypes/definitions/Query.definition'),
30
32
  role: require('./metadataTypes/definitions/Role.definition'),
31
33
  script: require('./metadataTypes/definitions/Script.definition'),
@@ -26,6 +26,8 @@ const MetadataTypeInfo = {
26
26
  importFile: require('./metadataTypes/ImportFile'),
27
27
  interaction: require('./metadataTypes/Interaction'),
28
28
  list: require('./metadataTypes/List'),
29
+ mobileCode: require('./metadataTypes/MobileCode'),
30
+ mobileKeyword: require('./metadataTypes/MobileKeyword'),
29
31
  query: require('./metadataTypes/Query'),
30
32
  role: require('./metadataTypes/Role'),
31
33
  script: require('./metadataTypes/Script'),