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
package/lib/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const TYPE = require('../types/mcdev.d');
|
|
3
4
|
const Util = require('./util/util');
|
|
5
|
+
const auth = require('./util/auth');
|
|
4
6
|
const File = require('./util/file');
|
|
7
|
+
const config = require('./util/config');
|
|
5
8
|
const Init = require('./util/init');
|
|
6
9
|
const InitGit = require('./util/init.git');
|
|
7
10
|
const Cli = require('./util/cli');
|
|
@@ -12,307 +15,133 @@ const Deployer = require('./Deployer');
|
|
|
12
15
|
const MetadataTypeInfo = require('./MetadataTypeInfo');
|
|
13
16
|
const MetadataTypeDefinitions = require('./MetadataTypeDefinitions');
|
|
14
17
|
const Retriever = require('./Retriever');
|
|
15
|
-
const
|
|
16
|
-
let properties;
|
|
18
|
+
const cache = require('./util/cache');
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* main class
|
|
20
22
|
*/
|
|
21
23
|
class Mcdev {
|
|
22
24
|
/**
|
|
23
|
-
*
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
*/
|
|
31
|
-
static async createDeltaPkg(argv) {
|
|
32
|
-
this._setLoggingLevel(argv);
|
|
33
|
-
properties = properties || File.loadConfigFile();
|
|
34
|
-
if (!Util.checkProperties(properties)) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
// get source market and source BU from config
|
|
38
|
-
if (argv.filter) {
|
|
39
|
-
return DevOps.createDeltaPkg(properties, argv.range, true, argv.filter);
|
|
40
|
-
} else {
|
|
41
|
-
// If no custom filter was provided, use deployment marketLists & templating
|
|
42
|
-
|
|
43
|
-
// check if sourceTargetMapping is valid
|
|
44
|
-
if (
|
|
45
|
-
!properties.options.deployment.sourceTargetMapping ||
|
|
46
|
-
!Object.keys(properties.options.deployment.sourceTargetMapping).length
|
|
47
|
-
) {
|
|
48
|
-
Util.logger.error('Bad configuration of options.deployment.sourceTargetMapping');
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const sourceMarketListArr = Object.keys(
|
|
52
|
-
properties.options.deployment.sourceTargetMapping
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
for (const sourceML of sourceMarketListArr) {
|
|
56
|
-
// check if sourceTargetMapping has valid values
|
|
57
|
-
// #1 check source marketlist
|
|
58
|
-
try {
|
|
59
|
-
Builder.verifyMarketList(sourceML, properties);
|
|
60
|
-
// remove potentially existing "description"-entry
|
|
61
|
-
delete properties.marketList[sourceML].description;
|
|
62
|
-
|
|
63
|
-
const sourceMarketBuArr = Object.keys(properties.marketList[sourceML]);
|
|
64
|
-
if (sourceMarketBuArr.length !== 1) {
|
|
65
|
-
throw new Error('Only 1 BU is allowed per source marketList');
|
|
66
|
-
}
|
|
67
|
-
if ('string' !== typeof properties.marketList[sourceML][sourceMarketBuArr[0]]) {
|
|
68
|
-
throw new Error('Only 1 market per BU is allowed per source marketList');
|
|
69
|
-
}
|
|
70
|
-
} catch (ex) {
|
|
71
|
-
Util.logger.error('Deployment Source: ' + ex.message);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
// #2 check corresponding target marketList
|
|
75
|
-
let targetML;
|
|
76
|
-
try {
|
|
77
|
-
targetML = properties.options.deployment.sourceTargetMapping[sourceML];
|
|
78
|
-
if ('string' !== typeof targetML) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
'Please define one target marketList per source in deployment.sourceTargetMapping (No arrays allowed)'
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
Builder.verifyMarketList(targetML, properties);
|
|
84
|
-
// remove potentially existing "description"-entry
|
|
85
|
-
delete properties.marketList[targetML].description;
|
|
86
|
-
} catch (ex) {
|
|
87
|
-
Util.logger.error('Deployment Target: ' + ex.message);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// all good let's loop a second time for actual execution
|
|
91
|
-
for (const sourceMlName of sourceMarketListArr) {
|
|
92
|
-
const targetMlName =
|
|
93
|
-
properties.options.deployment.sourceTargetMapping[sourceMlName];
|
|
94
|
-
const sourceBU = Object.keys(properties.marketList[sourceMlName])[0];
|
|
95
|
-
const sourceMarket = Object.values(properties.marketList[sourceMlName])[0];
|
|
96
|
-
|
|
97
|
-
const delta = await DevOps.createDeltaPkg(properties, argv.range, false, sourceBU);
|
|
98
|
-
// If only chaing templating and buildDefinition if required
|
|
99
|
-
if (!delta || delta.length === 0) {
|
|
100
|
-
// info/error messages was printed by DevOps.createDeltaPkg() already
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
Util.logger.info('=============');
|
|
104
|
-
|
|
105
|
-
// Put files into maps. One map with BU -> type -> file (for retrieveAsTemplate)
|
|
106
|
-
// Other map only with type -> file (for buildDefinitionBulk)
|
|
107
|
-
const buTypeDelta = {};
|
|
108
|
-
const typeDelta = {};
|
|
109
|
-
delta
|
|
110
|
-
// Only template/build files that were added/updated/moved. no deletions
|
|
111
|
-
// ! doesn't work for folder, because their name parsing doesnt work at the moment
|
|
112
|
-
.filter((file) => file.gitAction !== 'delete' && file.name)
|
|
113
|
-
.forEach((file) => {
|
|
114
|
-
const buPath = `${file._credential}/${file._businessUnit}`;
|
|
115
|
-
if (!buTypeDelta[buPath]) {
|
|
116
|
-
buTypeDelta[buPath] = {};
|
|
117
|
-
}
|
|
118
|
-
if (!buTypeDelta[buPath][file.type]) {
|
|
119
|
-
buTypeDelta[buPath][file.type] = [];
|
|
120
|
-
}
|
|
121
|
-
buTypeDelta[buPath][file.type].push(file.name);
|
|
122
|
-
|
|
123
|
-
if (!typeDelta[file.type]) {
|
|
124
|
-
typeDelta[file.type] = [];
|
|
125
|
-
}
|
|
126
|
-
typeDelta[file.type].push(file.name);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// Run retrieve as template for each business unit for each type
|
|
130
|
-
Util.logger.info('Retrieve template from Git delta');
|
|
131
|
-
// ! needs to be for (.. in ..) loop so that it gets executed in series
|
|
132
|
-
for (const bu in buTypeDelta) {
|
|
133
|
-
for (const type in buTypeDelta[bu]) {
|
|
134
|
-
Util.logger.info(
|
|
135
|
-
`⚡ mcdev rt ${bu} ${type} "${buTypeDelta[bu][type].join(
|
|
136
|
-
','
|
|
137
|
-
)}" ${sourceMarket}`
|
|
138
|
-
);
|
|
139
|
-
await this.retrieveAsTemplate(
|
|
140
|
-
bu,
|
|
141
|
-
type,
|
|
142
|
-
buTypeDelta[bu][type].join(','),
|
|
143
|
-
sourceMarket
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Run build definitions bulk for each type
|
|
149
|
-
Util.logger.info(`- ✔️ Templates created`);
|
|
150
|
-
Util.logger.info('=============');
|
|
151
|
-
Util.logger.info('Build definitions from delta templates');
|
|
152
|
-
if (
|
|
153
|
-
properties.directories.templateBuilds == properties.directories.deploy ||
|
|
154
|
-
(Array.isArray(properties.directories.templateBuilds) &&
|
|
155
|
-
properties.directories.templateBuilds.includes(
|
|
156
|
-
properties.directories.deploy
|
|
157
|
-
))
|
|
158
|
-
) {
|
|
159
|
-
let responses;
|
|
160
|
-
if (!argv.skipInteraction) {
|
|
161
|
-
// deploy folder is in targets for definition creation
|
|
162
|
-
// recommend to purge their content first
|
|
163
|
-
const questions = [
|
|
164
|
-
{
|
|
165
|
-
type: 'confirm',
|
|
166
|
-
name: 'isPurgeDeployFolder',
|
|
167
|
-
message:
|
|
168
|
-
'Do you want to empty the deploy folder (ensures no files from previous deployments remain)?',
|
|
169
|
-
default: true,
|
|
170
|
-
},
|
|
171
|
-
];
|
|
172
|
-
responses = await new Promise((resolve) => {
|
|
173
|
-
inquirer.prompt(questions).then((answers) => {
|
|
174
|
-
resolve(answers);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
if (argv.skipInteraction || responses.isPurgeDeployFolders) {
|
|
179
|
-
// Clear output folder structure for selected sub-type
|
|
180
|
-
File.removeSync(File.normalizePath([properties.directories.deploy]));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
const bdPromises = [];
|
|
184
|
-
for (const type in typeDelta) {
|
|
185
|
-
Util.logger.info(
|
|
186
|
-
`⚡ mcdev bdb ${targetMlName} ${type} "${typeDelta[type].join(',')}"`
|
|
187
|
-
);
|
|
188
|
-
// omitting "await" to speed up creation
|
|
189
|
-
bdPromises.push(
|
|
190
|
-
this.buildDefinitionBulk(targetMlName, type, typeDelta[type].join(','))
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
await Promise.all(bdPromises);
|
|
194
|
-
Util.logger.info(`- ✔️ Deploy defintions created`);
|
|
195
|
-
if (
|
|
196
|
-
properties.directories.templateBuilds == properties.directories.deploy ||
|
|
197
|
-
(Array.isArray(properties.directories.templateBuilds) &&
|
|
198
|
-
properties.directories.templateBuilds.includes(
|
|
199
|
-
properties.directories.deploy
|
|
200
|
-
))
|
|
201
|
-
) {
|
|
202
|
-
Util.logger.info(`You can now run deploy on the prepared BUs`);
|
|
203
|
-
} else {
|
|
204
|
-
Util.logger.info(
|
|
205
|
-
`Your templated defintions are now ready to be copied into the deploy folder. Hint: You can have this auto-copied if you adjust directories.templateBuilds in your config.`
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
25
|
+
* helper method to use unattended mode when including mcdev as a package
|
|
26
|
+
*
|
|
27
|
+
* @param {boolean | TYPE.skipInteraction} [skipInteraction] signals what to insert automatically for things usually asked via wizard
|
|
28
|
+
* @returns {void}
|
|
29
|
+
*/
|
|
30
|
+
static setSkipInteraction(skipInteraction) {
|
|
31
|
+
Util.skipInteraction = skipInteraction;
|
|
210
32
|
}
|
|
211
|
-
|
|
212
33
|
/**
|
|
213
34
|
* configures what is displayed in the console
|
|
35
|
+
*
|
|
214
36
|
* @param {object} argv list of command line parameters given by user
|
|
215
|
-
* @param {
|
|
216
|
-
* @param {
|
|
217
|
-
* @param {
|
|
37
|
+
* @param {boolean} [argv.silent] only errors printed to CLI
|
|
38
|
+
* @param {boolean} [argv.verbose] chatty user CLI output
|
|
39
|
+
* @param {boolean} [argv.debug] enables developer output & features
|
|
218
40
|
* @returns {void}
|
|
219
41
|
*/
|
|
220
|
-
static
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
42
|
+
static setLoggingLevel(argv) {
|
|
43
|
+
Util.setLoggingLevel(argv);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* handler for 'mcdev createDeltaPkg
|
|
47
|
+
*
|
|
48
|
+
* @param {object} argv yargs parameters
|
|
49
|
+
* @param {string} [argv.range] git commit range
|
|
50
|
+
into deploy directory
|
|
51
|
+
* @param {string} [argv.filter] filter file paths that start with any
|
|
52
|
+
* @param {TYPE.skipInteraction} [argv.skipInteraction] allows to skip interactive wizard
|
|
53
|
+
* @returns {Promise.<TYPE.DeltaPkgItem[]>} list of changed items
|
|
54
|
+
*/
|
|
55
|
+
static async createDeltaPkg(argv) {
|
|
56
|
+
Util.logger.info('Create Delta Package ::');
|
|
57
|
+
Mcdev.setSkipInteraction(argv.skipInteraction);
|
|
58
|
+
const properties = await config.getProperties();
|
|
59
|
+
if (!(await config.checkProperties(properties))) {
|
|
60
|
+
return null;
|
|
238
61
|
}
|
|
62
|
+
|
|
63
|
+
return argv.filter
|
|
64
|
+
? // get source market and source BU from config
|
|
65
|
+
DevOps.getDeltaList(properties, argv.range, true, argv.filter)
|
|
66
|
+
: // If no custom filter was provided, use deployment marketLists & templating
|
|
67
|
+
DevOps.buildDeltaDefinitions(properties, argv.range, argv.skipInteraction);
|
|
239
68
|
}
|
|
240
69
|
|
|
241
70
|
/**
|
|
242
71
|
* @returns {Promise} .
|
|
243
72
|
*/
|
|
244
73
|
static async selectTypes() {
|
|
245
|
-
properties =
|
|
246
|
-
if (!
|
|
74
|
+
const properties = await config.getProperties();
|
|
75
|
+
if (!(await config.checkProperties(properties))) {
|
|
247
76
|
return null;
|
|
248
77
|
}
|
|
249
78
|
await Cli.selectTypes(properties);
|
|
250
79
|
}
|
|
251
80
|
/**
|
|
252
|
-
* @returns {
|
|
81
|
+
* @returns {void}
|
|
253
82
|
*/
|
|
254
83
|
static explainTypes() {
|
|
255
84
|
Cli.explainTypes();
|
|
256
85
|
}
|
|
257
86
|
/**
|
|
258
|
-
* @param {
|
|
259
|
-
* @returns {Promise}
|
|
87
|
+
* @param {boolean | TYPE.skipInteraction} [skipInteraction] signals what to insert automatically for things usually asked via wizard
|
|
88
|
+
* @returns {Promise.<boolean>} success flag
|
|
260
89
|
*/
|
|
261
90
|
static async upgrade(skipInteraction) {
|
|
262
|
-
|
|
91
|
+
Mcdev.setSkipInteraction(skipInteraction);
|
|
92
|
+
const properties = await config.getProperties();
|
|
263
93
|
if (!properties) {
|
|
264
94
|
Util.logger.error('No config found. Please run mcdev init');
|
|
265
|
-
return;
|
|
95
|
+
return false;
|
|
266
96
|
}
|
|
267
97
|
if ((await InitGit.initGitRepo(skipInteraction)).status === 'error') {
|
|
268
|
-
return;
|
|
98
|
+
return false;
|
|
269
99
|
}
|
|
270
100
|
|
|
271
|
-
Init.upgradeProject(properties, false);
|
|
101
|
+
return Init.upgradeProject(properties, false);
|
|
272
102
|
}
|
|
273
103
|
|
|
274
104
|
/**
|
|
275
105
|
* Retrieve all metadata from the specified business unit into the local file system.
|
|
276
|
-
*
|
|
277
|
-
* @param {
|
|
106
|
+
*
|
|
107
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
108
|
+
* @param {string[]} [selectedTypesArr] limit retrieval to given metadata type
|
|
109
|
+
* @param {string[]} [keys] limit retrieval to given metadata key
|
|
278
110
|
* @param {boolean} [changelogOnly] skip saving, only create json in memory
|
|
279
|
-
* @returns {Promise
|
|
111
|
+
* @returns {Promise.<object>} -
|
|
280
112
|
*/
|
|
281
|
-
static async retrieve(businessUnit,
|
|
113
|
+
static async retrieve(businessUnit, selectedTypesArr, keys, changelogOnly) {
|
|
282
114
|
Util.logger.info('mcdev:: Retrieve');
|
|
283
|
-
properties =
|
|
284
|
-
if (!
|
|
115
|
+
const properties = await config.getProperties();
|
|
116
|
+
if (!(await config.checkProperties(properties))) {
|
|
285
117
|
// return null here to avoid seeing 2 error messages for the same issue
|
|
286
118
|
return null;
|
|
287
119
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
) {
|
|
297
|
-
Util.logger.error(`:: '${selectedType}' is not a valid metadata type`);
|
|
298
|
-
return;
|
|
120
|
+
|
|
121
|
+
// assume a list was passed in and check each entry's validity
|
|
122
|
+
if (selectedTypesArr) {
|
|
123
|
+
for (const selectedType of selectedTypesArr) {
|
|
124
|
+
if (!Util._isValidType(selectedType)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
299
128
|
}
|
|
300
129
|
|
|
301
130
|
if (businessUnit === '*') {
|
|
302
|
-
Util.logger.info('\n:: Retrieving all BUs for all credentials');
|
|
131
|
+
Util.logger.info('\n :: Retrieving all BUs for all credentials');
|
|
303
132
|
let counter_credTotal = 0;
|
|
304
133
|
for (const cred in properties.credentials) {
|
|
305
|
-
Util.logger.info(`\n:: Retrieving all BUs for ${cred}`);
|
|
134
|
+
Util.logger.info(`\n :: Retrieving all BUs for ${cred}`);
|
|
306
135
|
let counter_credBu = 0;
|
|
307
136
|
for (const bu in properties.credentials[cred].businessUnits) {
|
|
308
|
-
await this._retrieveBU(cred, bu,
|
|
137
|
+
await this._retrieveBU(cred, bu, selectedTypesArr, keys);
|
|
309
138
|
counter_credBu++;
|
|
310
139
|
Util.restartLogger();
|
|
311
140
|
}
|
|
312
141
|
counter_credTotal += counter_credBu;
|
|
313
|
-
Util.logger.info(`\n:: ${counter_credBu} BUs for ${cred}\n`);
|
|
142
|
+
Util.logger.info(`\n :: ${counter_credBu} BUs for ${cred}\n`);
|
|
314
143
|
}
|
|
315
|
-
Util.logger.info(`\n:: ${counter_credTotal} BUs in total\n`);
|
|
144
|
+
Util.logger.info(`\n :: ${counter_credTotal} BUs in total\n`);
|
|
316
145
|
} else {
|
|
317
146
|
let [cred, bu] = businessUnit ? businessUnit.split('/') : [null, null];
|
|
318
147
|
// to allow all-BU via user selection we need to run this here already
|
|
@@ -336,20 +165,21 @@ class Mcdev {
|
|
|
336
165
|
}
|
|
337
166
|
|
|
338
167
|
if (bu === '*' && properties.credentials && properties.credentials[cred]) {
|
|
339
|
-
Util.logger.info(`\n:: Retrieving all BUs for ${cred}`);
|
|
168
|
+
Util.logger.info(`\n :: Retrieving all BUs for ${cred}`);
|
|
340
169
|
let counter_credBu = 0;
|
|
341
170
|
for (const bu in properties.credentials[cred].businessUnits) {
|
|
342
|
-
await this._retrieveBU(cred, bu,
|
|
171
|
+
await this._retrieveBU(cred, bu, selectedTypesArr, keys);
|
|
343
172
|
counter_credBu++;
|
|
344
173
|
Util.restartLogger();
|
|
345
174
|
}
|
|
346
|
-
Util.logger.info(`\n:: ${counter_credBu} BUs for ${cred}\n`);
|
|
175
|
+
Util.logger.info(`\n :: ${counter_credBu} BUs for ${cred}\n`);
|
|
347
176
|
} else {
|
|
348
177
|
// retrieve a single BU; return
|
|
349
178
|
const retrieveChangelog = await this._retrieveBU(
|
|
350
179
|
cred,
|
|
351
180
|
bu,
|
|
352
|
-
|
|
181
|
+
selectedTypesArr,
|
|
182
|
+
keys,
|
|
353
183
|
changelogOnly
|
|
354
184
|
);
|
|
355
185
|
if (changelogOnly) {
|
|
@@ -361,14 +191,20 @@ class Mcdev {
|
|
|
361
191
|
}
|
|
362
192
|
/**
|
|
363
193
|
* helper for retrieve()
|
|
364
|
-
*
|
|
365
|
-
* @
|
|
366
|
-
* @param {
|
|
194
|
+
*
|
|
195
|
+
* @private
|
|
196
|
+
* @param {string} cred name of Credential
|
|
197
|
+
* @param {string} bu name of BU
|
|
198
|
+
* @param {string[]} [selectedTypesArr] limit retrieval to given metadata type/subtype
|
|
199
|
+
* @param {string[]} [keys] limit retrieval to given metadata key
|
|
367
200
|
* @param {boolean} [changelogOnly] skip saving, only create json in memory
|
|
368
|
-
* @returns {Promise
|
|
201
|
+
* @returns {Promise.<object>} ensure that BUs are worked on sequentially
|
|
369
202
|
*/
|
|
370
|
-
static async _retrieveBU(cred, bu,
|
|
371
|
-
properties =
|
|
203
|
+
static async _retrieveBU(cred, bu, selectedTypesArr, keys, changelogOnly) {
|
|
204
|
+
const properties = await config.getProperties();
|
|
205
|
+
if (!(await config.checkProperties(properties))) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
372
208
|
const buObject = await Cli.getCredentialObject(
|
|
373
209
|
properties,
|
|
374
210
|
cred !== null ? cred + '/' + bu : null,
|
|
@@ -376,216 +212,101 @@ class Mcdev {
|
|
|
376
212
|
true
|
|
377
213
|
);
|
|
378
214
|
if (buObject !== null) {
|
|
215
|
+
cache.initCache(buObject);
|
|
379
216
|
cred = buObject.credential;
|
|
380
217
|
bu = buObject.businessUnit;
|
|
381
|
-
Util.logger.info(`\n:: Retrieving ${cred}/${bu}\n`);
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
218
|
+
Util.logger.info(`\n :: Retrieving ${cred}/${bu}\n`);
|
|
219
|
+
const retrieveTypesArr = [];
|
|
220
|
+
if (selectedTypesArr) {
|
|
221
|
+
for (const selectedType of selectedTypesArr) {
|
|
222
|
+
const [type, subType] = selectedType ? selectedType.split('-') : [];
|
|
223
|
+
const removePathArr = [properties.directories.retrieve, cred, bu, type];
|
|
224
|
+
if (
|
|
225
|
+
type &&
|
|
226
|
+
subType &&
|
|
227
|
+
MetadataTypeInfo[type] &&
|
|
228
|
+
MetadataTypeDefinitions[type].subTypes.includes(subType)
|
|
229
|
+
) {
|
|
230
|
+
// Clear output folder structure for selected sub-type
|
|
231
|
+
removePathArr.push(subType);
|
|
232
|
+
retrieveTypesArr.push(selectedType);
|
|
233
|
+
} else if (type && MetadataTypeInfo[type]) {
|
|
234
|
+
// Clear output folder structure for selected type
|
|
235
|
+
retrieveTypesArr.push(type);
|
|
236
|
+
}
|
|
237
|
+
if (!keys) {
|
|
238
|
+
// dont delete directories if we are just re-retrieving a single file
|
|
239
|
+
await File.remove(File.normalizePath(removePathArr));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (!retrieveTypesArr.length) {
|
|
244
|
+
// assume no type was given and config settings are used instead:
|
|
402
245
|
// Clear output folder structure
|
|
403
246
|
File.removeSync(File.normalizePath([properties.directories.retrieve, cred, bu]));
|
|
404
|
-
// assume no type was given and config settings are used instead:
|
|
405
247
|
// removes subtypes and removes duplicates
|
|
406
|
-
retrieveTypesArr
|
|
407
|
-
...new Set(properties.metaDataTypes.retrieve.map((type) => type.split('-')[0]))
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
let client;
|
|
411
|
-
try {
|
|
412
|
-
client = await Util.getETClient(buObject);
|
|
413
|
-
} catch (ex) {
|
|
414
|
-
Util.logger.error(ex.message);
|
|
415
|
-
return;
|
|
248
|
+
retrieveTypesArr.push(
|
|
249
|
+
...new Set(properties.metaDataTypes.retrieve.map((type) => type.split('-')[0]))
|
|
250
|
+
);
|
|
416
251
|
}
|
|
417
|
-
const retriever = new Retriever(properties, buObject
|
|
252
|
+
const retriever = new Retriever(properties, buObject);
|
|
418
253
|
|
|
419
254
|
try {
|
|
420
255
|
// await is required or the calls end up conflicting
|
|
421
256
|
const retrieveChangelog = await retriever.retrieve(
|
|
422
257
|
retrieveTypesArr,
|
|
423
|
-
|
|
258
|
+
keys,
|
|
424
259
|
null,
|
|
425
260
|
changelogOnly
|
|
426
261
|
);
|
|
427
262
|
if (changelogOnly) {
|
|
428
263
|
return retrieveChangelog;
|
|
429
264
|
}
|
|
430
|
-
if (properties.options.documentOnRetrieve) {
|
|
431
|
-
// todo: find the underlying async issue that makes this wait necessary
|
|
432
|
-
await new Promise((resolve) => {
|
|
433
|
-
setTimeout(() => resolve('done!'), 1000);
|
|
434
|
-
});
|
|
435
|
-
await this.badKeys(`${cred}/${bu}`);
|
|
436
|
-
}
|
|
437
265
|
} catch (ex) {
|
|
438
|
-
Util.logger.
|
|
439
|
-
Util.logger.debug(ex.stack);
|
|
440
|
-
if (Util.logger.level === 'debug') {
|
|
441
|
-
console.log(ex.stack);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* helper for deploy()
|
|
448
|
-
* @param {String} cred name of Credential
|
|
449
|
-
* @param {String} bu name of BU
|
|
450
|
-
* @param {String} [type] limit deployment to given metadata type
|
|
451
|
-
* @returns {Promise} ensure that BUs are worked on sequentially
|
|
452
|
-
*/
|
|
453
|
-
static async _deployBU(cred, bu, type) {
|
|
454
|
-
const buPath = `${cred}/${bu}`;
|
|
455
|
-
Util.logger.info(`::Deploying ${buPath}`);
|
|
456
|
-
properties = properties || File.loadConfigFile();
|
|
457
|
-
const buObject = await Cli.getCredentialObject(properties, buPath, null, true);
|
|
458
|
-
if (buObject !== null) {
|
|
459
|
-
let client;
|
|
460
|
-
try {
|
|
461
|
-
client = await Util.getETClient(buObject);
|
|
462
|
-
} catch (ex) {
|
|
463
|
-
Util.logger.error(ex.message);
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
const deployer = new Deployer(properties, buObject, client, type);
|
|
467
|
-
try {
|
|
468
|
-
// await is required or the calls end up conflicting
|
|
469
|
-
await deployer.deploy();
|
|
470
|
-
} catch (ex) {
|
|
471
|
-
Util.logger.error('mcdev.deploy failed: ' + ex.message);
|
|
472
|
-
Util.logger.debug(ex.stack);
|
|
473
|
-
if (Util.logger.level === 'debug') {
|
|
474
|
-
console.log(ex.stack);
|
|
475
|
-
}
|
|
266
|
+
Util.logger.errorStack(ex, 'mcdev.retrieve failed');
|
|
476
267
|
}
|
|
477
268
|
}
|
|
478
269
|
}
|
|
479
270
|
|
|
480
271
|
/**
|
|
481
272
|
* Deploys all metadata located in the 'deploy' directory to the specified business unit
|
|
482
|
-
*
|
|
483
|
-
* @param {
|
|
484
|
-
* @
|
|
273
|
+
*
|
|
274
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
275
|
+
* @param {string[]} [selectedTypesArr] limit deployment to given metadata type
|
|
276
|
+
* @param {string[]} [keyArr] limit deployment to given metadata keys
|
|
277
|
+
* @param {boolean} [fromRetrieve] optionally deploy whats defined via selectedTypesArr + keyArr directly from retrieve folder instead of from deploy folder
|
|
278
|
+
* @returns {Promise.<void>} -
|
|
485
279
|
*/
|
|
486
|
-
static async deploy(businessUnit,
|
|
487
|
-
|
|
488
|
-
properties = properties || File.loadConfigFile();
|
|
489
|
-
|
|
490
|
-
const [type, subType] = selectedType ? selectedType.split('-') : [];
|
|
491
|
-
if (type && !MetadataTypeInfo[type]) {
|
|
492
|
-
Util.logger.error(`:: '${type}' is not a valid metadata type`);
|
|
493
|
-
return;
|
|
494
|
-
} else if (
|
|
495
|
-
type &&
|
|
496
|
-
subType &&
|
|
497
|
-
(!MetadataTypeInfo[type] || !MetadataTypeDefinitions[type].subTypes.includes(subType))
|
|
498
|
-
) {
|
|
499
|
-
Util.logger.error(`:: '${selectedType}' is not a valid metadata type`);
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
let counter_credBu = 0;
|
|
503
|
-
if (businessUnit === '*') {
|
|
504
|
-
// all credentials and all BUs shall be deployed to
|
|
505
|
-
const deployFolders = await File.readDirectories(
|
|
506
|
-
properties.directories.deploy,
|
|
507
|
-
2,
|
|
508
|
-
false
|
|
509
|
-
);
|
|
510
|
-
for (const buPath of deployFolders.filter((r) => r.includes('/'))) {
|
|
511
|
-
const [cred, bu] = buPath.split('/');
|
|
512
|
-
await this._deployBU(cred, bu, type);
|
|
513
|
-
counter_credBu++;
|
|
514
|
-
Util.logger.info('');
|
|
515
|
-
Util.restartLogger();
|
|
516
|
-
}
|
|
517
|
-
} else {
|
|
518
|
-
// anything but "*" passed in
|
|
519
|
-
let [cred, bu] = businessUnit ? businessUnit.split('/') : [null, null];
|
|
520
|
-
|
|
521
|
-
// to allow all-BU via user selection we need to run this here already
|
|
522
|
-
if (
|
|
523
|
-
properties.credentials &&
|
|
524
|
-
(!properties.credentials[cred] ||
|
|
525
|
-
(bu !== '*' && properties.credentials[cred].businessUnits[bu]))
|
|
526
|
-
) {
|
|
527
|
-
const buObject = await Cli.getCredentialObject(
|
|
528
|
-
properties,
|
|
529
|
-
cred !== null ? cred + '/' + bu : null,
|
|
530
|
-
null,
|
|
531
|
-
true
|
|
532
|
-
);
|
|
533
|
-
if (buObject !== null) {
|
|
534
|
-
cred = buObject.credential;
|
|
535
|
-
bu = buObject.businessUnit;
|
|
536
|
-
} else {
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
if (bu === '*' && properties.credentials && properties.credentials[cred]) {
|
|
542
|
-
// valid credential given and -all- BUs targeted
|
|
543
|
-
Util.logger.info(`\n:: Deploying all BUs for ${cred}`);
|
|
544
|
-
let counter_credBu = 0;
|
|
545
|
-
// for (const bu in properties.credentials[cred].businessUnits) {
|
|
546
|
-
const deployFolders = await File.readDirectories(
|
|
547
|
-
File.normalizePath([properties.directories.deploy, cred]),
|
|
548
|
-
1,
|
|
549
|
-
false
|
|
550
|
-
);
|
|
551
|
-
for (const buPath of deployFolders) {
|
|
552
|
-
await this._deployBU(cred, buPath, type);
|
|
553
|
-
counter_credBu++;
|
|
554
|
-
Util.logger.info('');
|
|
555
|
-
Util.restartLogger();
|
|
556
|
-
}
|
|
557
|
-
Util.logger.info(`\n:: ${counter_credBu} BUs for ${cred}\n`);
|
|
558
|
-
} else {
|
|
559
|
-
// either bad credential or specific BU or no BU given
|
|
560
|
-
await this._deployBU(cred, bu, type);
|
|
561
|
-
counter_credBu++;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
if (counter_credBu !== 0) {
|
|
565
|
-
Util.logger.info(`\n:: Deployed ${counter_credBu} BUs\n`);
|
|
566
|
-
}
|
|
280
|
+
static async deploy(businessUnit, selectedTypesArr, keyArr, fromRetrieve = false) {
|
|
281
|
+
return Deployer.deploy(businessUnit, selectedTypesArr, keyArr, fromRetrieve);
|
|
567
282
|
}
|
|
568
283
|
|
|
569
284
|
/**
|
|
570
285
|
* Creates template file for properties.json
|
|
286
|
+
*
|
|
571
287
|
* @param {string} [credentialsName] identifying name of the installed package / project
|
|
572
|
-
* @param {
|
|
573
|
-
* @returns {Promise
|
|
288
|
+
* @param {boolean | TYPE.skipInteraction} [skipInteraction] signals what to insert automatically for things usually asked via wizard
|
|
289
|
+
* @returns {Promise.<void>} -
|
|
574
290
|
*/
|
|
575
291
|
static async initProject(credentialsName, skipInteraction) {
|
|
576
292
|
Util.logger.info('mcdev:: Setting up project');
|
|
577
|
-
|
|
293
|
+
Mcdev.setSkipInteraction(skipInteraction);
|
|
294
|
+
const properties = await config.getProperties(!!credentialsName);
|
|
578
295
|
await Init.initProject(properties, credentialsName, skipInteraction);
|
|
579
296
|
}
|
|
580
297
|
|
|
581
298
|
/**
|
|
582
299
|
* Refreshes BU names and ID's from MC instance
|
|
300
|
+
*
|
|
583
301
|
* @param {string} credentialsName identifying name of the installed package / project
|
|
584
|
-
* @returns {Promise
|
|
302
|
+
* @returns {Promise.<void>} -
|
|
585
303
|
*/
|
|
586
304
|
static async findBUs(credentialsName) {
|
|
587
305
|
Util.logger.info('mcdev:: Load BUs');
|
|
588
|
-
properties =
|
|
306
|
+
const properties = await config.getProperties();
|
|
307
|
+
if (!(await config.checkProperties(properties))) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
589
310
|
const buObject = await Cli.getCredentialObject(properties, credentialsName, true);
|
|
590
311
|
if (buObject !== null) {
|
|
591
312
|
BuHelper.refreshBUProperties(properties, buObject.credential);
|
|
@@ -595,19 +316,22 @@ class Mcdev {
|
|
|
595
316
|
/**
|
|
596
317
|
* Creates docs for supported metadata types in Markdown and/or HTML format
|
|
597
318
|
*
|
|
598
|
-
* @param {
|
|
599
|
-
* @param {
|
|
600
|
-
* @returns {Promise
|
|
319
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
320
|
+
* @param {string} type metadata type
|
|
321
|
+
* @returns {Promise.<void>} -
|
|
601
322
|
*/
|
|
602
323
|
static async document(businessUnit, type) {
|
|
603
324
|
Util.logger.info('mcdev:: Document');
|
|
604
|
-
properties =
|
|
325
|
+
const properties = await config.getProperties();
|
|
326
|
+
if (!(await config.checkProperties(properties))) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
605
329
|
if (type && !MetadataTypeInfo[type]) {
|
|
606
330
|
Util.logger.error(`:: '${type}' is not a valid metadata type`);
|
|
607
331
|
return;
|
|
608
332
|
}
|
|
609
333
|
try {
|
|
610
|
-
const parentBUOnlyTypes = ['role'];
|
|
334
|
+
const parentBUOnlyTypes = ['accountUser', 'role'];
|
|
611
335
|
const buObject = await Cli.getCredentialObject(
|
|
612
336
|
properties,
|
|
613
337
|
parentBUOnlyTypes.includes(type) ? businessUnit.split('/')[0] : businessUnit,
|
|
@@ -629,20 +353,29 @@ class Mcdev {
|
|
|
629
353
|
/**
|
|
630
354
|
* Creates docs for supported metadata types in Markdown and/or HTML format
|
|
631
355
|
*
|
|
632
|
-
* @param {
|
|
633
|
-
* @param {
|
|
634
|
-
* @param {
|
|
635
|
-
* @returns {Promise
|
|
356
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
357
|
+
* @param {string} type supported metadata type
|
|
358
|
+
* @param {string} customerKey Identifier of data extension
|
|
359
|
+
* @returns {Promise.<void>} -
|
|
636
360
|
*/
|
|
637
361
|
static async deleteByKey(businessUnit, type, customerKey) {
|
|
638
362
|
Util.logger.info('mcdev:: delete');
|
|
639
|
-
properties =
|
|
363
|
+
const properties = await config.getProperties();
|
|
364
|
+
if (!(await config.checkProperties(properties))) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
640
367
|
const buObject = await Cli.getCredentialObject(properties, businessUnit);
|
|
641
368
|
if (buObject !== null) {
|
|
642
369
|
if ('string' !== typeof type) {
|
|
643
370
|
Util.logger.error('mcdev.delete failed: Bad metadata type passed in');
|
|
644
371
|
return;
|
|
645
372
|
}
|
|
373
|
+
try {
|
|
374
|
+
MetadataTypeInfo[type].client = auth.getSDK(buObject);
|
|
375
|
+
} catch (ex) {
|
|
376
|
+
Util.logger.error(ex.message);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
646
379
|
try {
|
|
647
380
|
MetadataTypeInfo[type].properties = properties;
|
|
648
381
|
MetadataTypeInfo[type].deleteByKey(buObject, customerKey);
|
|
@@ -654,11 +387,15 @@ class Mcdev {
|
|
|
654
387
|
|
|
655
388
|
/**
|
|
656
389
|
* Converts metadata to legacy format. Output is saved in 'converted' directory
|
|
657
|
-
*
|
|
658
|
-
* @
|
|
390
|
+
*
|
|
391
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
392
|
+
* @returns {Promise.<void>} -
|
|
659
393
|
*/
|
|
660
394
|
static async badKeys(businessUnit) {
|
|
661
|
-
properties =
|
|
395
|
+
const properties = await config.getProperties();
|
|
396
|
+
if (!(await config.checkProperties(properties))) {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
662
399
|
const buObject = await Cli.getCredentialObject(properties, businessUnit);
|
|
663
400
|
if (buObject !== null) {
|
|
664
401
|
Util.logger.info('Gathering list of Name<>External Key mismatches (bad keys)');
|
|
@@ -669,29 +406,23 @@ class Mcdev {
|
|
|
669
406
|
buObject.businessUnit,
|
|
670
407
|
])
|
|
671
408
|
);
|
|
672
|
-
const docPath = File.
|
|
673
|
-
properties.directories.
|
|
674
|
-
|
|
409
|
+
const docPath = File.normalizePath([
|
|
410
|
+
properties.directories.docs,
|
|
411
|
+
'badKeys',
|
|
412
|
+
buObject.credential,
|
|
413
|
+
]);
|
|
675
414
|
const filename = File.normalizePath([
|
|
676
415
|
docPath,
|
|
677
416
|
File.filterIllegalFilenames(buObject.businessUnit) + '.badKeys.md',
|
|
678
417
|
]);
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
} else if (File.existsSync(filename)) {
|
|
418
|
+
await File.ensureDir(docPath);
|
|
419
|
+
if (await File.pathExistsSync(filename)) {
|
|
682
420
|
File.removeSync(filename);
|
|
683
421
|
}
|
|
684
422
|
|
|
685
|
-
const regex = RegExp('(\\w+-){4}\\w+');
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
metadata = Deployer.readBUMetadata(retrieveDir, null, true);
|
|
689
|
-
} else {
|
|
690
|
-
Util.logger.warn(
|
|
691
|
-
`Looks like ${retrieveDir} does not exist. If there was no metadata retrieved this is expected, in other cases re-run retrieve to attempt to fix this issue`
|
|
692
|
-
);
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
423
|
+
const regex = new RegExp('(\\w+-){4}\\w+');
|
|
424
|
+
await File.ensureDir(retrieveDir);
|
|
425
|
+
const metadata = Deployer.readBUMetadata(retrieveDir, null, true);
|
|
695
426
|
let output = '# List of Metadata with Name-Key mismatches\n';
|
|
696
427
|
for (const metadataType in metadata) {
|
|
697
428
|
let listEntries = '';
|
|
@@ -726,27 +457,23 @@ class Mcdev {
|
|
|
726
457
|
|
|
727
458
|
/**
|
|
728
459
|
* Retrieve a specific metadata file and templatise.
|
|
729
|
-
*
|
|
730
|
-
* @param {
|
|
731
|
-
* @param {
|
|
732
|
-
* @param {
|
|
733
|
-
* @
|
|
460
|
+
*
|
|
461
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
462
|
+
* @param {string} selectedType supported metadata type
|
|
463
|
+
* @param {string[]} name name of the metadata
|
|
464
|
+
* @param {string} market market which should be used to revert template
|
|
465
|
+
* @returns {Promise.<TYPE.MultiMetadataTypeList>} -
|
|
734
466
|
*/
|
|
735
467
|
static async retrieveAsTemplate(businessUnit, selectedType, name, market) {
|
|
736
468
|
Util.logger.info('mcdev:: Retrieve as Template');
|
|
737
|
-
properties =
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
} else if (
|
|
743
|
-
type &&
|
|
744
|
-
subType &&
|
|
745
|
-
(!MetadataTypeInfo[type] || !MetadataTypeDefinitions[type].subTypes.includes(subType))
|
|
746
|
-
) {
|
|
747
|
-
Util.logger.error(`:: '${selectedType}' is not a valid metadata type`);
|
|
469
|
+
const properties = await config.getProperties();
|
|
470
|
+
if (!(await config.checkProperties(properties))) {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
if (!Util._isValidType(selectedType)) {
|
|
748
474
|
return;
|
|
749
475
|
}
|
|
476
|
+
const [type, subType] = selectedType ? selectedType.split('-') : [];
|
|
750
477
|
|
|
751
478
|
let retrieveTypesArr;
|
|
752
479
|
if (
|
|
@@ -761,126 +488,78 @@ class Mcdev {
|
|
|
761
488
|
}
|
|
762
489
|
const buObject = await Cli.getCredentialObject(properties, businessUnit);
|
|
763
490
|
if (buObject !== null) {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
} catch (ex) {
|
|
768
|
-
Util.logger.error(ex.message);
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
const retriever = new Retriever(properties, buObject, client);
|
|
772
|
-
if (this._checkMarket(market)) {
|
|
491
|
+
cache.initCache(buObject);
|
|
492
|
+
const retriever = new Retriever(properties, buObject);
|
|
493
|
+
if (Util.checkMarket(market, properties)) {
|
|
773
494
|
return retriever.retrieve(retrieveTypesArr, name, properties.markets[market]);
|
|
774
495
|
}
|
|
775
496
|
}
|
|
776
497
|
}
|
|
777
498
|
|
|
778
499
|
/**
|
|
779
|
-
* Build a
|
|
780
|
-
*
|
|
781
|
-
* @param {
|
|
782
|
-
* @param {
|
|
783
|
-
* @param {
|
|
784
|
-
* @
|
|
500
|
+
* Build a template based on a list of metadata files in the retrieve folder.
|
|
501
|
+
*
|
|
502
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
503
|
+
* @param {string} selectedType supported metadata type
|
|
504
|
+
* @param {string[]} keyArr customerkey of the metadata
|
|
505
|
+
* @param {string} market market localizations
|
|
506
|
+
* @returns {Promise.<TYPE.MultiMetadataTypeList>} -
|
|
785
507
|
*/
|
|
786
|
-
static async
|
|
787
|
-
Util.logger.info('mcdev:: Build
|
|
788
|
-
|
|
789
|
-
if (type.includes('-')) {
|
|
790
|
-
Util.logger.error(
|
|
791
|
-
`:: '${type}' is not a valid metadata type. Please don't include subtypes.`
|
|
792
|
-
);
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
if (type && !MetadataTypeInfo[type]) {
|
|
796
|
-
Util.logger.error(`:: '${type}' is not a valid metadata type`);
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
const buObject = await Cli.getCredentialObject(properties, businessUnit);
|
|
800
|
-
if (buObject !== null) {
|
|
801
|
-
const builder = new Builder(properties, buObject, null);
|
|
802
|
-
if (market === '*') {
|
|
803
|
-
for (const oneMarket in properties.markets) {
|
|
804
|
-
builder.buildDefinition(type, name, properties.markets[oneMarket]);
|
|
805
|
-
}
|
|
806
|
-
} else {
|
|
807
|
-
if (this._checkMarket(market)) {
|
|
808
|
-
builder.buildDefinition(type, name, properties.markets[market]);
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
}
|
|
508
|
+
static async buildTemplate(businessUnit, selectedType, keyArr, market) {
|
|
509
|
+
Util.logger.info('mcdev:: Build Template from retrieved files');
|
|
510
|
+
return Builder.buildTemplate(businessUnit, selectedType, keyArr, market);
|
|
812
511
|
}
|
|
813
512
|
/**
|
|
814
|
-
*
|
|
815
|
-
*
|
|
816
|
-
* @
|
|
513
|
+
* Build a specific metadata file based on a template.
|
|
514
|
+
*
|
|
515
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
516
|
+
* @param {string} selectedType supported metadata type
|
|
517
|
+
* @param {string} name name of the metadata
|
|
518
|
+
* @param {string} market market localizations
|
|
519
|
+
* @returns {Promise.<void>} -
|
|
817
520
|
*/
|
|
818
|
-
static
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
return true;
|
|
822
|
-
} else {
|
|
823
|
-
Util.logger.error(`Could not find the market '${market}' in your configuration file.`);
|
|
824
|
-
const marketArr = [];
|
|
825
|
-
for (const oneMarket in properties.markets) {
|
|
826
|
-
marketArr.push(oneMarket);
|
|
827
|
-
}
|
|
828
|
-
if (marketArr.length) {
|
|
829
|
-
Util.logger.info('Available markets are: ' + marketArr.join(', '));
|
|
830
|
-
}
|
|
831
|
-
return false;
|
|
832
|
-
}
|
|
521
|
+
static async buildDefinition(businessUnit, selectedType, name, market) {
|
|
522
|
+
Util.logger.info('mcdev:: Build Definition from Template');
|
|
523
|
+
return Builder.buildDefinition(businessUnit, selectedType, name, market);
|
|
833
524
|
}
|
|
834
525
|
|
|
835
526
|
/**
|
|
836
527
|
* Build a specific metadata file based on a template using a list of bu-market combos
|
|
837
|
-
*
|
|
838
|
-
* @param {
|
|
839
|
-
* @param {
|
|
840
|
-
* @
|
|
528
|
+
*
|
|
529
|
+
* @param {string} listName name of list of BU-market combos
|
|
530
|
+
* @param {string} type supported metadata type
|
|
531
|
+
* @param {string} name name of the metadata
|
|
532
|
+
* @returns {Promise.<void>} -
|
|
841
533
|
*/
|
|
842
534
|
static async buildDefinitionBulk(listName, type, name) {
|
|
843
535
|
Util.logger.info('mcdev:: Build Definition from Template Bulk');
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
536
|
+
return Builder.buildDefinitionBulk(listName, type, name);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
*
|
|
540
|
+
* @param {string} businessUnit references credentials from properties.json
|
|
541
|
+
* @param {string} selectedType supported metadata type
|
|
542
|
+
* @param {string[]} keyArr customerkey of the metadata
|
|
543
|
+
* @returns {Promise.<string[]>} list of all files that need to be committed in a flat array ['path/file1.ext', 'path/file2.ext']
|
|
544
|
+
*/
|
|
545
|
+
static async getFilesToCommit(businessUnit, selectedType, keyArr) {
|
|
546
|
+
Util.logger.info('mcdev:: getFilesToCommit');
|
|
547
|
+
const properties = await config.getProperties();
|
|
548
|
+
if (!(await config.checkProperties(properties))) {
|
|
549
|
+
return null;
|
|
848
550
|
}
|
|
849
|
-
if (!
|
|
850
|
-
Util.logger.error(`Please define properties.marketList.${listName} in your config`);
|
|
551
|
+
if (!Util._isValidType(selectedType)) {
|
|
851
552
|
return;
|
|
852
553
|
}
|
|
853
|
-
if (
|
|
854
|
-
Util.logger.error(
|
|
554
|
+
if (selectedType.includes('-')) {
|
|
555
|
+
Util.logger.error(
|
|
556
|
+
`:: '${selectedType}' is not a valid metadata type. Please don't include subtypes.`
|
|
557
|
+
);
|
|
855
558
|
return;
|
|
856
559
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
// skip, it's just a metadata on this list and not a BU
|
|
861
|
-
continue;
|
|
862
|
-
}
|
|
863
|
-
i++;
|
|
864
|
-
const market = properties.marketList[listName][businessUnit];
|
|
865
|
-
let marketList = [];
|
|
866
|
-
if ('string' === typeof market) {
|
|
867
|
-
marketList.push(market);
|
|
868
|
-
} else {
|
|
869
|
-
marketList = market;
|
|
870
|
-
}
|
|
871
|
-
marketList.forEach((market) => {
|
|
872
|
-
if (market && properties.markets[market]) {
|
|
873
|
-
Util.logger.info(`Executing for '${businessUnit}': '${market}'`);
|
|
874
|
-
this.buildDefinition(businessUnit, type, name, market);
|
|
875
|
-
} else {
|
|
876
|
-
Util.logger.error(
|
|
877
|
-
`Could not find '${market}' in properties.markets. Please check your properties.marketList.${listName} confguration.`
|
|
878
|
-
);
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
if (!i) {
|
|
883
|
-
Util.logger.error('Please define properties.marketList in your config');
|
|
560
|
+
const buObject = await Cli.getCredentialObject(properties, businessUnit);
|
|
561
|
+
if (buObject !== null) {
|
|
562
|
+
return DevOps.getFilesToCommit(properties, buObject, selectedType, keyArr);
|
|
884
563
|
}
|
|
885
564
|
}
|
|
886
565
|
}
|