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.
- package/.eslintrc.json +1 -1
- package/.github/ISSUE_TEMPLATE/bug.yml +75 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +3 -2
- package/.issuetracker +11 -3
- package/.vscode/settings.json +3 -3
- package/CHANGELOG.md +88 -0
- package/README.md +245 -141
- package/boilerplate/config.json +3 -2
- package/docs/dist/documentation.md +818 -352
- package/lib/Deployer.js +4 -1
- package/lib/MetadataTypeDefinitions.js +1 -0
- package/lib/MetadataTypeInfo.js +1 -0
- package/lib/Retriever.js +30 -14
- package/lib/cli.js +295 -0
- package/lib/index.js +774 -1019
- package/lib/metadataTypes/AccountUser.js +389 -0
- package/lib/metadataTypes/Asset.js +8 -7
- package/lib/metadataTypes/Automation.js +121 -56
- package/lib/metadataTypes/DataExtension.js +167 -121
- package/lib/metadataTypes/DataExtensionField.js +134 -4
- package/lib/metadataTypes/DataExtract.js +9 -5
- package/lib/metadataTypes/EventDefinition.js +9 -5
- package/lib/metadataTypes/FileTransfer.js +9 -5
- package/lib/metadataTypes/Folder.js +66 -69
- package/lib/metadataTypes/ImportFile.js +13 -12
- package/lib/metadataTypes/MetadataType.js +138 -77
- package/lib/metadataTypes/Query.js +2 -3
- package/lib/metadataTypes/Role.js +13 -8
- package/lib/metadataTypes/Script.js +2 -2
- package/lib/metadataTypes/definitions/AccountUser.definition.js +227 -0
- package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtension.definition.js +1 -1
- package/lib/metadataTypes/definitions/DataExtensionField.definition.js +1 -1
- package/lib/metadataTypes/definitions/Folder.definition.js +1 -1
- package/lib/metadataTypes/definitions/ImportFile.definition.js +2 -1
- package/lib/metadataTypes/definitions/Script.definition.js +5 -5
- package/lib/retrieveChangelog.js +96 -0
- package/lib/util/cli.js +4 -6
- package/lib/util/init.git.js +2 -1
- package/lib/util/util.js +20 -3
- package/package.json +19 -23
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -30
- package/img/README.md/troubleshoot-nodejs-postinstall.jpg +0 -0
- package/postinstall.js +0 -41
|
@@ -30,10 +30,10 @@ class DataExtract extends MetadataType {
|
|
|
30
30
|
* Retrieve a specific dataExtract Definition by Name
|
|
31
31
|
* @param {String} templateDir Directory where retrieved metadata directory will be saved
|
|
32
32
|
* @param {String} name name of the metadata file
|
|
33
|
-
* @param {Object}
|
|
33
|
+
* @param {Object} templateVariables variables to be replaced in the metadata
|
|
34
34
|
* @returns {Promise<Object>} Promise of metadata
|
|
35
35
|
*/
|
|
36
|
-
static async retrieveAsTemplate(templateDir, name,
|
|
36
|
+
static async retrieveAsTemplate(templateDir, name, templateVariables) {
|
|
37
37
|
const options = {
|
|
38
38
|
uri: '/automation/v1/dataextracts/?$filter=name%20eq%20' + name.split(' ').join('%20'),
|
|
39
39
|
};
|
|
@@ -51,16 +51,20 @@ class DataExtract extends MetadataType {
|
|
|
51
51
|
const extended = await this.client.RestClient.get({
|
|
52
52
|
uri: '/automation/v1/dataextracts/' + metadata.id,
|
|
53
53
|
});
|
|
54
|
+
const originalKey = extended.body[this.definition.keyField];
|
|
54
55
|
const val = JSON.parse(
|
|
55
|
-
Util.replaceByObject(
|
|
56
|
+
Util.replaceByObject(
|
|
57
|
+
JSON.stringify(this.parseMetadata(extended.body)),
|
|
58
|
+
templateVariables
|
|
59
|
+
)
|
|
56
60
|
);
|
|
57
61
|
|
|
58
62
|
// remove all fields listed in Definition for templating
|
|
59
63
|
this.keepTemplateFields(val);
|
|
60
64
|
File.writeJSONToFile(
|
|
61
65
|
[templateDir, this.definition.type].join('/'),
|
|
62
|
-
|
|
63
|
-
JSON.parse(Util.replaceByObject(JSON.stringify(val),
|
|
66
|
+
originalKey + '.' + this.definition.type + '-meta',
|
|
67
|
+
JSON.parse(Util.replaceByObject(JSON.stringify(val), templateVariables))
|
|
64
68
|
);
|
|
65
69
|
Util.logger.info(
|
|
66
70
|
`Dataextracts.retrieveAsTemplate:: Written Metadata to filesystem (${name})`
|
|
@@ -32,10 +32,10 @@ class EventDefinition extends MetadataType {
|
|
|
32
32
|
* Retrieve a specific Event Definition by Name
|
|
33
33
|
* @param {String} templateDir Directory where retrieved metadata directory will be saved
|
|
34
34
|
* @param {String} name name of the metadata file
|
|
35
|
-
* @param {Object}
|
|
35
|
+
* @param {Object} templateVariables variables to be replaced in the metadata
|
|
36
36
|
* @returns {Promise<Object>} Promise of metadata
|
|
37
37
|
*/
|
|
38
|
-
static async retrieveAsTemplate(templateDir, name,
|
|
38
|
+
static async retrieveAsTemplate(templateDir, name, templateVariables) {
|
|
39
39
|
// todo template based on name
|
|
40
40
|
const options = {
|
|
41
41
|
uri: '/interaction/v1/EventDefinitions?name=' + encodeURIComponent(name),
|
|
@@ -51,8 +51,12 @@ class EventDefinition extends MetadataType {
|
|
|
51
51
|
`please rename to be unique to avoid issues`
|
|
52
52
|
);
|
|
53
53
|
} else if (event && event.length === 1) {
|
|
54
|
+
const originalKey = event[0][this.definition.keyField];
|
|
54
55
|
const eventDef = JSON.parse(
|
|
55
|
-
Util.replaceByObject(
|
|
56
|
+
Util.replaceByObject(
|
|
57
|
+
JSON.stringify(this.parseMetadata(event[0])),
|
|
58
|
+
templateVariables
|
|
59
|
+
)
|
|
56
60
|
);
|
|
57
61
|
if (!eventDef.dataExtensionId) {
|
|
58
62
|
throw new Error(
|
|
@@ -67,8 +71,8 @@ class EventDefinition extends MetadataType {
|
|
|
67
71
|
this.keepTemplateFields(eventDef);
|
|
68
72
|
File.writeJSONToFile(
|
|
69
73
|
[templateDir, this.definition.type].join('/'),
|
|
70
|
-
|
|
71
|
-
JSON.parse(Util.replaceByObject(JSON.stringify(eventDef),
|
|
74
|
+
originalKey + '.' + this.definition.type + '-meta',
|
|
75
|
+
JSON.parse(Util.replaceByObject(JSON.stringify(eventDef), templateVariables))
|
|
72
76
|
);
|
|
73
77
|
Util.logger.info(
|
|
74
78
|
`EventDefinition.retrieveAsTemplate:: Written Metadata to filesystem (${name})`
|
|
@@ -30,10 +30,10 @@ class FileTransfer extends MetadataType {
|
|
|
30
30
|
* Retrieve a specific File Transfer Definition by Name
|
|
31
31
|
* @param {String} templateDir Directory where retrieved metadata directory will be saved
|
|
32
32
|
* @param {String} name name of the metadata file
|
|
33
|
-
* @param {Object}
|
|
33
|
+
* @param {Object} templateVariables variables to be replaced in the metadata
|
|
34
34
|
* @returns {Promise} Promise
|
|
35
35
|
*/
|
|
36
|
-
static async retrieveAsTemplate(templateDir, name,
|
|
36
|
+
static async retrieveAsTemplate(templateDir, name, templateVariables) {
|
|
37
37
|
const options = {
|
|
38
38
|
uri: '/automation/v1/filetransfers/?$filter=name%20eq%20' + name.split(' ').join('%20'),
|
|
39
39
|
};
|
|
@@ -51,16 +51,20 @@ class FileTransfer extends MetadataType {
|
|
|
51
51
|
const extended = await this.client.RestClient.get({
|
|
52
52
|
uri: '/automation/v1/filetransfers/' + metadata.id,
|
|
53
53
|
});
|
|
54
|
+
const originalKey = extended.body[this.definition.keyField];
|
|
54
55
|
const val = JSON.parse(
|
|
55
|
-
Util.replaceByObject(
|
|
56
|
+
Util.replaceByObject(
|
|
57
|
+
JSON.stringify(this.parseMetadata(extended.body)),
|
|
58
|
+
templateVariables
|
|
59
|
+
)
|
|
56
60
|
);
|
|
57
61
|
|
|
58
62
|
// remove all fields listed in Definition for templating
|
|
59
63
|
this.keepTemplateFields(val);
|
|
60
64
|
File.writeJSONToFile(
|
|
61
65
|
[templateDir, this.definition.type].join('/'),
|
|
62
|
-
|
|
63
|
-
JSON.parse(Util.replaceByObject(JSON.stringify(val),
|
|
66
|
+
originalKey + '.' + this.definition.type + '-meta',
|
|
67
|
+
JSON.parse(Util.replaceByObject(JSON.stringify(val), templateVariables))
|
|
64
68
|
);
|
|
65
69
|
Util.logger.info(
|
|
66
70
|
`FileTransfer.retrieveAsTemplate:: Written Metadata to filesystem (${name})`
|
|
@@ -13,16 +13,16 @@ class Folder extends MetadataType {
|
|
|
13
13
|
/**
|
|
14
14
|
* Retrieves metadata of metadata type into local filesystem. executes callback with retrieved metadata
|
|
15
15
|
* @param {String} retrieveDir Directory where retrieved metadata directory will be saved
|
|
16
|
-
* @param {String[]} [
|
|
16
|
+
* @param {String[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
|
|
17
17
|
* @param {Object} buObject properties for auth
|
|
18
18
|
* @returns {Promise} Promise
|
|
19
19
|
*/
|
|
20
|
-
static async retrieve(retrieveDir,
|
|
21
|
-
const queryAllFolders = await this.retrieveHelper(
|
|
20
|
+
static async retrieve(retrieveDir, additionalFields, buObject) {
|
|
21
|
+
const queryAllFolders = await this.retrieveHelper(additionalFields, true);
|
|
22
22
|
// if this is the parent, no need to query twice as QueryAllAccounts works.
|
|
23
23
|
|
|
24
24
|
if (buObject.eid !== buObject.mid) {
|
|
25
|
-
queryAllFolders.push(...(await this.retrieveHelper(
|
|
25
|
+
queryAllFolders.push(...(await this.retrieveHelper(additionalFields, false)));
|
|
26
26
|
}
|
|
27
27
|
const sortPairs = toposort(queryAllFolders.map((a) => [a.ParentFolder.ID, a.ID]));
|
|
28
28
|
const idMap = {};
|
|
@@ -258,39 +258,36 @@ class Folder extends MetadataType {
|
|
|
258
258
|
* @param {Object} metadata metadata of the folder
|
|
259
259
|
* @returns {Promise} Promise
|
|
260
260
|
*/
|
|
261
|
-
static create(metadata) {
|
|
262
|
-
|
|
261
|
+
static async create(metadata) {
|
|
262
|
+
if (metadata.Parent && metadata.Parent.ID && metadata.Parent.ID === 0) {
|
|
263
|
+
Util.logger.error(
|
|
264
|
+
`${this.definition.type}-${metadata.ContentType}.create:: Cannot create Root Folder: ${metadata.Name}`
|
|
265
|
+
);
|
|
266
|
+
return {};
|
|
267
|
+
}
|
|
263
268
|
const path = metadata.Path;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (
|
|
269
|
+
try {
|
|
270
|
+
const response = await super.createSOAP(metadata, 'DataFolder', true);
|
|
271
|
+
if (response) {
|
|
272
|
+
response.body.Results[0].Object = metadata;
|
|
273
|
+
response.body.Results[0].Object.ID = response.body.Results[0].NewID;
|
|
274
|
+
response.body.Results[0].Object.CustomerKey = metadata.CustomerKey;
|
|
275
|
+
delete response.body.Results[0].Object.$;
|
|
276
|
+
|
|
277
|
+
Util.logger.info(`- created folder: ${path}`);
|
|
278
|
+
return response;
|
|
279
|
+
}
|
|
280
|
+
} catch (ex) {
|
|
281
|
+
if (ex && ex.results) {
|
|
267
282
|
Util.logger.error(
|
|
268
|
-
`${this.definition.type}-${metadata.ContentType}.create::
|
|
283
|
+
`${this.definition.type}-${metadata.ContentType}.create:: error creating: '${path}'. ${ex.results[0].StatusMessage}`
|
|
284
|
+
);
|
|
285
|
+
} else if (ex) {
|
|
286
|
+
Util.logger.error(
|
|
287
|
+
`${this.definition.type}-${metadata.ContentType}.create:: error creating: '${path}'. ${ex.message}`
|
|
269
288
|
);
|
|
270
|
-
resolve({});
|
|
271
|
-
} else {
|
|
272
|
-
this.client.SoapClient.create('DataFolder', metadata, null, (ex, response) => {
|
|
273
|
-
if (ex && ex.results) {
|
|
274
|
-
Util.logger.error(
|
|
275
|
-
`${this.definition.type}-${metadata.ContentType}.create:: error creating: ${path}. ${ex.results[0].StatusMessage}`
|
|
276
|
-
);
|
|
277
|
-
resolve();
|
|
278
|
-
} else if (ex) {
|
|
279
|
-
Util.logger.error(
|
|
280
|
-
`${this.definition.type}-${metadata.ContentType}.create:: error creating: ${path}. ${ex.message}`
|
|
281
|
-
);
|
|
282
|
-
resolve();
|
|
283
|
-
} else {
|
|
284
|
-
response.body.Results[0].Object = metadata;
|
|
285
|
-
response.body.Results[0].Object.ID = response.body.Results[0].NewID;
|
|
286
|
-
response.body.Results[0].Object.CustomerKey = tempCustomerKey;
|
|
287
|
-
delete response.body.Results[0].Object.$;
|
|
288
|
-
Util.logger.info(`- created folder: ${path}`);
|
|
289
|
-
resolve(response);
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
289
|
}
|
|
293
|
-
}
|
|
290
|
+
}
|
|
294
291
|
}
|
|
295
292
|
|
|
296
293
|
/**
|
|
@@ -299,30 +296,27 @@ class Folder extends MetadataType {
|
|
|
299
296
|
* @returns {Promise} Promise
|
|
300
297
|
*/
|
|
301
298
|
static async update(metadata) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
});
|
|
299
|
+
const path = metadata.Path;
|
|
300
|
+
try {
|
|
301
|
+
const response = await super.updateSOAP(metadata, 'DataFolder', true);
|
|
302
|
+
if (response) {
|
|
303
|
+
response.body.Results[0].Object = metadata;
|
|
304
|
+
response.body.Results[0].Object.CustomerKey = metadata.CustomerKey;
|
|
305
|
+
delete response.body.Results[0].Object.$;
|
|
306
|
+
Util.logger.info(`- updated folder: ${path}`);
|
|
307
|
+
return response;
|
|
308
|
+
}
|
|
309
|
+
} catch (ex) {
|
|
310
|
+
if (ex && ex.results) {
|
|
311
|
+
Util.logger.error(
|
|
312
|
+
`${this.definition.type}-${metadata.ContentType}.update:: error updating: '${path}'. ${ex.results[0].StatusMessage}`
|
|
313
|
+
);
|
|
314
|
+
} else if (ex) {
|
|
315
|
+
Util.logger.error(
|
|
316
|
+
`${this.definition.type}-${metadata.ContentType}.update:: error updating: '${path}'. ${ex.message}`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
326
320
|
}
|
|
327
321
|
|
|
328
322
|
/**
|
|
@@ -451,25 +445,28 @@ class Folder extends MetadataType {
|
|
|
451
445
|
|
|
452
446
|
/**
|
|
453
447
|
* Helper to retrieve the folders as promise
|
|
454
|
-
* @param {String[]} [
|
|
448
|
+
* @param {String[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
|
|
455
449
|
* @param {Boolean} [queryAllAccounts] which queryAllAccounts setting to use
|
|
456
450
|
* @returns {Promise<Object>} soap object
|
|
457
451
|
*/
|
|
458
|
-
static async retrieveHelper(
|
|
452
|
+
static async retrieveHelper(additionalFields, queryAllAccounts) {
|
|
459
453
|
const options = { queryAllAccounts: !!queryAllAccounts };
|
|
460
454
|
let status = 'MoreDataAvailable';
|
|
461
455
|
const Results = [];
|
|
462
456
|
do {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
this.
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
457
|
+
let response;
|
|
458
|
+
await Util.retryOnError(`Retrying ${this.definition.type}`, async () => {
|
|
459
|
+
response = await new Promise((resolve, reject) => {
|
|
460
|
+
// filtered out path as we need them to be stored locally, but do not want to try and retrieve
|
|
461
|
+
this.client.SoapClient.retrieve(
|
|
462
|
+
'DataFolder',
|
|
463
|
+
this.getFieldNamesToRetrieve(additionalFields).filter(
|
|
464
|
+
(field) => !field.includes('Path')
|
|
465
|
+
),
|
|
466
|
+
options,
|
|
467
|
+
(ex, response) => (ex ? reject(ex) : resolve(response))
|
|
468
|
+
);
|
|
469
|
+
});
|
|
473
470
|
});
|
|
474
471
|
// merge results with existing
|
|
475
472
|
Results.push(...response.body.Results);
|
|
@@ -32,10 +32,10 @@ class ImportFile extends MetadataType {
|
|
|
32
32
|
* Retrieve a specific Import Definition by Name
|
|
33
33
|
* @param {String} templateDir Directory where retrieved metadata directory will be saved
|
|
34
34
|
* @param {String} name name of the metadata file
|
|
35
|
-
* @param {Object}
|
|
35
|
+
* @param {Object} templateVariables variables to be replaced in the metadata
|
|
36
36
|
* @returns {Promise} Promise
|
|
37
37
|
*/
|
|
38
|
-
static async retrieveAsTemplate(templateDir, name,
|
|
38
|
+
static async retrieveAsTemplate(templateDir, name, templateVariables) {
|
|
39
39
|
const options = {
|
|
40
40
|
uri: '/automation/v1/imports/?$filter=name%20eq%20' + name.split(' ').join('%20'),
|
|
41
41
|
};
|
|
@@ -48,17 +48,20 @@ class ImportFile extends MetadataType {
|
|
|
48
48
|
Util.logger.error(`No ${this.definition.typeName} found with name "${name}"`);
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
const originalKey = metadata[this.definition.keyField];
|
|
52
52
|
const val = JSON.parse(
|
|
53
|
-
Util.replaceByObject(
|
|
53
|
+
Util.replaceByObject(
|
|
54
|
+
JSON.stringify(this.parseMetadata(metadata)),
|
|
55
|
+
templateVariables
|
|
56
|
+
)
|
|
54
57
|
);
|
|
55
58
|
|
|
56
59
|
// remove all fields listed in Definition for templating
|
|
57
60
|
this.keepTemplateFields(val);
|
|
58
61
|
File.writeJSONToFile(
|
|
59
62
|
[templateDir, this.definition.type].join('/'),
|
|
60
|
-
|
|
61
|
-
JSON.parse(Util.replaceByObject(JSON.stringify(val),
|
|
63
|
+
originalKey + '.' + this.definition.type + '-meta',
|
|
64
|
+
JSON.parse(Util.replaceByObject(JSON.stringify(val), templateVariables))
|
|
62
65
|
);
|
|
63
66
|
Util.logger.info(
|
|
64
67
|
`ImportFile.retrieveAsTemplate:: Written Metadata to filesystem (${name})`
|
|
@@ -147,12 +150,10 @@ class ImportFile extends MetadataType {
|
|
|
147
150
|
}
|
|
148
151
|
}
|
|
149
152
|
// When the destinationObjectTypeId is 584 is refers to Mobile Connect which is not supported as an Import Type
|
|
150
|
-
metadata.destinationObjectTypeId =
|
|
151
|
-
metadata.c__destinationType
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
metadata.c__subscriberImportType
|
|
155
|
-
];
|
|
153
|
+
metadata.destinationObjectTypeId =
|
|
154
|
+
this.definition.destinationObjectTypeMapping[metadata.c__destinationType];
|
|
155
|
+
metadata.subscriberImportTypeId =
|
|
156
|
+
this.definition.subscriberImportTypeMapping[metadata.c__subscriberImportType];
|
|
156
157
|
metadata.updateTypeId = this.definition.updateTypeMapping[metadata.c__dataAction];
|
|
157
158
|
return metadata;
|
|
158
159
|
}
|