mcdev 3.1.1 → 4.0.0
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 +67 -7
- package/.github/ISSUE_TEMPLATE/bug.yml +5 -1
- package/.github/ISSUE_TEMPLATE/task.md +1 -1
- package/.github/PULL_REQUEST_TEMPLATE.md +5 -3
- package/.github/dependabot.yml +14 -0
- package/.github/workflows/code-analysis.yml +57 -0
- package/.husky/commit-msg +10 -0
- package/.husky/post-checkout +5 -0
- package/.husky/pre-commit +2 -1
- package/.prettierrc +8 -0
- package/.vscode/settings.json +1 -1
- package/LICENSE +2 -2
- package/README.md +134 -45
- package/boilerplate/config.json +5 -11
- package/boilerplate/files/.prettierrc +8 -0
- package/boilerplate/files/.vscode/extensions.json +0 -1
- package/boilerplate/files/.vscode/settings.json +28 -2
- package/boilerplate/files/README.md +2 -2
- package/boilerplate/forcedUpdates.json +10 -0
- package/boilerplate/npm-dependencies.json +5 -5
- package/docs/dist/documentation.md +2795 -1724
- package/jsconfig.json +1 -1
- package/lib/Builder.js +166 -75
- package/lib/Deployer.js +244 -96
- package/lib/MetadataTypeDefinitions.js +2 -0
- package/lib/MetadataTypeInfo.js +2 -0
- package/lib/Retriever.js +61 -84
- package/lib/cli.js +133 -25
- package/lib/index.js +242 -563
- package/lib/metadataTypes/AccountUser.js +101 -95
- package/lib/metadataTypes/Asset.js +677 -248
- package/lib/metadataTypes/AttributeGroup.js +23 -12
- package/lib/metadataTypes/Automation.js +456 -357
- package/lib/metadataTypes/Campaign.js +33 -93
- package/lib/metadataTypes/ContentArea.js +31 -11
- package/lib/metadataTypes/DataExtension.js +391 -376
- package/lib/metadataTypes/DataExtensionField.js +131 -54
- package/lib/metadataTypes/DataExtensionTemplate.js +22 -4
- package/lib/metadataTypes/DataExtract.js +67 -50
- package/lib/metadataTypes/DataExtractType.js +14 -8
- package/lib/metadataTypes/Discovery.js +21 -16
- package/lib/metadataTypes/Email.js +32 -12
- package/lib/metadataTypes/EmailSendDefinition.js +85 -80
- package/lib/metadataTypes/EventDefinition.js +69 -47
- package/lib/metadataTypes/FileTransfer.js +78 -54
- package/lib/metadataTypes/Filter.js +11 -4
- package/lib/metadataTypes/Folder.js +149 -117
- package/lib/metadataTypes/FtpLocation.js +14 -8
- package/lib/metadataTypes/ImportFile.js +69 -69
- package/lib/metadataTypes/Interaction.js +19 -4
- package/lib/metadataTypes/List.js +54 -13
- package/lib/metadataTypes/MetadataType.js +687 -479
- package/lib/metadataTypes/MobileCode.js +46 -0
- package/lib/metadataTypes/MobileKeyword.js +114 -0
- package/lib/metadataTypes/Query.js +204 -103
- package/lib/metadataTypes/Role.js +76 -61
- package/lib/metadataTypes/Script.js +146 -82
- package/lib/metadataTypes/SetDefinition.js +20 -8
- package/lib/metadataTypes/TriggeredSendDefinition.js +78 -58
- package/lib/metadataTypes/definitions/Asset.definition.js +21 -10
- package/lib/metadataTypes/definitions/AttributeGroup.definition.js +12 -0
- package/lib/metadataTypes/definitions/Automation.definition.js +10 -5
- package/lib/metadataTypes/definitions/Campaign.definition.js +44 -1
- package/lib/metadataTypes/definitions/DataExtension.definition.js +4 -0
- package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +6 -0
- package/lib/metadataTypes/definitions/DataExtract.definition.js +18 -14
- package/lib/metadataTypes/definitions/Discovery.definition.js +12 -0
- package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +4 -0
- package/lib/metadataTypes/definitions/EventDefinition.definition.js +22 -0
- package/lib/metadataTypes/definitions/FileTransfer.definition.js +4 -0
- package/lib/metadataTypes/definitions/Filter.definition.js +4 -0
- package/lib/metadataTypes/definitions/Folder.definition.js +6 -0
- package/lib/metadataTypes/definitions/FtpLocation.definition.js +4 -0
- package/lib/metadataTypes/definitions/ImportFile.definition.js +10 -5
- package/lib/metadataTypes/definitions/Interaction.definition.js +4 -0
- package/lib/metadataTypes/definitions/MobileCode.definition.js +163 -0
- package/lib/metadataTypes/definitions/MobileKeyword.definition.js +253 -0
- package/lib/metadataTypes/definitions/Query.definition.js +4 -0
- package/lib/metadataTypes/definitions/Role.definition.js +5 -0
- package/lib/metadataTypes/definitions/Script.definition.js +4 -0
- package/lib/metadataTypes/definitions/SetDefinition.definition.js +28 -0
- package/lib/metadataTypes/definitions/TriggeredSendDefinition.definition.js +4 -0
- package/lib/retrieveChangelog.js +7 -6
- package/lib/util/auth.js +117 -0
- package/lib/util/businessUnit.js +55 -66
- package/lib/util/cache.js +194 -0
- package/lib/util/cli.js +90 -116
- package/lib/util/config.js +302 -0
- package/lib/util/devops.js +240 -50
- package/lib/util/file.js +120 -191
- package/lib/util/init.config.js +195 -69
- package/lib/util/init.git.js +45 -50
- package/lib/util/init.js +72 -59
- package/lib/util/init.npm.js +48 -39
- package/lib/util/util.js +280 -564
- package/package.json +44 -33
- package/test/dataExtension.test.js +152 -0
- package/test/mockRoot/.mcdev-auth.json +8 -0
- package/test/mockRoot/.mcdevrc.json +67 -0
- package/test/mockRoot/deploy/testInstance/testBU/dataExtension/childBU_dataextension_test.dataExtension-meta.json +39 -0
- package/test/mockRoot/deploy/testInstance/testBU/dataExtension/testDataExtension.dataExtension-meta.json +23 -0
- package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +11 -0
- package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.sql +4 -0
- package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.json +11 -0
- package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.sql +4 -0
- package/test/query.test.js +149 -0
- package/test/resourceFactory.js +142 -0
- package/test/resources/1111111/dataFolder/retrieve-response.xml +43 -0
- package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +18 -0
- package/test/resources/9999999/automation/v1/queries/get-response.json +24 -0
- package/test/resources/9999999/automation/v1/queries/post-response.json +18 -0
- package/test/resources/9999999/dataExtension/build-expected.json +51 -0
- package/test/resources/9999999/dataExtension/create-expected.json +23 -0
- package/test/resources/9999999/dataExtension/create-response.xml +54 -0
- package/test/resources/9999999/dataExtension/retrieve-expected.json +51 -0
- package/test/resources/9999999/dataExtension/retrieve-response.xml +47 -0
- package/test/resources/9999999/dataExtension/template-expected.json +51 -0
- package/test/resources/9999999/dataExtension/update-expected.json +55 -0
- package/test/resources/9999999/dataExtension/update-response.xml +52 -0
- package/test/resources/9999999/dataExtensionField/retrieve-response.xml +93 -0
- package/test/resources/9999999/dataExtensionTemplate/retrieve-response.xml +303 -0
- package/test/resources/9999999/dataFolder/retrieve-response.xml +65 -0
- package/test/resources/9999999/query/build-expected.json +8 -0
- package/test/resources/9999999/query/get-expected.json +11 -0
- package/test/resources/9999999/query/patch-expected.json +11 -0
- package/test/resources/9999999/query/post-expected.json +11 -0
- package/test/resources/9999999/query/template-expected.json +8 -0
- package/test/resources/auth.json +32 -0
- package/test/resources/rest404-response.json +5 -0
- package/test/resources/retrieve-response.xml +21 -0
- package/test/utils.js +107 -0
- package/types/mcdev.d.js +301 -0
- package/CHANGELOG.md +0 -126
- package/PULL_REQUEST_TEMPLATE.md +0 -19
- package/test/util/file.js +0 -51
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const TYPE = require('../../types/mcdev.d');
|
|
3
4
|
const MetadataType = require('./MetadataType');
|
|
4
5
|
const toposort = require('toposort');
|
|
5
6
|
const Util = require('../util/util');
|
|
6
7
|
const File = require('../util/file');
|
|
8
|
+
const cache = require('../util/cache');
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Folder MetadataType
|
|
12
|
+
*
|
|
10
13
|
* @augments MetadataType
|
|
11
14
|
*/
|
|
12
15
|
class Folder extends MetadataType {
|
|
13
16
|
/**
|
|
14
17
|
* Retrieves metadata of metadata type into local filesystem. executes callback with retrieved metadata
|
|
15
|
-
*
|
|
16
|
-
* @param {
|
|
17
|
-
* @param {
|
|
18
|
+
*
|
|
19
|
+
* @param {string} retrieveDir Directory where retrieved metadata directory will be saved
|
|
20
|
+
* @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
|
|
21
|
+
* @param {TYPE.BuObject} buObject properties for auth
|
|
22
|
+
* @param {void} [___] unused parameter
|
|
23
|
+
* @param {string} [key] customer key of single item to retrieve
|
|
18
24
|
* @returns {Promise} Promise
|
|
19
25
|
*/
|
|
20
|
-
static async retrieve(retrieveDir, additionalFields, buObject) {
|
|
26
|
+
static async retrieve(retrieveDir, additionalFields, buObject, ___, key) {
|
|
27
|
+
if (key) {
|
|
28
|
+
Util.logger.error(`Folder.retrieve() does not support key parameter`);
|
|
29
|
+
}
|
|
21
30
|
const queryAllFolders = await this.retrieveHelper(additionalFields, true);
|
|
22
|
-
// if this is the parent, no need to query twice as QueryAllAccounts works.
|
|
23
31
|
|
|
24
32
|
if (buObject.eid !== buObject.mid) {
|
|
25
33
|
queryAllFolders.push(...(await this.retrieveHelper(additionalFields, false)));
|
|
@@ -36,6 +44,8 @@ class Folder extends MetadataType {
|
|
|
36
44
|
else if (!val.CustomerKey) {
|
|
37
45
|
val.CustomerKey = [buObject.eid, val.ID].join('-');
|
|
38
46
|
}
|
|
47
|
+
// ensure name is a string and not a number (SFMC-SDK workaround)
|
|
48
|
+
val.Name = val.Name + '';
|
|
39
49
|
|
|
40
50
|
idMap[val.ID] = val;
|
|
41
51
|
}
|
|
@@ -47,12 +57,9 @@ class Folder extends MetadataType {
|
|
|
47
57
|
for (const id of sortPairs) {
|
|
48
58
|
if (!idMap[id]) {
|
|
49
59
|
Util.logger.debug(`Error: id ${id} not found in idMap-obj but in sortPairs-array.`);
|
|
50
|
-
if (Util.logger.level === 'debug') {
|
|
51
|
-
console.log(`Error: id ${id} not found in idMap-ob but in sortPairs-array.`);
|
|
52
|
-
}
|
|
53
60
|
} else if (
|
|
54
61
|
idMap[id].ParentFolder &&
|
|
55
|
-
idMap[id].ParentFolder.ID &&
|
|
62
|
+
Number.isSafeInteger(idMap[id].ParentFolder.ID) &&
|
|
56
63
|
idMap[id].Name !== '<ROOT>'
|
|
57
64
|
) {
|
|
58
65
|
// if the parent folder can be found by ID
|
|
@@ -69,16 +76,16 @@ class Folder extends MetadataType {
|
|
|
69
76
|
idMap[id].Path = idMap[id].Name;
|
|
70
77
|
}
|
|
71
78
|
} else {
|
|
72
|
-
Util.logger.
|
|
73
|
-
`
|
|
79
|
+
Util.logger.warn(
|
|
80
|
+
` - Skipping folder ${idMap[id].Name} (${id}, type: ${idMap[id].ContentType}): Cannot find parent folder (${idMap[id].ParentFolder.ID})`
|
|
74
81
|
);
|
|
75
82
|
}
|
|
76
83
|
}
|
|
77
84
|
// All folders except the artificial root have ParentFolder attribute. If they dont something else is wrong
|
|
78
85
|
else if (idMap[id].Name !== '<ROOT>') {
|
|
79
86
|
idMap[id].Path = '';
|
|
80
|
-
Util.logger.
|
|
81
|
-
`
|
|
87
|
+
Util.logger.warn(
|
|
88
|
+
` - Skipping folder ${idMap[id].Name} (${id}, type: ${idMap[id].ContentType}): Does not have a parent folder`
|
|
82
89
|
);
|
|
83
90
|
}
|
|
84
91
|
}
|
|
@@ -97,8 +104,7 @@ class Folder extends MetadataType {
|
|
|
97
104
|
for (const id in idMap) {
|
|
98
105
|
// remove keys which are listed in other BUs and skip root
|
|
99
106
|
if (
|
|
100
|
-
idMap[id].Client &&
|
|
101
|
-
idMap[id].Client.ID &&
|
|
107
|
+
idMap[id].Client?.ID &&
|
|
102
108
|
(buObject.mid == idMap[id].Client.ID ||
|
|
103
109
|
this.definition.folderTypesFromParent.includes(
|
|
104
110
|
idMap[id].ContentType.toLowerCase()
|
|
@@ -142,7 +148,8 @@ class Folder extends MetadataType {
|
|
|
142
148
|
|
|
143
149
|
/**
|
|
144
150
|
* Retrieves folder metadata for caching
|
|
145
|
-
*
|
|
151
|
+
*
|
|
152
|
+
* @param {TYPE.BuObject} buObject properties for auth
|
|
146
153
|
* @returns {Promise} Promise
|
|
147
154
|
*/
|
|
148
155
|
static retrieveForCache(buObject) {
|
|
@@ -153,12 +160,14 @@ class Folder extends MetadataType {
|
|
|
153
160
|
* Folder upsert (copied from Metadata Upsert), after retrieving from target
|
|
154
161
|
* and comparing to check if create or update operation is needed.
|
|
155
162
|
* Copied due to having a dependency on itself, meaning the created need to be serial
|
|
156
|
-
*
|
|
157
|
-
* @
|
|
163
|
+
*
|
|
164
|
+
* @param {TYPE.MetadataTypeMap} metadata metadata mapped by their keyField
|
|
165
|
+
* @returns {Promise.<object>} Promise of saved metadata
|
|
158
166
|
*/
|
|
159
167
|
static async upsert(metadata) {
|
|
160
168
|
let updateCount = 0;
|
|
161
169
|
let createCount = 0;
|
|
170
|
+
let filteredByPreDeploy = 0;
|
|
162
171
|
const upsertResults = {};
|
|
163
172
|
const sortPairs = toposort(
|
|
164
173
|
Object.keys(metadata).map((customerKey) => [
|
|
@@ -180,18 +189,61 @@ class Folder extends MetadataType {
|
|
|
180
189
|
let existingId;
|
|
181
190
|
try {
|
|
182
191
|
// perform a secondary check based on path
|
|
183
|
-
existingId =
|
|
184
|
-
this.cache,
|
|
192
|
+
existingId = cache.searchForField(
|
|
185
193
|
'folder',
|
|
186
194
|
deployableMetadata.Path,
|
|
187
195
|
'Path',
|
|
188
196
|
'ID'
|
|
189
197
|
);
|
|
190
|
-
|
|
198
|
+
const cachedVersion = cache.getByKey(
|
|
199
|
+
'folder',
|
|
200
|
+
cache.searchForField(
|
|
201
|
+
'folder',
|
|
202
|
+
deployableMetadata.Path,
|
|
203
|
+
'Path',
|
|
204
|
+
this.definition.keyField
|
|
205
|
+
)
|
|
206
|
+
);
|
|
207
|
+
if (
|
|
208
|
+
existingId &&
|
|
209
|
+
!this.hasChangedGeneric(
|
|
210
|
+
cachedVersion,
|
|
211
|
+
metadata[metadataKey],
|
|
212
|
+
null,
|
|
213
|
+
true
|
|
214
|
+
)
|
|
215
|
+
) {
|
|
216
|
+
Util.logger.verbose(
|
|
217
|
+
` - skipping ${this.definition.type} ${
|
|
218
|
+
cachedVersion?.Path ||
|
|
219
|
+
metadata[metadataKey][this.definition.nameField]
|
|
220
|
+
}: no change detected`
|
|
221
|
+
);
|
|
222
|
+
filteredByPreDeploy++;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
} catch {
|
|
191
226
|
// In case no path matching, then try to use CustomerKey
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
227
|
+
const cachedVersion = cache.getByKey('folder', normalizedKey);
|
|
228
|
+
existingId = cachedVersion?.ID;
|
|
229
|
+
if (
|
|
230
|
+
existingId &&
|
|
231
|
+
!this.hasChangedGeneric(
|
|
232
|
+
cachedVersion,
|
|
233
|
+
metadata[metadataKey],
|
|
234
|
+
null,
|
|
235
|
+
true
|
|
236
|
+
)
|
|
237
|
+
) {
|
|
238
|
+
Util.logger.verbose(
|
|
239
|
+
` - skipping ${this.definition.type} ${
|
|
240
|
+
cachedVersion?.Path ||
|
|
241
|
+
metadata[metadataKey][this.definition.nameField]
|
|
242
|
+
}: no change detected`
|
|
243
|
+
);
|
|
244
|
+
filteredByPreDeploy++;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
195
247
|
}
|
|
196
248
|
|
|
197
249
|
let result;
|
|
@@ -206,48 +258,48 @@ class Folder extends MetadataType {
|
|
|
206
258
|
result = await this.create(deployableMetadata);
|
|
207
259
|
createCount++;
|
|
208
260
|
}
|
|
209
|
-
if (result
|
|
261
|
+
if (result?.Results) {
|
|
210
262
|
const parsed = this.parseResponseBody({
|
|
211
|
-
Results: [result.
|
|
263
|
+
Results: [result.Results[0].Object],
|
|
212
264
|
});
|
|
213
|
-
if (
|
|
214
|
-
!result.body.Results[0].Object.CustomerKey &&
|
|
215
|
-
parsed['undefined']
|
|
216
|
-
) {
|
|
265
|
+
if (!result.Results[0].Object.CustomerKey && parsed['undefined']) {
|
|
217
266
|
// when inserting folders without specifying a CustomerKey, this happens in parseResponseBody()
|
|
218
267
|
parsed[normalizedKey] = parsed['undefined'];
|
|
219
268
|
delete parsed['undefined'];
|
|
220
269
|
}
|
|
221
|
-
|
|
270
|
+
const newObject = {};
|
|
271
|
+
newObject[normalizedKey] = Object.assign(
|
|
222
272
|
beforeMetadata,
|
|
223
273
|
parsed[normalizedKey]
|
|
224
274
|
);
|
|
275
|
+
cache.mergeMetadata('folder', newObject);
|
|
225
276
|
|
|
226
277
|
upsertResults[metadataKey] = beforeMetadata;
|
|
227
278
|
} else {
|
|
228
279
|
Util.logger.debug(result);
|
|
229
280
|
throw new Error(
|
|
230
|
-
`'${beforeMetadata
|
|
281
|
+
`'${beforeMetadata.Path}' was not deployed correctly`
|
|
231
282
|
);
|
|
232
283
|
}
|
|
233
284
|
}
|
|
234
285
|
} catch (ex) {
|
|
235
|
-
Util.
|
|
286
|
+
Util.logger.errorStack(
|
|
287
|
+
ex,
|
|
288
|
+
`Upserting ${this.definition.type} failed: ${ex.message}`
|
|
289
|
+
);
|
|
236
290
|
}
|
|
237
291
|
}
|
|
238
292
|
}
|
|
239
293
|
}
|
|
240
294
|
// Logging
|
|
241
|
-
Util.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
'upsert',
|
|
245
|
-
`${createCount} created / ${updateCount} updated`
|
|
295
|
+
Util.logger.info(
|
|
296
|
+
`${this.definition.type} upsert: ${createCount} created / ${updateCount} updated` +
|
|
297
|
+
(filteredByPreDeploy > 0 ? ` / ${filteredByPreDeploy} filtered` : '')
|
|
246
298
|
);
|
|
247
299
|
|
|
248
300
|
if (updateCount) {
|
|
249
301
|
Util.logger.warn(
|
|
250
|
-
`Folders are recognized for updates based on their CustomerKey or, if that is not given, their folder-path.`
|
|
302
|
+
` - Folders are recognized for updates based on their CustomerKey or, if that is not given, their folder-path.`
|
|
251
303
|
);
|
|
252
304
|
}
|
|
253
305
|
return upsertResults;
|
|
@@ -255,36 +307,37 @@ class Folder extends MetadataType {
|
|
|
255
307
|
|
|
256
308
|
/**
|
|
257
309
|
* creates a folder based on metatadata
|
|
258
|
-
*
|
|
310
|
+
*
|
|
311
|
+
* @param {TYPE.MetadataTypeItem} metadataEntry metadata of the folder
|
|
259
312
|
* @returns {Promise} Promise
|
|
260
313
|
*/
|
|
261
|
-
static async create(
|
|
262
|
-
if (
|
|
314
|
+
static async create(metadataEntry) {
|
|
315
|
+
if (metadataEntry?.Parent?.ID === 0) {
|
|
263
316
|
Util.logger.error(
|
|
264
|
-
`${this.definition.type}-${
|
|
317
|
+
`${this.definition.type}-${metadataEntry.ContentType}.create:: Cannot create Root Folder: ${metadataEntry.Name}`
|
|
265
318
|
);
|
|
266
319
|
return {};
|
|
267
320
|
}
|
|
268
|
-
const path =
|
|
321
|
+
const path = metadataEntry.Path;
|
|
269
322
|
try {
|
|
270
|
-
const response = await super.createSOAP(
|
|
323
|
+
const response = await super.createSOAP(metadataEntry, 'DataFolder', true);
|
|
271
324
|
if (response) {
|
|
272
|
-
response.
|
|
273
|
-
response.
|
|
274
|
-
response.
|
|
275
|
-
delete response.
|
|
325
|
+
response.Results[0].Object = metadataEntry;
|
|
326
|
+
response.Results[0].Object.ID = response.Results[0].NewID;
|
|
327
|
+
response.Results[0].Object.CustomerKey = metadataEntry.CustomerKey;
|
|
328
|
+
delete response.Results[0].Object.$;
|
|
276
329
|
|
|
277
|
-
Util.logger.info(
|
|
330
|
+
Util.logger.info(` - created folder: ${path}`);
|
|
278
331
|
return response;
|
|
279
332
|
}
|
|
280
333
|
} catch (ex) {
|
|
281
|
-
if (ex
|
|
334
|
+
if (ex?.results) {
|
|
282
335
|
Util.logger.error(
|
|
283
|
-
`${this.definition.type}-${
|
|
336
|
+
`${this.definition.type}-${metadataEntry.ContentType}.create:: error creating: '${path}'. ${ex.results[0].StatusMessage}`
|
|
284
337
|
);
|
|
285
338
|
} else if (ex) {
|
|
286
339
|
Util.logger.error(
|
|
287
|
-
`${this.definition.type}-${
|
|
340
|
+
`${this.definition.type}-${metadataEntry.ContentType}.create:: error creating: '${path}'. ${ex.message}`
|
|
288
341
|
);
|
|
289
342
|
}
|
|
290
343
|
}
|
|
@@ -292,28 +345,29 @@ class Folder extends MetadataType {
|
|
|
292
345
|
|
|
293
346
|
/**
|
|
294
347
|
* Updates a single Folder.
|
|
295
|
-
*
|
|
348
|
+
*
|
|
349
|
+
* @param {TYPE.MetadataTypeItem} metadataEntry single metadata entry
|
|
296
350
|
* @returns {Promise} Promise
|
|
297
351
|
*/
|
|
298
|
-
static async update(
|
|
299
|
-
const path =
|
|
352
|
+
static async update(metadataEntry) {
|
|
353
|
+
const path = metadataEntry.Path;
|
|
300
354
|
try {
|
|
301
|
-
const response = await super.updateSOAP(
|
|
355
|
+
const response = await super.updateSOAP(metadataEntry, 'DataFolder', true);
|
|
302
356
|
if (response) {
|
|
303
|
-
response.
|
|
304
|
-
response.
|
|
305
|
-
delete response.
|
|
306
|
-
Util.logger.info(
|
|
357
|
+
response.Results[0].Object = metadataEntry;
|
|
358
|
+
response.Results[0].Object.CustomerKey = metadataEntry.CustomerKey;
|
|
359
|
+
delete response.Results[0].Object.$;
|
|
360
|
+
Util.logger.info(` - updated folder: ${path}`);
|
|
307
361
|
return response;
|
|
308
362
|
}
|
|
309
363
|
} catch (ex) {
|
|
310
|
-
if (ex
|
|
364
|
+
if (ex?.results) {
|
|
311
365
|
Util.logger.error(
|
|
312
|
-
`${this.definition.type}-${
|
|
366
|
+
`${this.definition.type}-${metadataEntry.ContentType}.update:: error updating: '${path}'. ${ex.results[0].StatusMessage}`
|
|
313
367
|
);
|
|
314
368
|
} else if (ex) {
|
|
315
369
|
Util.logger.error(
|
|
316
|
-
`${this.definition.type}-${
|
|
370
|
+
`${this.definition.type}-${metadataEntry.ContentType}.update:: error updating: '${path}'. ${ex.message}`
|
|
317
371
|
);
|
|
318
372
|
}
|
|
319
373
|
}
|
|
@@ -321,13 +375,14 @@ class Folder extends MetadataType {
|
|
|
321
375
|
|
|
322
376
|
/**
|
|
323
377
|
* prepares a folder for deployment
|
|
324
|
-
*
|
|
325
|
-
* @
|
|
378
|
+
*
|
|
379
|
+
* @param {TYPE.MetadataTypeItem} metadata a single folder definition
|
|
380
|
+
* @returns {Promise.<TYPE.MetadataTypeItem>} Promise of parsed folder metadata
|
|
326
381
|
*/
|
|
327
382
|
static async preDeployTasks(metadata) {
|
|
328
383
|
if (!this.definition.deployFolderTypes.includes(metadata.ContentType.toLowerCase())) {
|
|
329
384
|
Util.logger.warn(
|
|
330
|
-
`Folder ${metadata.Name} is of a type which does not support deployment (Type: ${metadata.ContentType}). Please create this manually in the Web-Interface.`
|
|
385
|
+
` - Folder ${metadata.Name} is of a type which does not support deployment (Type: ${metadata.ContentType}). Please create this manually in the Web-Interface.`
|
|
331
386
|
);
|
|
332
387
|
return;
|
|
333
388
|
}
|
|
@@ -353,9 +408,8 @@ class Folder extends MetadataType {
|
|
|
353
408
|
return;
|
|
354
409
|
}
|
|
355
410
|
// retreive ID based on the matching Path of the parent folder
|
|
356
|
-
else if (metadata
|
|
357
|
-
metadata.ParentFolder.ID =
|
|
358
|
-
this.cache,
|
|
411
|
+
else if (metadata?.ParentFolder?.Path) {
|
|
412
|
+
metadata.ParentFolder.ID = cache.searchForField(
|
|
359
413
|
'folder',
|
|
360
414
|
metadata.ParentFolder.Path,
|
|
361
415
|
'Path',
|
|
@@ -375,9 +429,10 @@ class Folder extends MetadataType {
|
|
|
375
429
|
|
|
376
430
|
/**
|
|
377
431
|
* Returns file contents mapped to their filename without '.json' ending
|
|
378
|
-
*
|
|
432
|
+
*
|
|
433
|
+
* @param {string} dir directory that contains '.json' files to be read
|
|
379
434
|
* @param {boolean} [listBadKeys=false] do not print errors, used for badKeys()
|
|
380
|
-
* @returns {
|
|
435
|
+
* @returns {TYPE.MetadataTypeMap} fileName => fileContent map
|
|
381
436
|
*/
|
|
382
437
|
static getJsonFromFS(dir, listBadKeys) {
|
|
383
438
|
try {
|
|
@@ -407,9 +462,7 @@ class Folder extends MetadataType {
|
|
|
407
462
|
fileContent.ParentFolder = {
|
|
408
463
|
Path: standardSubDir,
|
|
409
464
|
};
|
|
410
|
-
const key = fileContent.CustomerKey
|
|
411
|
-
? fileContent.CustomerKey
|
|
412
|
-
: `new-${++newCounter}`;
|
|
465
|
+
const key = fileContent.CustomerKey || `new-${++newCounter}`;
|
|
413
466
|
if (fileName2FileContent[key]) {
|
|
414
467
|
Util.logger.error(
|
|
415
468
|
`Your have multiple folder-JSONs with the same CustomerKey '${key}' - skipping ${fileName}`
|
|
@@ -445,58 +498,38 @@ class Folder extends MetadataType {
|
|
|
445
498
|
|
|
446
499
|
/**
|
|
447
500
|
* Helper to retrieve the folders as promise
|
|
448
|
-
*
|
|
449
|
-
* @param {
|
|
450
|
-
* @
|
|
501
|
+
*
|
|
502
|
+
* @param {string[]} [additionalFields] Returns specified fields even if their retrieve definition is not set to true
|
|
503
|
+
* @param {boolean} [queryAllAccounts] which queryAllAccounts setting to use
|
|
504
|
+
* @returns {Promise.<object>} soap object
|
|
451
505
|
*/
|
|
452
506
|
static async retrieveHelper(additionalFields, queryAllAccounts) {
|
|
453
|
-
const options = {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
-
});
|
|
470
|
-
});
|
|
471
|
-
// merge results with existing
|
|
472
|
-
Results.push(...response.body.Results);
|
|
473
|
-
// set status for calling again if required
|
|
474
|
-
status = response.body.OverallStatus;
|
|
475
|
-
options.continueRequest = response.body.RequestID;
|
|
476
|
-
if (status === 'MoreDataAvailable') {
|
|
477
|
-
Util.logger.info(
|
|
478
|
-
'- more than ' +
|
|
479
|
-
Results.length +
|
|
480
|
-
' folders in Business Unit - loading next batch...'
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
} while (status === 'MoreDataAvailable');
|
|
484
|
-
return Results;
|
|
507
|
+
const options = { QueryAllAccounts: !!queryAllAccounts };
|
|
508
|
+
const response = await this.client.soap.retrieveBulk(
|
|
509
|
+
'DataFolder',
|
|
510
|
+
this.getFieldNamesToRetrieve(additionalFields).filter(
|
|
511
|
+
(field) => !field.includes('Path')
|
|
512
|
+
),
|
|
513
|
+
options
|
|
514
|
+
);
|
|
515
|
+
return response.Results;
|
|
485
516
|
}
|
|
486
517
|
/**
|
|
487
518
|
* Gets executed after retreive of metadata type
|
|
488
|
-
*
|
|
489
|
-
* @
|
|
519
|
+
*
|
|
520
|
+
* @param {TYPE.MetadataTypeItem} metadata metadata mapped by their keyField
|
|
521
|
+
* @returns {TYPE.MetadataTypeItem} cloned metadata
|
|
490
522
|
*/
|
|
491
523
|
static postRetrieveTasks(metadata) {
|
|
492
524
|
return JSON.parse(JSON.stringify(metadata));
|
|
493
525
|
}
|
|
494
526
|
/**
|
|
495
527
|
* Helper for writing Metadata to disk, used for Retrieve and deploy
|
|
496
|
-
*
|
|
497
|
-
* @param {
|
|
498
|
-
* @param {
|
|
499
|
-
* @
|
|
528
|
+
*
|
|
529
|
+
* @param {object} results metadata results from deploy
|
|
530
|
+
* @param {string} retrieveDir directory where metadata should be stored after deploy/retrieve
|
|
531
|
+
* @param {number} mid current mid for this credential / business unit
|
|
532
|
+
* @returns {Promise.<object>} Promise of saved metadata
|
|
500
533
|
*/
|
|
501
534
|
static async saveResults(results, retrieveDir, mid) {
|
|
502
535
|
const savedResults = {};
|
|
@@ -556,6 +589,5 @@ class Folder extends MetadataType {
|
|
|
556
589
|
|
|
557
590
|
// Assign definition to static attributes
|
|
558
591
|
Folder.definition = require('../MetadataTypeDefinitions').folder;
|
|
559
|
-
Folder.client = undefined;
|
|
560
592
|
|
|
561
593
|
module.exports = Folder;
|
|
@@ -1,34 +1,40 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const TYPE = require('../../types/mcdev.d');
|
|
3
4
|
const MetadataType = require('./MetadataType');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* ImportFile MetadataType
|
|
8
|
+
*
|
|
7
9
|
* @augments MetadataType
|
|
8
10
|
*/
|
|
9
11
|
class FtpLocation extends MetadataType {
|
|
10
12
|
/**
|
|
11
13
|
* Retrieves Metadata of FtpLocation
|
|
12
14
|
* Endpoint /automation/v1/ftplocations/ return all FtpLocations
|
|
13
|
-
*
|
|
14
|
-
* @
|
|
15
|
+
*
|
|
16
|
+
* @param {string} retrieveDir Directory where retrieved metadata directory will be saved
|
|
17
|
+
* @param {void} [_] unused parameter
|
|
18
|
+
* @param {void} [__] unused parameter
|
|
19
|
+
* @param {void} [___] unused parameter
|
|
20
|
+
* @param {string} [key] customer key of single item to retrieve
|
|
21
|
+
* @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise
|
|
15
22
|
*/
|
|
16
|
-
static retrieve(retrieveDir) {
|
|
17
|
-
return super.retrieveREST(retrieveDir, '/automation/v1/ftplocations/', null);
|
|
23
|
+
static retrieve(retrieveDir, _, __, ___, key) {
|
|
24
|
+
return super.retrieveREST(retrieveDir, '/automation/v1/ftplocations/', null, null, key);
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
/**
|
|
21
28
|
* Retrieves folder metadata into local filesystem. Also creates a uniquePath attribute for each folder.
|
|
22
|
-
*
|
|
29
|
+
*
|
|
30
|
+
* @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise
|
|
23
31
|
*/
|
|
24
32
|
static async retrieveForCache() {
|
|
25
|
-
return super.retrieveREST(null, '/automation/v1/ftplocations/'
|
|
33
|
+
return super.retrieveREST(null, '/automation/v1/ftplocations/');
|
|
26
34
|
}
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
// Assign definition to static attributes
|
|
30
38
|
FtpLocation.definition = require('../MetadataTypeDefinitions').ftpLocation;
|
|
31
|
-
FtpLocation.cache = {};
|
|
32
|
-
FtpLocation.client = undefined;
|
|
33
39
|
|
|
34
40
|
module.exports = FtpLocation;
|