mcdev 3.0.2 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.eslintrc.json +1 -1
  2. package/.github/ISSUE_TEMPLATE/bug.yml +75 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +3 -2
  4. package/.issuetracker +11 -3
  5. package/.vscode/settings.json +3 -3
  6. package/CHANGELOG.md +88 -0
  7. package/README.md +245 -141
  8. package/boilerplate/config.json +3 -2
  9. package/docs/dist/documentation.md +818 -352
  10. package/lib/Deployer.js +4 -1
  11. package/lib/MetadataTypeDefinitions.js +1 -0
  12. package/lib/MetadataTypeInfo.js +1 -0
  13. package/lib/Retriever.js +30 -14
  14. package/lib/cli.js +295 -0
  15. package/lib/index.js +774 -1019
  16. package/lib/metadataTypes/AccountUser.js +389 -0
  17. package/lib/metadataTypes/Asset.js +8 -7
  18. package/lib/metadataTypes/Automation.js +121 -56
  19. package/lib/metadataTypes/DataExtension.js +167 -121
  20. package/lib/metadataTypes/DataExtensionField.js +134 -4
  21. package/lib/metadataTypes/DataExtract.js +9 -5
  22. package/lib/metadataTypes/EventDefinition.js +9 -5
  23. package/lib/metadataTypes/FileTransfer.js +9 -5
  24. package/lib/metadataTypes/Folder.js +66 -69
  25. package/lib/metadataTypes/ImportFile.js +13 -12
  26. package/lib/metadataTypes/MetadataType.js +138 -77
  27. package/lib/metadataTypes/Query.js +2 -3
  28. package/lib/metadataTypes/Role.js +13 -8
  29. package/lib/metadataTypes/Script.js +2 -2
  30. package/lib/metadataTypes/definitions/AccountUser.definition.js +227 -0
  31. package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
  32. package/lib/metadataTypes/definitions/DataExtension.definition.js +1 -1
  33. package/lib/metadataTypes/definitions/DataExtensionField.definition.js +1 -1
  34. package/lib/metadataTypes/definitions/Folder.definition.js +1 -1
  35. package/lib/metadataTypes/definitions/ImportFile.definition.js +2 -1
  36. package/lib/metadataTypes/definitions/Script.definition.js +5 -5
  37. package/lib/retrieveChangelog.js +96 -0
  38. package/lib/util/cli.js +4 -6
  39. package/lib/util/init.git.js +2 -1
  40. package/lib/util/util.js +20 -3
  41. package/package.json +19 -23
  42. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -30
  43. package/img/README.md/troubleshoot-nodejs-postinstall.jpg +0 -0
  44. package/postinstall.js +0 -41
package/lib/Deployer.js CHANGED
@@ -81,7 +81,10 @@ class Deployer {
81
81
  MetadataTypeInfo[type].client = this.client;
82
82
  MetadataTypeInfo[type].properties = this.properties;
83
83
  Util.logger.info('Caching dependent Metadata: ' + metadataType);
84
- const result = await MetadataTypeInfo[type].retrieveForCache(this.buObject, subType);
84
+ let result;
85
+ await Util.retryOnError(`Retrying ${type}`, async () => {
86
+ result = await MetadataTypeInfo[type].retrieveForCache(this.buObject, subType);
87
+ });
85
88
  this.cache[type] = result.metadata;
86
89
  }
87
90
  // deploy metadata files, extending cache once deploys
@@ -4,6 +4,7 @@
4
4
  * Provides access to all metadataType classes
5
5
  */
