mcdev 3.1.3 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +67 -7
- package/.github/ISSUE_TEMPLATE/bug.yml +2 -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 +30 -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 +2807 -1730
- package/jsconfig.json +1 -1
- package/lib/Builder.js +171 -74
- 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 +116 -11
- package/lib/index.js +241 -561
- package/lib/metadataTypes/AccountUser.js +117 -103
- package/lib/metadataTypes/Asset.js +705 -255
- package/lib/metadataTypes/AttributeGroup.js +23 -12
- package/lib/metadataTypes/Automation.js +489 -392
- package/lib/metadataTypes/Campaign.js +33 -93
- package/lib/metadataTypes/ContentArea.js +31 -11
- package/lib/metadataTypes/DataExtension.js +387 -372
- package/lib/metadataTypes/DataExtensionField.js +131 -54
- package/lib/metadataTypes/DataExtensionTemplate.js +22 -4
- package/lib/metadataTypes/DataExtract.js +61 -48
- 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 +61 -43
- package/lib/metadataTypes/FileTransfer.js +72 -52
- 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 +61 -64
- package/lib/metadataTypes/Interaction.js +19 -4
- package/lib/metadataTypes/List.js +54 -13
- package/lib/metadataTypes/MetadataType.js +664 -454
- package/lib/metadataTypes/MobileCode.js +46 -0
- package/lib/metadataTypes/MobileKeyword.js +114 -0
- package/lib/metadataTypes/Query.js +206 -105
- package/lib/metadataTypes/Role.js +76 -61
- package/lib/metadataTypes/Script.js +147 -83
- 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 +250 -50
- package/lib/util/file.js +141 -201
- package/lib/util/init.config.js +208 -75
- 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 +45 -34
- 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/util/init.config.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const TYPE = require('../../types/mcdev.d');
|
|
3
4
|
const Cli = require('./cli');
|
|
4
5
|
const File = require('./file');
|
|
6
|
+
const config = require('./config');
|
|
5
7
|
const Util = require('./util');
|
|
6
8
|
const inquirer = require('inquirer');
|
|
7
|
-
const path = require('path');
|
|
9
|
+
const path = require('node:path');
|
|
10
|
+
const semver = require('semver');
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* CLI helper class
|
|
@@ -13,8 +16,9 @@ const path = require('path');
|
|
|
13
16
|
const Init = {
|
|
14
17
|
/**
|
|
15
18
|
* helper method for this.upgradeProject that upgrades project config if needed
|
|
16
|
-
*
|
|
17
|
-
* @
|
|
19
|
+
*
|
|
20
|
+
* @param {TYPE.Mcdevrc} properties config file's json
|
|
21
|
+
* @returns {Promise.<boolean>} returns true if worked without errors
|
|
18
22
|
*/
|
|
19
23
|
async fixMcdevConfig(properties) {
|
|
20
24
|
if (!properties) {
|
|
@@ -26,12 +30,12 @@ const Init = {
|
|
|
26
30
|
|
|
27
31
|
const upgradeMsgs = [`Upgrading existing ${Util.configFileName}:`];
|
|
28
32
|
|
|
29
|
-
const missingFields =
|
|
33
|
+
const missingFields = await config.checkProperties(properties, true);
|
|
34
|
+
const defaultProps = await config.getDefaultProperties();
|
|
30
35
|
if (missingFields.length) {
|
|
31
|
-
const
|
|
32
|
-
missingFields.forEach((fieldName) => {
|
|
36
|
+
for (const fieldName of missingFields) {
|
|
33
37
|
switch (fieldName) {
|
|
34
|
-
case 'marketList':
|
|
38
|
+
case 'marketList': {
|
|
35
39
|
if (properties.marketBulk) {
|
|
36
40
|
upgradeMsgs.push(`- ✔️ converted 'marketBulk' to '${fieldName}'`);
|
|
37
41
|
properties[fieldName] = properties.marketBulk;
|
|
@@ -41,20 +45,39 @@ const Init = {
|
|
|
41
45
|
this._updateLeaf(properties, defaultProps, fieldName);
|
|
42
46
|
}
|
|
43
47
|
break;
|
|
44
|
-
|
|
48
|
+
}
|
|
49
|
+
case 'directories.docs': {
|
|
50
|
+
if (properties.directories.badKeys) {
|
|
51
|
+
delete properties.directories.badKeys;
|
|
52
|
+
upgradeMsgs.push(`- ✋ removed 'directories.badKeys'`);
|
|
53
|
+
}
|
|
54
|
+
if (properties.directories.dataExtension) {
|
|
55
|
+
File.removeSync(properties.directories.dataExtension);
|
|
56
|
+
delete properties.directories.dataExtension;
|
|
57
|
+
upgradeMsgs.push(`- ✋ removed 'directories.dataExtension'`);
|
|
58
|
+
}
|
|
59
|
+
if (properties.directories.deltaPackage) {
|
|
60
|
+
delete properties.directories.deltaPackage;
|
|
61
|
+
upgradeMsgs.push(`- ✋ removed 'directories.deltaPackage'`);
|
|
62
|
+
}
|
|
45
63
|
if (properties.directories.dataextension) {
|
|
46
|
-
upgradeMsgs.push(
|
|
47
|
-
`- ✔️ converted 'directories.dataextension' to '${fieldName}'`
|
|
48
|
-
);
|
|
49
|
-
properties.directories.dataExtension =
|
|
50
|
-
properties.directories.dataextension;
|
|
51
64
|
delete properties.directories.dataextension;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
upgradeMsgs.push(`- ✋ removed 'directories.dataextension'`);
|
|
66
|
+
}
|
|
67
|
+
if (properties.directories.roles) {
|
|
68
|
+
delete properties.directories.roles;
|
|
69
|
+
upgradeMsgs.push(`- ✋ removed 'directories.roles'`);
|
|
55
70
|
}
|
|
71
|
+
if (properties.directories.users) {
|
|
72
|
+
delete properties.directories.users;
|
|
73
|
+
upgradeMsgs.push(`- ✋ removed 'directories.users'`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
this._updateLeaf(properties, defaultProps, fieldName);
|
|
77
|
+
upgradeMsgs.push(`- ✔️ added '${fieldName}'`);
|
|
56
78
|
break;
|
|
57
|
-
|
|
79
|
+
}
|
|
80
|
+
case 'metaDataTypes.documentOnRetrieve': {
|
|
58
81
|
if (!properties.options.documentOnRetrieve) {
|
|
59
82
|
properties.metaDataTypes.documentOnRetrieve = [];
|
|
60
83
|
} else {
|
|
@@ -65,7 +88,8 @@ const Init = {
|
|
|
65
88
|
`- ✔️ converted 'options.documentOnRetrieve' to '${fieldName}'`
|
|
66
89
|
);
|
|
67
90
|
break;
|
|
68
|
-
|
|
91
|
+
}
|
|
92
|
+
case 'options.deployment.commitHistory': {
|
|
69
93
|
if (properties.options.commitHistory) {
|
|
70
94
|
upgradeMsgs.push(
|
|
71
95
|
`- ✔️ converted 'options.commitHistory' to '${fieldName}'`
|
|
@@ -78,7 +102,8 @@ const Init = {
|
|
|
78
102
|
this._updateLeaf(properties, defaultProps, fieldName);
|
|
79
103
|
}
|
|
80
104
|
break;
|
|
81
|
-
|
|
105
|
+
}
|
|
106
|
+
case 'options.exclude': {
|
|
82
107
|
if (properties.options.filter) {
|
|
83
108
|
upgradeMsgs.push(`- ✔️ converted 'options.filter' to '${fieldName}'`);
|
|
84
109
|
properties.options.exclude = properties.options.filter;
|
|
@@ -88,21 +113,27 @@ const Init = {
|
|
|
88
113
|
this._updateLeaf(properties, defaultProps, fieldName);
|
|
89
114
|
}
|
|
90
115
|
break;
|
|
91
|
-
|
|
116
|
+
}
|
|
117
|
+
case 'version': {
|
|
92
118
|
// do nothing other than ensure we re-save the config (with the new version)
|
|
93
|
-
delete properties.catalystFullVersion;
|
|
94
|
-
delete properties.catalystVersion;
|
|
95
|
-
|
|
96
119
|
upgradeMsgs.push(`- ✔️ version updated`);
|
|
97
120
|
break;
|
|
98
|
-
|
|
121
|
+
}
|
|
122
|
+
default: {
|
|
99
123
|
this._updateLeaf(properties, defaultProps, fieldName);
|
|
100
124
|
upgradeMsgs.push(`- ✔️ added '${fieldName}'`);
|
|
125
|
+
}
|
|
101
126
|
}
|
|
102
|
-
}
|
|
127
|
+
}
|
|
103
128
|
updateConfigNeeded = true;
|
|
104
129
|
}
|
|
105
130
|
|
|
131
|
+
// ensure we document dataExtensions and automations on retrieve as they should now be in the retrieve folder
|
|
132
|
+
this._updateLeaf(properties, defaultProps, 'metaDataTypes.documentOnRetrieve');
|
|
133
|
+
upgradeMsgs.push(
|
|
134
|
+
`- ✔️ updated 'metaDataTypes.documentOnRetrieve' to include all available types`
|
|
135
|
+
);
|
|
136
|
+
|
|
106
137
|
// check if metaDataTypes.retrieve is set to default values and if not, launch selectTypes
|
|
107
138
|
const defaultRetrieveArr = Util.getRetrieveTypeChoices();
|
|
108
139
|
let reselectDefaultRetrieve = false;
|
|
@@ -118,6 +149,18 @@ const Init = {
|
|
|
118
149
|
updateConfigNeeded = true;
|
|
119
150
|
}
|
|
120
151
|
|
|
152
|
+
// move to version 4 uses integers for MIDs
|
|
153
|
+
for (const cred in properties.credentials) {
|
|
154
|
+
properties.credentials[cred].eid = Number.parseInt(properties.credentials[cred].eid);
|
|
155
|
+
for (const bu in properties.credentials[cred].businessUnits) {
|
|
156
|
+
properties.credentials[cred].businessUnits[bu] = Number.parseInt(
|
|
157
|
+
properties.credentials[cred].businessUnits[bu]
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
updateConfigNeeded = true;
|
|
161
|
+
upgradeMsgs.push(`- ✔️ updated Business Unit format (${cred})`);
|
|
162
|
+
}
|
|
163
|
+
|
|
121
164
|
// update config
|
|
122
165
|
if (updateConfigNeeded) {
|
|
123
166
|
for (const msg of upgradeMsgs) {
|
|
@@ -131,16 +174,16 @@ const Init = {
|
|
|
131
174
|
Util.logger.warn('');
|
|
132
175
|
if (toBeAddedTypes.length) {
|
|
133
176
|
Util.logger.warn('Adding types:');
|
|
134
|
-
|
|
177
|
+
for (const type of toBeAddedTypes) {
|
|
135
178
|
Util.logger.warn(` - ${type}`);
|
|
136
|
-
}
|
|
179
|
+
}
|
|
137
180
|
Util.logger.warn('');
|
|
138
181
|
}
|
|
139
182
|
if (toBeRemovedTypes.length) {
|
|
140
183
|
Util.logger.warn('Removing types:');
|
|
141
|
-
|
|
184
|
+
for (const type of toBeRemovedTypes) {
|
|
142
185
|
Util.logger.warn(` - ${type}`);
|
|
143
|
-
}
|
|
186
|
+
}
|
|
144
187
|
Util.logger.warn('');
|
|
145
188
|
}
|
|
146
189
|
await Cli.selectTypes(properties, defaultRetrieveArr);
|
|
@@ -154,21 +197,19 @@ const Init = {
|
|
|
154
197
|
|
|
155
198
|
return true;
|
|
156
199
|
},
|
|
200
|
+
|
|
157
201
|
/**
|
|
158
202
|
* handles creation/update of all config file from the boilerplate
|
|
159
|
-
*
|
|
203
|
+
*
|
|
204
|
+
* @param {string} versionBeforeUpgrade 'x.y.z'
|
|
205
|
+
* @returns {Promise.<boolean>} status of config file creation
|
|
160
206
|
*/
|
|
161
|
-
async createIdeConfigFiles() {
|
|
207
|
+
async createIdeConfigFiles(versionBeforeUpgrade) {
|
|
162
208
|
Util.logger.info('Checking configuration files (existing files will not be changed):');
|
|
163
209
|
const creationLog = [];
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (!File.existsSync('src/cloudPages')) {
|
|
170
|
-
File.mkdirpSync('src/cloudPages');
|
|
171
|
-
}
|
|
210
|
+
await File.ensureDir('deploy/');
|
|
211
|
+
await File.ensureDir('src/cloudPages');
|
|
212
|
+
const relevantForcedUpdates = await this._getForcedUpdateList(versionBeforeUpgrade);
|
|
172
213
|
|
|
173
214
|
// copy in .gitignore (cant be retrieved via npm install directly)
|
|
174
215
|
const gitignoreFileName = path.resolve(
|
|
@@ -176,32 +217,39 @@ const Init = {
|
|
|
176
217
|
Util.boilerplateDirectory,
|
|
177
218
|
'gitignore-template'
|
|
178
219
|
);
|
|
179
|
-
if (!File.
|
|
220
|
+
if (!(await File.pathExists(gitignoreFileName))) {
|
|
180
221
|
Util.logger.debug(`Dependency file not found in ${gitignoreFileName}`);
|
|
181
222
|
return false;
|
|
182
223
|
} else {
|
|
183
|
-
const fileContent = File.
|
|
224
|
+
const fileContent = await File.readFile(gitignoreFileName, 'utf8');
|
|
184
225
|
creationLog.push(
|
|
185
|
-
await this._createIdeConfigFile(
|
|
226
|
+
await this._createIdeConfigFile(
|
|
227
|
+
['.' + path.sep, '', '.gitignore'],
|
|
228
|
+
relevantForcedUpdates,
|
|
229
|
+
fileContent
|
|
230
|
+
)
|
|
186
231
|
);
|
|
187
232
|
}
|
|
188
233
|
|
|
189
234
|
// load file list from boilerplate dir and initiate copy process
|
|
190
235
|
const boilerPlateFilesPath = path.resolve(__dirname, Util.boilerplateDirectory, 'files');
|
|
191
|
-
|
|
192
|
-
|
|
236
|
+
// ! do not switch to readDirectories before merging the two custom methods. Their logic is different!
|
|
237
|
+
const directories = await File.readDirectoriesSync(boilerPlateFilesPath, 10, false);
|
|
193
238
|
for (const subdir of directories) {
|
|
194
239
|
// walk thru the root of our boilerplate-files directory and all sub folders
|
|
195
240
|
const curDir = path.join(boilerPlateFilesPath, subdir);
|
|
196
|
-
for (const file of File.
|
|
241
|
+
for (const file of await File.readdir(curDir)) {
|
|
197
242
|
// read all files in these directories
|
|
198
|
-
if (!File.
|
|
243
|
+
if (!(await File.lstat(path.join(curDir, file))).isDirectory()) {
|
|
199
244
|
// filter entries that are actually folders
|
|
200
245
|
const fileArr = file.split('.');
|
|
201
246
|
const ext = '.' + fileArr.pop();
|
|
202
247
|
// awaiting the result here due to interactive optional overwrite
|
|
203
248
|
creationLog.push(
|
|
204
|
-
await this._createIdeConfigFile(
|
|
249
|
+
await this._createIdeConfigFile(
|
|
250
|
+
[subdir + path.sep, fileArr.join('.'), ext],
|
|
251
|
+
relevantForcedUpdates
|
|
252
|
+
)
|
|
205
253
|
);
|
|
206
254
|
}
|
|
207
255
|
}
|
|
@@ -220,9 +268,10 @@ const Init = {
|
|
|
220
268
|
},
|
|
221
269
|
/**
|
|
222
270
|
* recursive helper for _fixMcdevConfig that adds missing settings
|
|
223
|
-
*
|
|
224
|
-
* @param {
|
|
225
|
-
* @param {
|
|
271
|
+
*
|
|
272
|
+
* @param {object} propertiersCur current sub-object of project settings
|
|
273
|
+
* @param {object} defaultPropsCur current sub-object of default settings
|
|
274
|
+
* @param {string} fieldName dot-concatenated object-path that needs adding
|
|
226
275
|
* @returns {void}
|
|
227
276
|
*/
|
|
228
277
|
_updateLeaf(propertiersCur, defaultPropsCur, fieldName) {
|
|
@@ -242,13 +291,45 @@ const Init = {
|
|
|
242
291
|
propertiersCur[fieldName] = defaultPropsCur[fieldName];
|
|
243
292
|
}
|
|
244
293
|
},
|
|
294
|
+
/**
|
|
295
|
+
* returns list of files that need to be updated
|
|
296
|
+
*
|
|
297
|
+
* @param {string} projectVersion version found in config file of the current project
|
|
298
|
+
* @returns {Promise.<string[]>} relevant files with path that need to be updated
|
|
299
|
+
*/
|
|
300
|
+
async _getForcedUpdateList(projectVersion) {
|
|
301
|
+
// list of files that absolutely need to get overwritten, no questions asked, when upgrading from a version lower than the given.
|
|
302
|
+
let forceIdeConfigUpdate;
|
|
303
|
+
const relevantForcedUpdates = [];
|
|
304
|
+
if (await File.pathExists(Util.configFileName)) {
|
|
305
|
+
forceIdeConfigUpdate = File.readJsonSync(
|
|
306
|
+
path.resolve(__dirname, Util.boilerplateDirectory, 'forcedUpdates.json')
|
|
307
|
+
);
|
|
308
|
+
// return all if no project version was found or only changes from "newer" versions otherwise
|
|
309
|
+
for (const element of forceIdeConfigUpdate) {
|
|
310
|
+
if (!projectVersion || semver.gt(element.version, projectVersion)) {
|
|
311
|
+
relevantForcedUpdates.push(
|
|
312
|
+
// adapt it for local file systems
|
|
313
|
+
...element.files.map((item) => path.normalize(item))
|
|
314
|
+
);
|
|
315
|
+
} else {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return relevantForcedUpdates;
|
|
322
|
+
},
|
|
245
323
|
/**
|
|
246
324
|
* handles creation/update of one config file from the boilerplate at a time
|
|
247
|
-
*
|
|
248
|
-
* @param {
|
|
249
|
-
* @
|
|
325
|
+
*
|
|
326
|
+
* @param {string[]} fileNameArr 0: path, 1: filename, 2: extension with dot
|
|
327
|
+
* @param {string[]} relevantForcedUpdates if fileNameArr is in this list we require an override
|
|
328
|
+
* @param {string} [boilerplateFileContent] in case we cannot copy files 1:1 this can be used to pass in content
|
|
329
|
+
* @returns {Promise.<boolean>} install successful or error occured
|
|
250
330
|
*/
|
|
251
|
-
async _createIdeConfigFile(fileNameArr,
|
|
331
|
+
async _createIdeConfigFile(fileNameArr, relevantForcedUpdates, boilerplateFileContent) {
|
|
332
|
+
let update = false;
|
|
252
333
|
const fileName = fileNameArr.join('');
|
|
253
334
|
const boilerplateFileName = path.resolve(
|
|
254
335
|
__dirname,
|
|
@@ -256,41 +337,93 @@ const Init = {
|
|
|
256
337
|
'files',
|
|
257
338
|
fileName
|
|
258
339
|
);
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
default: false,
|
|
267
|
-
},
|
|
268
|
-
];
|
|
269
|
-
const responses = await new Promise((resolve) => {
|
|
270
|
-
inquirer.prompt(questions).then((answers) => {
|
|
271
|
-
resolve(answers);
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
if (!responses.overrideFile) {
|
|
340
|
+
boilerplateFileContent =
|
|
341
|
+
boilerplateFileContent || (await File.readFile(boilerplateFileName, 'utf8'));
|
|
342
|
+
|
|
343
|
+
if (await File.pathExists(fileName)) {
|
|
344
|
+
const existingFileContent = await File.readFile(fileName, 'utf8');
|
|
345
|
+
if (existingFileContent === boilerplateFileContent) {
|
|
346
|
+
Util.logger.info(`- ✔️ ${fileName} found. No update needed`);
|
|
275
347
|
return true;
|
|
276
348
|
}
|
|
349
|
+
if (relevantForcedUpdates.includes(path.normalize(fileName))) {
|
|
350
|
+
Util.logger.info(
|
|
351
|
+
`- ✋ ${fileName} found but an update is required. Commencing with override:`
|
|
352
|
+
);
|
|
353
|
+
} else {
|
|
354
|
+
Util.logger.info(
|
|
355
|
+
`- ✋ ${fileName} found with differences to the new standard version. We recommend updating it.`
|
|
356
|
+
);
|
|
357
|
+
if (!Util.skipInteraction) {
|
|
358
|
+
const responses = await inquirer.prompt([
|
|
359
|
+
{
|
|
360
|
+
type: 'confirm',
|
|
361
|
+
name: 'overrideFile',
|
|
362
|
+
message: 'Would you like to update (override) it?',
|
|
363
|
+
default: true,
|
|
364
|
+
},
|
|
365
|
+
]);
|
|
366
|
+
if (!responses.overrideFile) {
|
|
367
|
+
// skip override without error
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
update = true;
|
|
373
|
+
|
|
374
|
+
// ensure our update is not leading to data loss in case config files were not versioned correctly by the user
|
|
375
|
+
await File.rename(fileName, fileName + '.BAK');
|
|
277
376
|
}
|
|
278
|
-
fileContent = fileContent || File.readFileSync(boilerplateFileName, 'utf8');
|
|
279
377
|
const saveStatus = await File.writeToFile(
|
|
280
378
|
fileNameArr[0],
|
|
281
379
|
fileNameArr[1],
|
|
282
|
-
fileNameArr[2].
|
|
283
|
-
|
|
380
|
+
fileNameArr[2].slice(1),
|
|
381
|
+
boilerplateFileContent
|
|
284
382
|
);
|
|
285
383
|
|
|
286
384
|
if (saveStatus) {
|
|
287
|
-
Util.logger.info(
|
|
385
|
+
Util.logger.info(
|
|
386
|
+
`- ✔️ ${fileName} ${
|
|
387
|
+
update
|
|
388
|
+
? `updated (we created a backup of the old file under ${fileName + '.BAK'})`
|
|
389
|
+
: 'created'
|
|
390
|
+
}`
|
|
391
|
+
);
|
|
288
392
|
return true;
|
|
289
393
|
} else {
|
|
290
|
-
Util.logger.warn(`- ❌ ${fileName} creation failed`);
|
|
394
|
+
Util.logger.warn(`- ❌ ${fileName} ${update ? 'update' : 'creation'} failed`);
|
|
291
395
|
return false;
|
|
292
396
|
}
|
|
293
397
|
},
|
|
398
|
+
/**
|
|
399
|
+
* helper method for this.upgradeProject that upgrades project config if needed
|
|
400
|
+
*
|
|
401
|
+
* @returns {Promise.<boolean>} returns true if worked without errors
|
|
402
|
+
*/
|
|
403
|
+
async upgradeAuthFile() {
|
|
404
|
+
if (await File.pathExists(Util.authFileName)) {
|
|
405
|
+
const existingAuth = await File.readJSON(Util.authFileName);
|
|
406
|
+
// if has credentials key then is old format
|
|
407
|
+
if (existingAuth.credentials) {
|
|
408
|
+
const newAuth = {};
|
|
409
|
+
for (const cred in existingAuth.credentials) {
|
|
410
|
+
newAuth[cred] = {
|
|
411
|
+
client_id: existingAuth.credentials[cred].clientId,
|
|
412
|
+
client_secret: existingAuth.credentials[cred].clientSecret,
|
|
413
|
+
auth_url: `https://${existingAuth.credentials[cred].tenant}.auth.marketingcloudapis.com/`,
|
|
414
|
+
account_id: Number.parseInt(existingAuth.credentials[cred].eid),
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
await File.writeJSONToFile(
|
|
418
|
+
'./',
|
|
419
|
+
Util.authFileName.replace(/(.json)+$/, ''),
|
|
420
|
+
newAuth
|
|
421
|
+
);
|
|
422
|
+
Util.logger.info(`- ✔️ upgraded credential file`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return true;
|
|
426
|
+
},
|
|
294
427
|
};
|
|
295
428
|
|
|
296
429
|
module.exports = Init;
|