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
@@ -0,0 +1,302 @@
1
+ const TYPE = require('../../types/mcdev.d');
2
+ const Util = require('./util');
3
+ const File = require('./file');
4
+ const inquirer = require('inquirer');
5
+ const semver = require('semver');
6
+ const path = require('node:path');
7
+ /**
8
+ * Central class for loading and validating properties from config and auth
9
+ */
10
+ const config = {
11
+ properties: null,
12
+
13
+ /**
14
+ * loads central properties from config file
15
+ *
16
+ * @param {boolean} [silent] omit throwing errors and print messages; assuming not silent if not set
17
+ * @returns {Promise.<TYPE.Mcdevrc>} central properties object
18
+ */
19
+ async getProperties(silent) {
20
+ if (config.properties) {
21
+ return config.properties;
22
+ }
23
+ if (await File.pathExists(Util.configFileName)) {
24
+ try {
25
+ config.properties = await File.readJson(Util.configFileName);
26
+ } catch (ex) {
27
+ Util.logger.error(`${ex.code}: ${ex.message}`);
28
+ return;
29
+ }
30
+ if (await File.pathExists(Util.authFileName)) {
31
+ let auth;
32
+ try {
33
+ auth = await File.readJson(Util.authFileName);
34
+ } catch (ex) {
35
+ Util.logger.error(`${ex.code}: ${ex.message}`);
36
+ return;
37
+ }
38
+
39
+ if (!auth) {
40
+ const err = `${Util.authFileName} is not set up correctly.`;
41
+ Util.logger.error(err);
42
+ throw new Error(err);
43
+ }
44
+ for (const cred in config.properties.credentials) {
45
+ if (auth[cred]) {
46
+ if (
47
+ config.properties.credentials[cred].eid != auth[cred].account_id &&
48
+ !silent
49
+ ) {
50
+ Util.logger.error(
51
+ `'${cred}' found in ${Util.configFileName} (${typeof config
52
+ .properties.credentials[cred].eid} ${
53
+ config.properties.credentials[cred].eid
54
+ }) and ${Util.authFileName} (${typeof auth[cred].account_id} ${
55
+ auth[cred].account_id
56
+ }) have a Enterprise ID mismatch. Please check.`
57
+ );
58
+ return;
59
+ }
60
+ // TODO add auth checks #294
61
+ } else if (!silent) {
62
+ Util.logger.error(
63
+ `'${cred}' found in ${Util.configFileName} but not in ${Util.authFileName}. Please run 'mcdev init' to provide the missing credential details.`
64
+ );
65
+ return;
66
+ }
67
+ }
68
+ } else if (!silent) {
69
+ Util.logger.error(
70
+ `${Util.authFileName} not found. Please run 'mcdev init' to provide the missing credential details.`
71
+ );
72
+ return;
73
+ }
74
+ }
75
+ return config.properties;
76
+ },
77
+ /**
78
+ * check if the config file is correctly formatted and has values
79
+ *
80
+ * @param {TYPE.Mcdevrc} properties javascript object in .mcdevrc.json
81
+ * @param {boolean} [silent] set to true for internal use w/o cli output
82
+ * @returns {Promise.<boolean | string[]>} file structure ok OR list of fields to be fixed
83
+ */
84
+ async checkProperties(properties, silent) {
85
+ if (!(await File.pathExists(Util.configFileName))) {
86
+ Util.logger.error(`Could not find ${Util.configFileName} in ${process.cwd()}.`);
87
+ Util.logger.error(`Run 'mcdev init' to initialize your project.\n`);
88
+ return false;
89
+ }
90
+ if (!(await File.pathExists(Util.authFileName))) {
91
+ Util.logger.error(`Could not find ${Util.authFileName} in ${process.cwd()}.`);
92
+ Util.logger.error(`Run 'mcdev init' to initialize your project.\n`);
93
+ return false;
94
+ }
95
+ if (!properties) {
96
+ // assume there was an error loading the config failed
97
+ return false;
98
+ }
99
+
100
+ // check if user is running older (ignores patches) mcdev version than whats saved to the config
101
+ if (properties.version && semver.gt(properties.version, Util.packageJsonMcdev.version)) {
102
+ Util.logger.error(
103
+ `Your Accenture SFMC DevTools version ${Util.packageJsonMcdev.version} is lower than your project's config version ${properties.version}`
104
+ );
105
+ if (Util.skipInteraction) {
106
+ return false;
107
+ }
108
+
109
+ const responses = await inquirer.prompt([
110
+ {
111
+ type: 'confirm',
112
+ name: 'runUpgradeNow',
113
+ message: `Do you want to run 'npm update -g mcdev@${properties.version}' now? This may take a few minutes.`,
114
+ default: true,
115
+ },
116
+ ]);
117
+ if (responses.runUpgradeNow) {
118
+ // use _execSync here to avoid a circular dependency
119
+ Util.execSync('npm', ['update', '-g', `mcdev@${properties.version}`]);
120
+ }
121
+ return false;
122
+ }
123
+
124
+ // check config properties
125
+ const defaultProps = await this.getDefaultProperties();
126
+ const errorMsgs = [];
127
+ const solutionSet = new Set();
128
+ const missingFields = [];
129
+ for (const key in defaultProps) {
130
+ if (Object.prototype.hasOwnProperty.call(defaultProps, key)) {
131
+ if (!Object.prototype.hasOwnProperty.call(properties, key)) {
132
+ errorMsgs.push(`${key}{} missing`);
133
+ solutionSet.add(
134
+ `Run 'mcdev upgrade' to fix missing or changed configuration options`
135
+ );
136
+ missingFields.push(key);
137
+ } else {
138
+ if (!silent && key === 'credentials') {
139
+ if (!Object.keys(properties.credentials)) {
140
+ errorMsgs.push(`no Credential defined`);
141
+ } else {
142
+ for (const cred in properties.credentials) {
143
+ if (cred.includes('/') || cred.includes('\\')) {
144
+ errorMsgs.push(
145
+ `Credential names may not includes slashes: ${cred}`
146
+ );
147
+ solutionSet.add('Apply manual fix in your config.');
148
+ }
149
+ if (
150
+ !properties.credentials[cred].eid ||
151
+ properties.credentials[cred].eid === 0
152
+ ) {
153
+ errorMsgs.push(`invalid account_id (EID) on ${cred}`);
154
+ solutionSet.add(`Run 'mcdev init ${cred}'`);
155
+ }
156
+ let i = 0;
157
+ for (const buName in properties.credentials[cred].businessUnits) {
158
+ if (buName.includes('/') || buName.includes('\\')) {
159
+ errorMsgs.push(
160
+ `Business Unit names may not includes slashes: ${cred}: ${buName}`
161
+ );
162
+ solutionSet.add(`Run 'mcdev reloadBUs ${cred}'`);
163
+ }
164
+ if (
165
+ Object.prototype.hasOwnProperty.call(
166
+ properties.credentials[cred].businessUnits,
167
+ buName
168
+ ) &&
169
+ properties.credentials[cred].businessUnits[buName] !== 0
170
+ ) {
171
+ i++;
172
+ }
173
+ }
174
+ if (!i) {
175
+ errorMsgs.push(`no Business Units defined`);
176
+ solutionSet.add(`Run 'mcdev reloadBUs ${cred}'`);
177
+ }
178
+ }
179
+ }
180
+ } else if (['directories', 'metaDataTypes', 'options'].includes(key)) {
181
+ for (const subkey in defaultProps[key]) {
182
+ if (
183
+ Object.prototype.hasOwnProperty.call(defaultProps[key], subkey) &&
184
+ !Object.prototype.hasOwnProperty.call(properties[key], subkey)
185
+ ) {
186
+ errorMsgs.push(
187
+ `${key}.${subkey} missing. Default value (${
188
+ Array.isArray(defaultProps[key][subkey])
189
+ ? 'Array'
190
+ : typeof defaultProps[key][subkey]
191
+ }): ${defaultProps[key][subkey]}`
192
+ );
193
+ solutionSet.add(
194
+ `Run 'mcdev upgrade' to fix missing or changed configuration options`
195
+ );
196
+ missingFields.push(`${key}.${subkey}`);
197
+ } else if (subkey === 'deployment') {
198
+ for (const dkey in defaultProps[key][subkey]) {
199
+ if (
200
+ Object.prototype.hasOwnProperty.call(
201
+ defaultProps[key][subkey],
202
+ dkey
203
+ ) &&
204
+ !Object.prototype.hasOwnProperty.call(
205
+ properties[key][subkey],
206
+ dkey
207
+ )
208
+ ) {
209
+ errorMsgs.push(
210
+ `${key}.${subkey} missing. Default value (${
211
+ Array.isArray(defaultProps[key][subkey][dkey])
212
+ ? 'Array'
213
+ : typeof defaultProps[key][subkey][dkey]
214
+ }): ${defaultProps[key][subkey][dkey]}`
215
+ );
216
+ solutionSet.add(
217
+ `Run 'mcdev upgrade' to fix missing or changed configuration options`
218
+ );
219
+ missingFields.push(`${key}.${subkey}.${dkey}`);
220
+ }
221
+ }
222
+ }
223
+ }
224
+ }
225
+ }
226
+ }
227
+ }
228
+ // check if project config version is outdated compared to user's mcdev version
229
+ if (
230
+ !properties.version ||
231
+ (![null, 'patch'].includes(
232
+ semver.diff(Util.packageJsonMcdev.version, properties.version)
233
+ ) &&
234
+ semver.gt(Util.packageJsonMcdev.version, properties.version))
235
+ ) {
236
+ errorMsgs.push(
237
+ `Your project's config version ${properties.version} is lower than your Accenture SFMC DevTools version ${Util.packageJsonMcdev.version}`
238
+ );
239
+ solutionSet.add(`Run 'mcdev upgrade' to ensure optimal performance`);
240
+ missingFields.push('version');
241
+ }
242
+ if (silent) {
243
+ return missingFields;
244
+ } else {
245
+ if (errorMsgs.length) {
246
+ const errorMsgOutput = [
247
+ `Found problems in your ./${Util.configFileName} that you need to fix first:`,
248
+ ];
249
+ for (const msg of errorMsgs) {
250
+ errorMsgOutput.push(' - ' + msg);
251
+ }
252
+ Util.logger.error(errorMsgOutput.join('\n'));
253
+ if (Util.skipInteraction) {
254
+ return false;
255
+ }
256
+ Util.logger.info(
257
+ [
258
+ 'Here is what you can do to fix these issues:',
259
+ ...Array.from(solutionSet),
260
+ ].join('\n- ')
261
+ );
262
+ const responses = await inquirer.prompt([
263
+ {
264
+ type: 'confirm',
265
+ name: 'runUpgradeNow',
266
+ message: `Do you want to run 'mcdev upgrade' now?`,
267
+ default: true,
268
+ },
269
+ ]);
270
+ if (responses.runUpgradeNow) {
271
+ // use _execSync here to avoid a circular dependency
272
+ Util.execSync('mcdev', ['upgrade']);
273
+ }
274
+ return false;
275
+ } else {
276
+ return true;
277
+ }
278
+ }
279
+ },
280
+ /**
281
+ * defines how the properties.json should look like
282
+ * used for creating a template and for checking if variables are set
283
+ *
284
+ * @returns {Promise.<TYPE.Mcdevrc>} default properties
285
+ */
286
+ async getDefaultProperties() {
287
+ const configFileName = path.resolve(__dirname, Util.boilerplateDirectory, 'config.json');
288
+ if (!(await File.pathExists(configFileName))) {
289
+ Util.logger.debug(`Default config file not found in ${configFileName}`);
290
+ return false;
291
+ }
292
+ // const defaultProperties = File.readJsonSync(configFileName);
293
+ const defaultProperties = await File.readJson(configFileName);
294
+ // set default name for parent BU
295
+ defaultProperties.credentials.default.businessUnits[Util.parentBuName] = 0;
296
+ // set default retrieve values
297
+ defaultProperties.metaDataTypes.retrieve = Util.getRetrieveTypeChoices();
298
+
299
+ return defaultProperties;
300
+ },
301
+ };
302
+ module.exports = config;