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/jsconfig.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "include": ["lib/**/*.js"]
2
+ "include": ["lib/**/*.js", "types/**/*.js"]
3
3
  }
package/lib/Builder.js CHANGED
@@ -1,7 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ const TYPE = require('../types/mcdev.d');
3
4
  const Util = require('./util/util');
4
-
5
+ const File = require('./util/file');
6
+ const config = require('./util/config');
7
+ const Cli = require('./util/cli');
8
+ const auth = require('./util/auth');
5
9
  const MetadataTypeInfo = require('./MetadataTypeInfo');
6
10
  // @ts-ignore
7
11
 
@@ -12,50 +16,46 @@ class Builder {
12
16
  /**
13
17
  * Creates a Builder, uses v2 auth if v2AuthOptions are passed.
14
18
  *
15
- * @param {Object} properties properties for auth
16
- * @param {String} properties.clientId clientId for FuelSDK auth
17
- * @param {String} properties.clientSecret clientSecret for FuelSDK auth
18
- * @param {Object} properties.directories list of default directories
19
- * @param {String} properties.directories.template where templates are saved
20
- * @param {String} properties.directories.templateBuilds where template-based deployment definitions are saved
21
- * @param {String} properties.tenant v2 Auth Tenant Information
22
- * @param {String} properties.businessUnits ID of Business Unit to authenticate with
23
- * @param {Object} buObject properties for auth
24
- * @param {String} buObject.clientId clientId for FuelSDK auth
25
- * @param {String} buObject.clientSecret clientSecret for FuelSDK auth
26
- * @param {Object} buObject.credential clientId for FuelSDK auth
27
- * @param {String} buObject.tenant v2 Auth Tenant Information
28
- * @param {String} buObject.mid ID of Business Unit to authenticate with
29
- * @param {String} buObject.businessUnit name of Business Unit to authenticate with
30
- * @param {Util.ET_Client} client fuel client
19
+ * @param {TYPE.Mcdevrc} properties properties for auth
20
+ saved
21
+ * @param {TYPE.BuObject} buObject properties for auth
31
22
  */
32
- constructor(properties, buObject, client) {
33
- this.client = client;
23
+ constructor(properties, buObject) {
34
24
  this.properties = properties;
35
25
  this.templateDir = properties.directories.template;
26
+ this.retrieveDir = File.normalizePath([
27
+ properties.directories.retrieve,
28
+ buObject.credential,
29
+ buObject.businessUnit,
30
+ ]);
31
+ this.buObject = buObject;
36
32
 
37
33
  // allow multiple target directories
38
34
  const templateBuildsArr = Array.isArray(properties.directories.templateBuilds)
39
35
  ? properties.directories.templateBuilds
40
36
  : [properties.directories.templateBuilds];
41
-
42
37
  this.targetDir = templateBuildsArr.map(
43
38
  (directoriesTemplateBuilds) =>
44
39
  directoriesTemplateBuilds + buObject.credential + '/' + buObject.businessUnit
45
40
  );
46
41
 
42
+ /**
43
+ * @type {TYPE.MultiMetadataTypeList}
44
+ */
47
45
  this.metadata = {};
48
46
  }
49
47
 
50
48
  /**
51
49
  * Builds a specific metadata file by name
52
- * @param {String} metadataType metadata type to build
53
- * @param {String} name name of metadata to build
54
- * @param {Object} variables variables to be replaced in the metadata
55
- * @returns {Promise} Promise
50
+ *
51
+ * @param {string} metadataType metadata type to build
52
+ * @param {string} name name of metadata to build
53
+ * @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
54
+ * @returns {Promise.<TYPE.MultiMetadataTypeList>} Promise
56
55
  */
57
- async buildDefinition(metadataType, name, variables) {
56
+ async _buildDefinition(metadataType, name, templateVariables) {
58
57
  let nameArr;
58
+ /* eslint-disable unicorn/prefer-ternary */
59
59
  if (name.includes(',')) {
60
60
  nameArr = name.split(',').map((item) =>
61
61
  // allow whitespace in comma-separated lists
@@ -64,6 +64,8 @@ class Builder {
64
64
  } else {
65
65
  nameArr = [name.trim()];
66
66
  }
67
+ /* eslint-enable unicorn/prefer-ternary */
68
+
67
69
  const type = metadataType;
68
70
  try {
69
71
  const result = await Promise.all(
@@ -72,78 +74,173 @@ class Builder {
72
74
  // we hence require users to put %20 in their stead and have to convert that back
73
75
  name = name.split('%20').join(' ');
74
76
 
75
- MetadataTypeInfo[type].cache = null;
76
- MetadataTypeInfo[type].client = this.client;
77
+ MetadataTypeInfo[type].client = auth.getSDK(this.buObject);
77
78
  MetadataTypeInfo[type].properties = this.properties;
79
+ MetadataTypeInfo[type].buObject = this.buObject;
78
80
  return MetadataTypeInfo[type].buildDefinition(
79
81
  this.templateDir,
80
82
  this.targetDir,
81
83
  name,
82
- variables
84
+ templateVariables
83
85
  );
84
86
  })
85
87
  );
86
88
  if (result) {
87
89
  this.metadata[result[0].type] = [];
88
- result.forEach((element) => {
90
+ for (const element of result) {
89
91
  this.metadata[result[0].type].push(element.metadata);
90
- });
92
+ }
91
93
  }
92
94
  } catch (ex) {
93
- Util.logger.error('mcdev.buildDefinition:' + ex.message);
94
- Util.logger.debug(ex.stack);
95
- if (Util.logger.level === 'debug') {
96
- console.log(ex.stack);
95
+ Util.logger.errorStack(ex, 'mcdev.buildDefinition');
96
+ }
97
+ return this.metadata;
98
+ }
99
+ /**
100
+ * Build a template based on a list of metadata files in the retrieve folder.
101
+ *
102
+ * @param {string} businessUnit references credentials from properties.json
103
+ * @param {string} selectedType supported metadata type
104
+ * @param {string[]} keyArr customerkey of the metadata
105
+ * @param {string} market market localizations
106
+ * @returns {Promise.<TYPE.MultiMetadataTypeList>} -
107
+ */
108
+ static async buildTemplate(businessUnit, selectedType, keyArr, market) {
109
+ const properties = await config.getProperties();
110
+ if (!(await config.checkProperties(properties))) {
111
+ return null;
112
+ }
113
+ if (!Util._isValidType(selectedType)) {
114
+ return;
115
+ }
116
+ if (selectedType.includes('-')) {
117
+ Util.logger.error(
118
+ `:: '${selectedType}' is not a valid metadata type. Please don't include subtypes.`
119
+ );
120
+ return;
121
+ }
122
+ const buObject = await Cli.getCredentialObject(properties, businessUnit);
123
+ if (buObject !== null) {
124
+ const builder = new Builder(properties, buObject);
125
+ if (Util.checkMarket(market, properties)) {
126
+ return builder._buildTemplate(selectedType, keyArr, properties.markets[market]);
97
127
  }
98
128
  }
129
+ }
130
+ /**
131
+ * Build a template based on a list of metadata files in the retrieve folder.
132
+ *
133
+ * @param {string} metadataType metadata type to create a template of
134
+ * @param {string[]} keyArr customerkey of metadata to create a template of
135
+ * @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
136
+ * @returns {Promise.<TYPE.MultiMetadataTypeList>} Promise
137
+ */
138
+ async _buildTemplate(metadataType, keyArr, templateVariables) {
139
+ const type = metadataType;
140
+ try {
141
+ /** @type {TYPE.MetadataTypeItemObj[]} */
142
+ const result = await Promise.all(
143
+ keyArr.map((key) => {
144
+ MetadataTypeInfo[type].client = this.client;
145
+ MetadataTypeInfo[type].properties = this.properties;
146
+ MetadataTypeInfo[type].buObject = this.buObject;
147
+
148
+ /** @type {TYPE.MetadataTypeItemObj} */
149
+ return MetadataTypeInfo[type].buildTemplate(
150
+ this.retrieveDir,
151
+ this.templateDir,
152
+ key,
153
+ templateVariables
154
+ );
155
+ })
156
+ );
157
+ if (result) {
158
+ this.metadata[result[0].type] = result.map((element) => element.metadata);
159
+ }
160
+ } catch (ex) {
161
+ Util.logger.errorStack(ex, 'mcdev.buildTemplate');
162
+ }
99
163
  return this.metadata;
100
164
  }
101
165
  /**
102
- * ensure provided MarketList exists and it's content including markets and BUs checks out
103
- * @param {String} mlName name of marketList
104
- * @param {Object} properties General configuration to be used in retrieve
105
- * @param {Object} properties.markets list of template variable combos
106
- * @param {Object} properties.marketList list of bu-market combos
107
- * @param {Object} properties.credentials list of credentials and their BUs
108
- * @returns {void} throws errors if problems were found
166
+ * Build a specific metadata file based on a template.
167
+ *
168
+ * @param {string} businessUnit references credentials from properties.json
169
+ * @param {string} selectedType supported metadata type
170
+ * @param {string} name name of the metadata
171
+ * @param {string} market market localizations
172
+ * @returns {Promise.<TYPE.MultiMetadataTypeList>} -
109
173
  */
110
- static verifyMarketList(mlName, properties) {
111
- if (!properties.marketList[mlName]) {
112
- // ML does not exist
113
- throw new Error(`Market List ${mlName} is not defined`);
114
- } else {
115
- // ML exists, check if it is properly set up
174
+ static async buildDefinition(businessUnit, selectedType, name, market) {
175
+ const properties = await config.getProperties();
176
+ if (!(await config.checkProperties(properties))) {
177
+ return null;
178
+ }
179
+ if (!Util._isValidType(selectedType)) {
180
+ return;
181
+ }
182
+ if (selectedType.includes('-')) {
183
+ Util.logger.error(
184
+ `:: '${selectedType}' is not a valid metadata type. Please don't include subtypes.`
185
+ );
186
+ return;
187
+ }
188
+ const buObject = await Cli.getCredentialObject(properties, businessUnit);
189
+ if (buObject !== null) {
190
+ const builder = new Builder(properties, buObject);
191
+ if (Util.checkMarket(market, properties)) {
192
+ return builder._buildDefinition(selectedType, name, properties.markets[market]);
193
+ }
194
+ }
195
+ }
196
+ /**
197
+ * Build a specific metadata file based on a template using a list of bu-market combos
198
+ *
199
+ * @param {string} listName name of list of BU-market combos
200
+ * @param {string} type supported metadata type
201
+ * @param {string} name name of the metadata
202
+ * @returns {Promise.<TYPE.MultiMetadataTypeList[]>} -
203
+ */
204
+ static async buildDefinitionBulk(listName, type, name) {
205
+ const properties = await config.getProperties();
206
+ if (!(await config.checkProperties(properties))) {
207
+ return null;
208
+ }
209
+ Util.verifyMarketList(listName, properties);
210
+ if (type && !MetadataTypeInfo[type]) {
211
+ Util.logger.error(`:: '${type}' is not a valid metadata type`);
212
+ return;
213
+ }
214
+ let i = 0;
215
+ const bdPromises = [];
116
216
 
117
- // check if BUs in marketList are valid
118
- let buCounter = 0;
119
- for (const businessUnit in properties.marketList[mlName]) {
120
- if (businessUnit !== 'description') {
121
- buCounter++;
122
- const [cred, bu] = businessUnit ? businessUnit.split('/') : [null, null];
123
- if (
124
- !properties.credentials[cred] ||
125
- !properties.credentials[cred].businessUnits[bu]
126
- ) {
127
- throw new Error(`'${businessUnit}' in Market ${mlName} is not defined.`);
128
- }
129
- // check if markets are valid
130
- let marketArr = properties.marketList[mlName][businessUnit];
131
- if ('string' === typeof marketArr) {
132
- marketArr = [marketArr];
133
- }
134
- for (const market of marketArr) {
135
- if (!properties.markets[market]) {
136
- throw new Error(`Market '${market}' is not defined.`);
137
- } else {
138
- // * markets can be empty or include variables. Nothing we can test here
139
- }
140
- }
141
- }
217
+ for (const businessUnit in properties.marketList[listName]) {
218
+ if (businessUnit === 'description') {
219
+ // skip, it's just a metadata on this list and not a BU
220
+ continue;
221
+ }
222
+ i++;
223
+ const market = properties.marketList[listName][businessUnit];
224
+ let marketList = [];
225
+ if ('string' === typeof market) {
226
+ marketList.push(market);
227
+ } else {
228
+ marketList = market;
142
229
  }
143
- if (!buCounter) {
144
- throw new Error(`No BUs defined in marketList ${mlName}`);
230
+ for (const market of marketList) {
231
+ if (Util.checkMarket(market, properties)) {
232
+ Util.logger.info(`Executing for '${businessUnit}': '${market}'`);
233
+ // omitting "await" to speed up creation
234
+ bdPromises.push(this.buildDefinition(businessUnit, type, name, market));
235
+ }
145
236
  }
146
237
  }
238
+ const response = await Promise.all(bdPromises);
239
+
240
+ if (!i) {
241
+ Util.logger.error('Please define properties.marketList in your config');
242
+ }
243
+ return response;
147
244
  }
148
245
  }
149
246