mcdev 3.0.1 → 3.1.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 (42) hide show
  1. package/.eslintrc.json +1 -1
  2. package/.github/ISSUE_TEMPLATE/bug.yml +72 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. package/.github/ISSUE_TEMPLATE/task.md +10 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +11 -0
  6. package/.issuetracker +11 -3
  7. package/.vscode/settings.json +3 -3
  8. package/CHANGELOG.md +103 -1
  9. package/README.md +245 -141
  10. package/boilerplate/config.json +3 -2
  11. package/docs/dist/documentation.md +803 -337
  12. package/lib/Deployer.js +4 -1
  13. package/lib/MetadataTypeDefinitions.js +1 -0
  14. package/lib/MetadataTypeInfo.js +1 -0
  15. package/lib/Retriever.js +32 -17
  16. package/lib/cli.js +295 -0
  17. package/lib/index.js +774 -1019
  18. package/lib/metadataTypes/AccountUser.js +389 -0
  19. package/lib/metadataTypes/Asset.js +20 -12
  20. package/lib/metadataTypes/Automation.js +115 -52
  21. package/lib/metadataTypes/DataExtension.js +159 -113
  22. package/lib/metadataTypes/DataExtensionField.js +134 -4
  23. package/lib/metadataTypes/Folder.js +66 -69
  24. package/lib/metadataTypes/ImportFile.js +4 -6
  25. package/lib/metadataTypes/MetadataType.js +136 -67
  26. package/lib/metadataTypes/Query.js +2 -3
  27. package/lib/metadataTypes/Role.js +13 -8
  28. package/lib/metadataTypes/definitions/AccountUser.definition.js +227 -0
  29. package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
  30. package/lib/metadataTypes/definitions/Campaign.definition.js +1 -1
  31. package/lib/metadataTypes/definitions/DataExtension.definition.js +1 -1
  32. package/lib/metadataTypes/definitions/DataExtensionField.definition.js +1 -1
  33. package/lib/metadataTypes/definitions/Folder.definition.js +1 -1
  34. package/lib/metadataTypes/definitions/ImportFile.definition.js +2 -1
  35. package/lib/metadataTypes/definitions/Script.definition.js +5 -5
  36. package/lib/retrieveChangelog.js +96 -0
  37. package/lib/util/cli.js +4 -6
  38. package/lib/util/init.git.js +2 -1
  39. package/lib/util/util.js +31 -15
  40. package/package.json +19 -23
  41. package/img/README.md/troubleshoot-nodejs-postinstall.jpg +0 -0
  42. 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
@@ -32,7 +32,6 @@ class Retriever {
32
32
  buObject.credential,
33
33
  buObject.businessUnit,
34
34
  ]);
35
-
36
35
  this.metadata = {};
37
36
  }
38
37
 
@@ -41,9 +40,11 @@ class Retriever {
41
40
  * @param {String[]} metadataTypes String list of metadata types to retrieve
42
41
  * @param {String} [name] name of Metadata to retrieve (in case of templating)
43
42
  * @param {Object} [templateVariables] Object of values which can be replaced (in case of templating)
44
- * @returns {Promise} Promise
43
+ * @param {boolean} [changelogOnly] skip saving, only create json in memory
44
+ * @returns {Promise<Object<string,Object>>} Promise
45
45
  */
46
- async retrieve(metadataTypes, name, templateVariables) {
46
+ async retrieve(metadataTypes, name, templateVariables, changelogOnly) {
47
+ const retrieveChangelog = {};
47
48
  for (const metadataType of Util.getMetadataHierachy(metadataTypes)) {
48
49
  let result;
49
50
  const [type, subType] = metadataType.split('-');
@@ -53,7 +54,11 @@ class Retriever {
53
54
  MetadataTypeInfo[type].properties = this.properties;
54
55
 
55
56
  try {
56
- if (!metadataTypes.includes(type)) {
57
+ if (!metadataTypes.includes(type) && !metadataTypes.includes(metadataType)) {
58
+ if (changelogOnly) {
59
+ // no extra caching needed for list view
60
+ continue;
61
+ }
57
62
  Util.logger.info(`Caching dependent Metadata: ${metadataType}`);
58
63
  await Util.retryOnError(
59
64
  `Retrying to cache ${metadataType}`,
@@ -62,12 +67,8 @@ class Retriever {
62
67
  this.buObject,
63
68
  subType
64
69
  );
65
- if (type == 'list') {
66
- Util.logger.debug('==list==');
67
- Util.logger.debug(JSON.stringify(result));
68
- }
69
70
  },
70
- true
71
+ false
71
72
  );
72
73
  } else if (templateVariables) {
73
74
  Util.logger.info(`Retrieving as Template: ${metadataType}`);
@@ -98,14 +99,24 @@ class Retriever {
98
99
  });
99
100
  } else {
100
101
  Util.logger.info('Retrieving: ' + metadataType);
101
- await Util.retryOnError(`Retrying ${metadataType}`, async () => {
102
- result = await MetadataTypeInfo[type].retrieve(
103
- this.savePath,
104
- null,
105
- this.buObject,
106
- subType
107
- );
108
- });
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
+ }
109
120
  }
110
121
  if (result) {
111
122
  if (templateVariables && Array.isArray(result)) {
@@ -113,6 +124,9 @@ class Retriever {
113
124
  this.metadata[type] = result.map((element) => element.metadata);
114
125
  } else {
115
126
  this.metadata[type] = result.metadata;
127
+ if (metadataTypes.includes(type) || metadataTypes.includes(metadataType)) {
128
+ retrieveChangelog[type] = result.metadata;
129
+ }
116
130
  }
117
131
  }
118
132
  } catch (ex) {
@@ -123,6 +137,7 @@ class Retriever {
123
137
  }
124
138
  }
125
139
  }
140
+ return retrieveChangelog;
126
141
  }
127
142
  }
128
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;