-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathconfig.js
324 lines (316 loc) · 15.4 KB
/
config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
import { Util } from './util.js';
import File from './file.js';
import inquirer from 'inquirer';
import semver from 'semver';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
/**
* @typedef {import('../../types/mcdev.d.js').AuthObject} AuthObject
* @typedef {import('../../types/mcdev.d.js').BuObject} BuObject
* @typedef {import('../../types/mcdev.d.js').Cache} Cache
* @typedef {import('../../types/mcdev.d.js').CodeExtract} CodeExtract
* @typedef {import('../../types/mcdev.d.js').CodeExtractItem} CodeExtractItem
* @typedef {import('../../types/mcdev.d.js').DeltaPkgItem} DeltaPkgItem
* @typedef {import('../../types/mcdev.d.js').Mcdevrc} Mcdevrc
* @typedef {import('../../types/mcdev.d.js').MetadataTypeItem} MetadataTypeItem
* @typedef {import('../../types/mcdev.d.js').MetadataTypeItemDiff} MetadataTypeItemDiff
* @typedef {import('../../types/mcdev.d.js').MetadataTypeItemObj} MetadataTypeItemObj
* @typedef {import('../../types/mcdev.d.js').MetadataTypeMap} MetadataTypeMap
* @typedef {import('../../types/mcdev.d.js').MetadataTypeMapObj} MetadataTypeMapObj
* @typedef {import('../../types/mcdev.d.js').MultiMetadataTypeList} MultiMetadataTypeList
* @typedef {import('../../types/mcdev.d.js').MultiMetadataTypeMap} MultiMetadataTypeMap
* @typedef {import('../../types/mcdev.d.js').SoapRequestParams} SoapRequestParams
* @typedef {import('../../types/mcdev.d.js').TemplateMap} TemplateMap
* @typedef {import('../../types/mcdev.d.js').TypeKeyCombo} TypeKeyCombo
*/
/**
* Central class for loading and validating properties from config and auth
*/
const config = {
properties: null,
/**
* loads central properties from config file
*
* @param {boolean} [silent] omit throwing errors and print messages; assuming not silent if not set
* @param {boolean} [isInit] don't tell the user to run init
* @returns {Promise.<Mcdevrc>} central properties object
*/
async getProperties(silent, isInit) {
if (config.properties) {
return config.properties;
}
if (await File.pathExists(Util.configFileName)) {
try {
config.properties = await File.readJSON(Util.configFileName);
} catch (ex) {
Util.logger.error(`${ex.code}: ${ex.message}`);
return;
}
if (await File.pathExists(Util.authFileName)) {
let auth;
try {
auth = await File.readJSON(Util.authFileName);
} catch (ex) {
Util.logger.error(`${ex.code}: ${ex.message}`);
return;
}
if (!auth) {
const err = `${Util.authFileName} is not set up correctly.`;
Util.logger.error(err);
throw new Error(err);
}
for (const cred in config.properties.credentials) {
if (auth[cred]) {
if (
config.properties.credentials[cred].eid != auth[cred].account_id &&
!silent
) {
Util.logger.error(
`'${cred}' found in ${Util.configFileName} (${typeof config
.properties.credentials[cred].eid} ${
config.properties.credentials[cred].eid
}) and ${Util.authFileName} (${typeof auth[cred].account_id} ${
auth[cred].account_id
}) have a Enterprise ID mismatch. Please check.`
);
return;
}
// TODO add auth checks #294
} else if (!silent) {
Util.logger.error(
`'${cred}' found in ${Util.configFileName} but not in ${Util.authFileName}. Please run 'mcdev init' to provide the missing credential details.`
);
return;
}
}
} else if (!silent && !isInit) {
Util.logger.error(
`${Util.authFileName} not found. Please run 'mcdev init' to provide the missing credential details.`
);
return;
}
}
return config.properties;
},
/**
* check if the config file is correctly formatted and has values
*
* @param {Mcdevrc} properties javascript object in .mcdevrc.json
* @param {boolean} [silent] set to true for internal use w/o cli output
* @returns {Promise.<boolean | string[]>} file structure ok OR list of fields to be fixed
*/
async checkProperties(properties, silent) {
if (!(await File.pathExists(Util.configFileName))) {
Util.logger.error(`Could not find ${Util.configFileName} in ${process.cwd()}.`);
Util.logger.error(`Run 'mcdev init' to initialize your project.\n`);
return false;
}
if (!(await File.pathExists(Util.authFileName))) {
Util.logger.error(`Could not find ${Util.authFileName} in ${process.cwd()}.`);
Util.logger.error(`Run 'mcdev init' to initialize your project.\n`);
return false;
}
if (!properties) {
// assume there was an error loading the config failed
return false;
}
// check if user is running older (ignores patches) mcdev version than whats saved to the config
if (properties.version && semver.gt(properties.version, Util.packageJsonMcdev.version)) {
Util.logger.error(
`Your Accenture SFMC DevTools version ${Util.packageJsonMcdev.version} is lower than your project's config version ${properties.version}`
);
if (Util.skipInteraction) {
return false;
}
const responses = await inquirer.prompt([
{
type: 'confirm',
name: 'runUpgradeNow',
message: `Do you want to run 'npm update -g mcdev@${properties.version}' now? This may take a few minutes.`,
default: true,
},
]);
if (responses.runUpgradeNow) {
// use _execSync here to avoid a circular dependency
Util.execSync('npm', ['update', '-g', `mcdev@${properties.version}`]);
}
return false;
}
// check config properties
const defaultProps = await this.getDefaultProperties();
const errorMsgs = [];
const solutionSet = new Set();
const missingFields = [];
for (const key in defaultProps) {
if (Object.prototype.hasOwnProperty.call(defaultProps, key)) {
if (Object.prototype.hasOwnProperty.call(properties, key)) {
if (!silent && key === 'credentials') {
if (Object.keys(properties.credentials)) {
for (const cred in properties.credentials) {
if (cred.includes('/') || cred.includes('\\')) {
errorMsgs.push(
`Credential names may not includes slashes: ${cred}`
);
solutionSet.add('Apply manual fix in your config.');
}
if (
!properties.credentials[cred].eid ||
properties.credentials[cred].eid === 0
) {
errorMsgs.push(`invalid account_id (EID) on ${cred}`);
solutionSet.add(`Run 'mcdev init ${cred}'`);
}
let i = 0;
for (const buName in properties.credentials[cred].businessUnits) {
if (buName.includes('/') || buName.includes('\\')) {
errorMsgs.push(
`Business Unit names may not includes slashes: ${cred}: ${buName}`
);
solutionSet.add(`Run 'mcdev reloadBUs ${cred}'`);
}
if (
Object.prototype.hasOwnProperty.call(
properties.credentials[cred].businessUnits,
buName
) &&
properties.credentials[cred].businessUnits[buName] !== 0
) {
i++;
}
}
if (!i) {
errorMsgs.push(`no Business Units defined`);
solutionSet.add(`Run 'mcdev reloadBUs ${cred}'`);
}
}
} else {
errorMsgs.push(`no Credential defined`);
}
} else if (['directories', 'metaDataTypes', 'options'].includes(key)) {
for (const subkey in defaultProps[key]) {
if (
Object.prototype.hasOwnProperty.call(defaultProps[key], subkey) &&
!Object.prototype.hasOwnProperty.call(properties[key], subkey)
) {
errorMsgs.push(
`${key}.${subkey} missing. Default value (${
Array.isArray(defaultProps[key][subkey])
? 'Array'
: typeof defaultProps[key][subkey]
}): ${defaultProps[key][subkey]}`
);
solutionSet.add(
`Run 'mcdev upgrade' to fix missing or changed configuration options`
);
missingFields.push(`${key}.${subkey}`);
} else if (subkey === 'deployment') {
for (const dkey in defaultProps[key][subkey]) {
if (
Object.prototype.hasOwnProperty.call(
defaultProps[key][subkey],
dkey
) &&
!Object.prototype.hasOwnProperty.call(
properties[key][subkey],
dkey
)
) {
errorMsgs.push(
`${key}.${subkey} missing. Default value (${
Array.isArray(defaultProps[key][subkey][dkey])
? 'Array'
: typeof defaultProps[key][subkey][dkey]
}): ${defaultProps[key][subkey][dkey]}`
);
solutionSet.add(
`Run 'mcdev upgrade' to fix missing or changed configuration options`
);
missingFields.push(`${key}.${subkey}.${dkey}`);
}
}
}
}
}
} else {
errorMsgs.push(`${key}{} missing`);
solutionSet.add(
`Run 'mcdev upgrade' to fix missing or changed configuration options`
);
missingFields.push(key);
}
}
}
// check if project config version is outdated compared to user's mcdev version
if (
!properties.version ||
(![null, 'patch'].includes(
semver.diff(Util.packageJsonMcdev.version, properties.version)
) &&
semver.gt(Util.packageJsonMcdev.version, properties.version))
) {
errorMsgs.push(
`Your project's config version ${properties.version} is lower than your Accenture SFMC DevTools version ${Util.packageJsonMcdev.version}`
);
solutionSet.add(`Run 'mcdev upgrade' to ensure optimal performance`);
missingFields.push('version');
}
if (silent) {
return missingFields;
} else {
if (errorMsgs.length) {
const errorMsgOutput = [
`Found problems in your ./${Util.configFileName} that you need to fix first:`,
];
for (const msg of errorMsgs) {
errorMsgOutput.push(' - ' + msg);
}
Util.logger.error(errorMsgOutput.join('\n'));
if (Util.skipInteraction) {
return false;
}
Util.logger.info(
[
'Here is what you can do to fix these issues:',
...Array.from(solutionSet),
].join('\n- ')
);
const responses = await inquirer.prompt([
{
type: 'confirm',
name: 'runUpgradeNow',
message: `Do you want to run 'mcdev upgrade' now?`,
default: true,
},
]);
if (responses.runUpgradeNow) {
// use _execSync here to avoid a circular dependency
Util.execSync('mcdev', ['upgrade']);
}
return false;
} else {
return true;
}
}
},
/**
* defines how the properties.json should look like
* used for creating a template and for checking if variables are set
*
* @returns {Promise.<Mcdevrc>} default properties
*/
async getDefaultProperties() {
const configFileName = path.resolve(__dirname, Util.boilerplateDirectory, 'config.json');
if (!(await File.pathExists(configFileName))) {
Util.logger.debug(`Default config file not found in ${configFileName}`);
return;
}
const defaultProperties = await File.readJSON(configFileName);
// set default name for parent BU
defaultProperties.credentials.default.businessUnits[Util.parentBuName] = 0;
// set default retrieve values
defaultProperties.metaDataTypes.retrieve = Util.getRetrieveTypeChoices();
return defaultProperties;
},
};
export default config;