6
6
  const MetadataTypeDefinitions = {
7
+ accountUser: require('./metadataTypes/definitions/AccountUser.definition'),
7
8
  asset: require('./metadataTypes/definitions/Asset.definition'),
8
9
  attributeGroup: require('./metadataTypes/definitions/AttributeGroup.definition'),
9
10
  automation: require('./metadataTypes/definitions/Automation.definition'),
@@ -4,6 +4,7 @@
4
4
  * Provides access to all metadataType classes
5
5
  */
6
6
  const MetadataTypeInfo = {
7
+ accountUser: require('./metadataTypes/AccountUser'),
7
8
  asset: require('./metadataTypes/Asset'),
8
9
  attributeGroup: require('./metadataTypes/AttributeGroup'),
9
10
  automation: require('./metadataTypes/Automation'),
package/lib/Retriever.js CHANGED
@@ -40,9 +40,11 @@ class Retriever {
40
40
  * @param {String[]} metadataTypes String list of metadata types to retrieve
41
41
  * @param {String} [name] name of Metadata to retrieve (in case of templating)
42
42
  * @param {Object} [templateVariables] Object of values which can be replaced (in case of templating)
43
- * @returns {Promise} Promise
43
+ * @param {boolean} [changelogOnly] skip saving, only create json in memory
44
+ * @returns {Promise<Object<string,Object>>} Promise
44
45
  */
45
- async retrieve(metadataTypes, name, templateVariables) {
46
+ async retrieve(metadataTypes, name, templateVariables, changelogOnly) {
47
+ const retrieveChangelog = {};
46
48
  for (const metadataType of Util.getMetadataHierachy(metadataTypes)) {
47
49
  let result;
48
50
  const [type, subType] = metadataType.split('-');
@@ -53,6 +55,10 @@ class Retriever {
53
55
 
54
56
  try {
55
57
  if (!metadataTypes.includes(type) && !metadataTypes.includes(metadataType)) {
58
+ if (changelogOnly) {
59
+ // no extra caching needed for list view
60
+ continue;
61
+ }
56
62
  Util.logger.info(`Caching dependent Metadata: ${metadataType}`);
57
63
  await Util.retryOnError(
58
64
  `Retrying to cache ${metadataType}`,
@@ -61,10 +67,6 @@ class Retriever {
61
67
  this.buObject,
62
68
  subType
63
69
  );
64
- if (type == 'list') {
65
- Util.logger.debug('==list==');
66
- Util.logger.debug(JSON.stringify(result));
67
- }
68
70
  },
69
71
  false
70
72
  );
@@ -97,14 +99,24 @@ class Retriever {
97
99
  });
98
100
  } else {
99
101
  Util.logger.info('Retrieving: ' + metadataType);
100
- await Util.retryOnError(`Retrying ${metadataType}`, async () => {
101
- result = await MetadataTypeInfo[type].retrieve(
102
- this.savePath,
103
- null,
104
- this.buObject,
105
- subType
106
- );
107
- });
102
+ if (changelogOnly) {
103
+ await Util.retryOnError(`Retrying ${metadataType}`, async () => {
104
+ result = await MetadataTypeInfo[type].retrieveChangelog(
105
+ null,
106
+ this.buObject,
107
+ subType
108
+ );
109
+ });
110
+ } else {
111
+ await Util.retryOnError(`Retrying ${metadataType}`, async () => {
112
+ result = await MetadataTypeInfo[type].retrieve(
113
+ this.savePath,
114
+ null,
115
+ this.buObject,
116
+ subType
117
+ );
118
+ });
119
+ }
108
120
  }
109
121
  if (result) {
110
122
  if (templateVariables && Array.isArray(result)) {
@@ -112,6 +124,9 @@ class Retriever {
112
124
  this.metadata[type] = result.map((element) => element.metadata);
113
125
  } else {
114
126
  this.metadata[type] = result.metadata;
127
+ if (metadataTypes.includes(type) || metadataTypes.includes(metadataType)) {
128
+ retrieveChangelog[type] = result.metadata;
129
+ }
115
130
  }
116
131
  }
117
132
  } catch (ex) {
@@ -122,6 +137,7 @@ class Retriever {
122
137
  }
123
138
  }
124
139
  }
140
+ return retrieveChangelog;
125
141
  }
126
142
  }
127
143
 
package/lib/cli.js ADDED
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * CLI entry for SFMC DevTools
6
+ */
7
+
8
+ const Util = require('./util/util');
9
+ const yargs = require('yargs');
10
+ const Mcdev = require('./index');
11
+
12
+ yargs
13
+ .scriptName('mcdev')
14
+ .usage('$0 <command> [options]')
15
+ .command({
16
+ command: 'retrieve [BU] [TYPE]',
17
+ aliases: ['r'],
18
+ desc: 'retrieves metadata of a business unit',
19
+ // @ts-ignore
20
+ builder: (yargs) => {
21
+ yargs
22
+ .positional('BU', {
23
+ type: 'string',
24
+ describe:
25
+ 'the business unit to retrieve from (in format "credential name/BU name")',
26
+ })
27
+ .positional('TYPE', {
28
+ type: 'string',
29
+ describe: 'metadata type that shall be exclusively downloaded',
30
+ });
31
+ },
32
+ handler: (argv) => {
33
+ Mcdev._setLoggingLevel(argv);
34
+ Mcdev.retrieve(argv.BU, argv.TYPE);
35
+ },
36
+ })
37
+ .command({
38
+ command: 'deploy [BU] [TYPE]',
39
+ aliases: ['d'],
40
+ desc: 'deploys local metadata to a business unit',
41
+ builder: (yargs) => {
42
+ yargs
43
+ .positional('BU', {
44
+ type: 'string',
45
+ describe:
46
+ 'the business unit to deploy to (in format "credential name/BU name")',
47
+ })
48
+ .positional('TYPE', {
49
+ type: 'string',
50
+ describe: 'metadata type that shall be exclusively uploaded',
51
+ });
52
+ },
53
+ handler: (argv) => {
54
+ Mcdev._setLoggingLevel(argv);
55
+ Mcdev.deploy(argv.BU, argv.TYPE);
56
+ },
57
+ })
58
+ .command({
59
+ command: 'init [credentialsName]',
60
+ desc: `creates '${Util.configFileName}' in your root or adds additional credentials to the existing one`,
61
+ builder: (yargs) => {
62
+ yargs.positional('credentialsName', {
63
+ type: 'string',
64
+ describe: 'name of your installed package',
65
+ });
66
+ },
67
+ handler: (argv) => {
68
+ Mcdev._setLoggingLevel(argv);
69
+ Mcdev.initProject(argv.credentialsName, argv.skipInteraction);
70
+ },
71
+ })
72
+ .command({
73
+ command: 'reloadBUs [credentialsName]',
74
+ aliases: ['rb'],
75
+ desc: 'loads the list of available BUs from the server and saves it to your config',
76
+ builder: (yargs) => {
77
+ yargs.positional('credentialsName', {
78
+ type: 'string',
79
+ describe: 'name of your installed package',
80
+ });
81
+ },
82
+ handler: (argv) => {
83
+ Mcdev._setLoggingLevel(argv);
84
+ Mcdev.findBUs(argv.credentialsName);
85
+ },
86
+ })
87
+ .command({
88
+ command: 'badKeys [BU]',
89
+ desc: 'lists metadata with random API names in specified Business Unit directory',
90
+ builder: (yargs) => {
91
+ yargs.positional('BU', {
92
+ type: 'string',
93
+ describe: 'the business unit to deploy to',
94
+ });
95
+ },
96
+ handler: (argv) => {
97
+ Mcdev._setLoggingLevel(argv);
98
+ Mcdev.badKeys(argv.BU);
99
+ },
100
+ })
101
+ .command({
102
+ command: 'document <BU> <TYPE>',
103
+ aliases: ['doc'],
104
+ desc: 'Creates Markdown or HTML documentation for the selected type',
105
+ builder: (yargs) => {
106
+ yargs
107
+ .positional('TYPE', {
108
+ type: 'string',
109
+ describe:
110
+ 'metadata type to generate docs for; currently supported: dataExtension, role',
111
+ })
112
+ .positional('BU', {
113
+ type: 'string',
114
+ describe:
115
+ 'the business unit to generate docs for (in format "credential name/BU name")',
116
+ });
117
+ },
118
+ handler: (argv) => {
119
+ Mcdev._setLoggingLevel(argv);
120
+ Mcdev.document(argv.BU, argv.TYPE);
121
+ },
122
+ })
123
+ .command({
124
+ command: 'delete <BU> <TYPE> <EXTERNALKEY>',
125
+ aliases: ['del'],
126
+ desc: 'deletes metadata of selected type and external key',
127
+ builder: (yargs) => {
128
+ yargs
129
+ .positional('BU', {
130
+ type: 'string',
131
+ describe:
132
+ 'the business unit to delete from (in format "credential name/BU name")',
133
+ })
134
+ .positional('TYPE', {
135
+ type: 'string',
136
+ describe: 'metadata type to delete from; currently supported: dataExtension',
137
+ })
138
+ .positional('EXTERNALKEY', {
139
+ type: 'string',
140
+ describe: 'the key to delete',
141
+ });
142
+ },
143
+ handler: (argv) => {
144
+ Mcdev._setLoggingLevel(argv);
145
+ Mcdev.deleteByKey(argv.BU, argv.TYPE, argv.EXTERNALKEY);
146
+ },
147
+ })
148
+ .command({
149
+ command: 'retrieveAsTemplate <BU> <TYPE> <NAME> <MARKET>',
150
+ aliases: ['rt'],
151
+ desc: 'Retrieves a specific metadata file by name for templating',
152
+ builder: (yargs) => {
153
+ yargs
154
+ .positional('BU', {
155
+ type: 'string',
156
+ describe:
157
+ 'the business unit to deploy to (in format "credential name/BU name")',
158
+ })
159
+ .positional('TYPE', {
160
+ type: 'string',
161
+ describe: 'metadata type',
162
+ })
163
+ .positional('NAME', {
164
+ type: 'string',
165
+ describe: 'name of the metadata component',
166
+ })
167
+ .positional('MARKET', {
168
+ type: 'string',
169
+ describe: 'market used for reverse building template',
170
+ });
171
+ },
172
+ handler: (argv) => {
173
+ Mcdev._setLoggingLevel(argv);
174
+ Mcdev.retrieveAsTemplate(argv.BU, argv.TYPE, argv.NAME, argv.MARKET);
175
+ },
176
+ })
177
+ .command({
178
+ command: 'buildDefinition <BU> <TYPE> <NAME> <MARKET>',
179
+ aliases: ['bd'],
180
+ desc: 'builds metadata definition based on template',
181
+ builder: (yargs) => {
182
+ yargs
183
+ .positional('BU', {
184
+ type: 'string',
185
+ describe: 'the business unit to deploy to',
186
+ })
187
+ .positional('TYPE', {
188
+ type: 'string',
189
+ describe: 'metadata type',
190
+ })
191
+ .positional('NAME', {
192
+ type: 'string',
193
+ describe: 'name of the metadata component',
194
+ })
195
+ .positional('MARKET', {
196
+ type: 'string',
197
+ describe: 'the business unit to deploy to',
198
+ });
199
+ },
200
+ handler: (argv) => {
201
+ Mcdev._setLoggingLevel(argv);
202
+ Mcdev.buildDefinition(argv.BU, argv.TYPE, argv.NAME, argv.MARKET);
203
+ },
204
+ })
205
+ .command({
206
+ command: 'buildDefinitionBulk <LISTNAME> <TYPE> <NAME>',
207
+ aliases: ['bdb'],
208
+ desc: 'builds metadata definition based on template en bulk',
209
+ builder: (yargs) => {
210
+ yargs
211
+ .positional('LISTNAME', {
212
+ type: 'string',
213
+ describe: 'name of list of BU-market combos',
214
+ })
215
+ .positional('TYPE', {
216
+ type: 'string',
217
+ describe: 'metadata type',
218
+ })
219
+ .positional('NAME', {
220
+ type: 'string',
221
+ describe: 'name of the metadata component',
222
+ });
223
+ },
224
+ handler: (argv) => {
225
+ Mcdev._setLoggingLevel(argv);
226
+ Mcdev.buildDefinitionBulk(argv.LISTNAME, argv.TYPE, argv.NAME);
227
+ },
228
+ })
229
+ .command({
230
+ command: 'selectTypes',
231
+ aliases: ['st'],
232
+ desc: 'lets you choose what metadata types to retrieve',
233
+ handler: (argv) => {
234
+ Mcdev._setLoggingLevel(argv);
235
+ Mcdev.selectTypes();
236
+ },
237
+ })
238
+ .command({
239
+ command: 'explainTypes',
240
+ aliases: ['et'],
241
+ desc: 'explains metadata types that can be retrieved',
242
+ handler: (argv) => {
243
+ Mcdev._setLoggingLevel(argv);
244
+ Mcdev.explainTypes();
245
+ },
246
+ })
247
+ .command({
248
+ command: 'createDeltaPkg [range] [filter]',
249
+ aliases: ['cdp'],
250
+ desc: 'Copies commit-based file delta into deploy folder',
251
+ builder: (yargs) => {
252
+ yargs
253
+ .positional('range', {
254
+ type: 'string',
255
+ describe: 'Pull Request target branch or git commit range',
256
+ })
257
+ .positional('filter', {
258
+ type: 'string',
259
+ describe:
260
+ 'Disable templating & instead filter by the specified file path (comma separated)',
261
+ });
262
+ },
263
+ handler: Mcdev.createDeltaPkg,
264
+ })
265
+ .command({
266
+ command: 'upgrade',
267
+ aliases: ['up'],
268
+ desc: 'Add NPM dependencies and IDE configuration files to your project',
269
+ handler: (argv) => {
270
+ Mcdev._setLoggingLevel(argv);
271
+ Mcdev.upgrade(argv.skipInteraction);
272
+ },
273
+ })
274
+ .option('verbose', {
275
+ type: 'boolean',
276
+ description: 'Run with verbose CLI output',
277
+ })
278
+ .option('debug', {
279
+ type: 'boolean',
280
+ description: 'Enable developer & edge-case features',
281
+ })
282
+ .option('silent', {
283
+ type: 'boolean',
284
+ description: 'Only output errors to CLI',
285
+ })
286
+ .option('skipInteraction', {
287
+ alias: ['yes', 'y'],
288
+ description: 'Interactive questions where possible and go with defaults instead',
289
+ })
290
+ .demandCommand(1, 'Please enter a valid command')
291
+ .strict()
292
+ .recommendCommands()
293
+ .wrap(yargs.terminalWidth())
294
+ .epilog('Copyright 2021. Accenture.')
295
+ .help().argv;