mcdev 7.7.0 → 7.7.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.
@@ -39,6 +39,7 @@ body:
39
39
  label: Version
40
40
  description: What version of our software are you running? (mcdev --version)
41
41
  options:
42
+ - 7.7.1
42
43
  - 7.7.0
43
44
  - 7.6.3
44
45
  - 7.6.2
@@ -1,16 +1,18 @@
1
1
  import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
2
+ import eslintPluginUnicorn from 'eslint-plugin-unicorn';
3
+ import globals from 'globals';
2
4
  import jsdoc from 'eslint-plugin-jsdoc';
3
5
  import js from '@eslint/js';
4
6
  import sfmcSsjs from 'eslint-config-ssjs';
5
- import globals from 'globals';
6
7
 
7
8
  export default [
8
9
  {
9
10
  ignores: ['deploy/**/*', 'docs/**/*', 'logs/**/*', 'node_modules/**/*', 'template/**/*']
10
11
  },
11
- js.configs['recommended'],
12
+ js.configs.recommended,
12
13
  eslintPluginPrettierRecommended,
13
14
  jsdoc.configs['flat/recommended'],
15
+ eslintPluginUnicorn.configs['flat/recommended'],
14
16
  {
15
17
  plugins: { jsdoc },
16
18
  rules: {
@@ -66,7 +68,7 @@ export default [
66
68
  }
67
69
  },
68
70
  {
69
- files: ['.mcdev-validations.js'],
71
+ files: ['lib/**.js', '.mcdev-validations.js'],
70
72
 
71
73
  languageOptions: {
72
74
  globals: {
@@ -76,8 +78,101 @@ export default [
76
78
  ecmaVersion: 2022,
77
79
  sourceType: 'module'
78
80
  },
81
+ settings: {
82
+ jsdoc: {
83
+ mode: 'typescript',
84
+
85
+ preferredTypes: {
86
+ array: 'Array',
87
+ 'array.<>': '[]',
88
+ 'Array.<>': '[]',
89
+ 'array<>': '[]',
90
+ 'Array<>': '[]',
91
+ Object: 'object',
92
+ 'object.<>': 'Object.<>',
93
+ 'object<>': 'Object.<>',
94
+ 'Object<>': 'Object.<>',
95
+ set: 'Set',
96
+ 'set.<>': 'Set.<>',
97
+ 'set<>': 'Set.<>',
98
+ 'Set<>': 'Set.<>',
99
+ promise: 'Promise',
100
+ 'promise.<>': 'Promise.<>',
101
+ 'promise<>': 'Promise.<>',
102
+ 'Promise<>': 'Promise.<>'
103
+ }
104
+ }
105
+ },
79
106
 
80
107
  rules: {
108
+ 'logical-assignment-operators': ['error', 'always'],
109
+ 'unicorn/better-regex': 'off',
110
+
111
+ 'unicorn/catch-error-name': [
112
+ 'error',
113
+ {
114
+ name: 'ex'
115
+ }
116
+ ],
117
+
118
+ 'unicorn/explicit-length-check': 'off',
119
+ 'unicorn/no-null': 'off',
120
+ 'unicorn/prefer-module': 'off',
121
+ 'unicorn/prevent-abbreviations': 'off',
122
+ 'unicorn/filename-case': 'off',
123
+ 'unicorn/no-array-callback-reference': 'off',
124
+ 'unicorn/no-array-reduce': 'off',
125
+ 'unicorn/no-await-expression-member': 'off',
126
+ 'unicorn/no-hex-escape': 'off',
127
+ 'unicorn/no-nested-ternary': 'off',
128
+ 'unicorn/no-static-only-class': 'off',
129
+ 'unicorn/no-unused-properties': 'warn',
130
+ 'unicorn/numeric-separators-style': 'off',
131
+ 'unicorn/prefer-array-some': 'off',
132
+ 'unicorn/prefer-set-has': 'off',
133
+ 'unicorn/prefer-spread': 'off',
134
+ 'unicorn/prefer-string-replace-all': 'error',
135
+ 'arrow-body-style': ['error', 'as-needed'],
136
+ curly: 'error',
137
+
138
+ 'jsdoc/check-line-alignment': 2,
139
+
140
+ 'jsdoc/require-jsdoc': [
141
+ 'warn',
142
+ {
143
+ require: {
144
+ FunctionDeclaration: true,
145
+ MethodDefinition: true,
146
+ ClassDeclaration: true,
147
+ ArrowFunctionExpression: false,
148
+ FunctionExpression: true
149
+ }
150
+ }
151
+ ],
152
+
153
+ 'jsdoc/require-param-type': 'error',
154
+
155
+ 'jsdoc/tag-lines': [
156
+ 'warn',
157
+ 'any',
158
+ {
159
+ startLines: 1
160
+ }
161
+ ],
162
+
163
+ 'jsdoc/no-undefined-types': 'off',
164
+ 'jsdoc/valid-types': 'off',
165
+
166
+ 'spaced-comment': [
167
+ 'warn',
168
+ 'always',
169
+ {
170
+ block: {
171
+ exceptions: ['*'],
172
+ balanced: true
173
+ }
174
+ }
175
+ ],
81
176
  'no-var': 'error',
82
177
  'prefer-const': 'error',
83
178
  'prettier/prettier': 'warn'
@@ -4,6 +4,7 @@
4
4
  "eslint-config-ssjs",
5
5
  "eslint-plugin-jsdoc",
6
6
  "eslint-plugin-prettier",
7
+ "eslint-plugin-unicorn",
7
8
  "eslint",
8
9
  "globals",
9
10
  "prettier-plugin-sql",
package/lib/Builder.js CHANGED
@@ -112,8 +112,8 @@ saved
112
112
  */
113
113
  static async buildTemplate(businessUnit, selectedType, keyArr, marketArr) {
114
114
  const properties = await config.getProperties();
115
- if (!(await config.checkProperties(properties))) {
116
- return null;
115
+ if (!properties) {
116
+ return;
117
117
  }
118
118
  if (!Util._isValidType(selectedType)) {
119
119
  return;
@@ -198,8 +198,8 @@ saved
198
198
  */
199
199
  static async buildDefinition(businessUnit, selectedType, nameArr, marketArr) {
200
200
  const properties = await config.getProperties();
201
- if (!(await config.checkProperties(properties))) {
202
- return null;
201
+ if (!properties) {
202
+ return;
203
203
  }
204
204
  if (!Util._isValidType(selectedType)) {
205
205
  return;
@@ -241,8 +241,8 @@ saved
241
241
  */
242
242
  static async buildDefinitionBulk(listName, type, nameArr) {
243
243
  const properties = await config.getProperties();
244
- if (!(await config.checkProperties(properties))) {
245
- return null;
244
+ if (!properties) {
245
+ return;
246
246
  }
247
247
  try {
248
248
  Util.verifyMarketList(listName, properties);
@@ -301,6 +301,9 @@ saved
301
301
  */
302
302
  static async purgeDeployFolderList(listName) {
303
303
  const properties = await config.getProperties();
304
+ if (!properties) {
305
+ return;
306
+ }
304
307
  for (const businessUnit in properties.marketList[listName]) {
305
308
  if (businessUnit === 'description') {
306
309
  // skip, it's just a metadata on this list and not a BU
@@ -320,6 +323,9 @@ saved
320
323
  */
321
324
  static async purgeDeployFolder(businessUnit) {
322
325
  const properties = await config.getProperties();
326
+ if (!properties) {
327
+ return;
328
+ }
323
329
  if (!Util.isValidBU(properties, businessUnit, true)) {
324
330
  throw new Error(`'${businessUnit}' does not exist.`);
325
331
  }
package/lib/Deployer.js CHANGED
@@ -71,8 +71,8 @@ class Deployer {
71
71
  /** @type {Object.<string, MultiMetadataTypeMap>} */
72
72
  const buMultiMetadataTypeMap = {};
73
73
  const properties = await config.getProperties();
74
- if (!(await config.checkProperties(properties))) {
75
- return null;
74
+ if (!properties) {
75
+ return;
76
76
  }
77
77
  const deployDirBak = properties.directories.deploy;
78
78
  if (Util.OPTIONS.fromRetrieve) {
package/lib/cli.js CHANGED
@@ -1372,7 +1372,7 @@ yargs(hideBin(process.argv))
1372
1372
  .recommendCommands()
1373
1373
  .wrap(yargs(hideBin(process.argv)).terminalWidth())
1374
1374
  .epilog(
1375
- 'Copyright 2024. Accenture. Get support at https://github.com/Accenture/sfmc-devtools/issues'
1375
+ 'Copyright 2025. Accenture. Get support at https://github.com/Accenture/sfmc-devtools/issues'
1376
1376
  )
1377
1377
  .help().argv;
1378
1378
 
package/lib/index.js CHANGED
@@ -158,8 +158,8 @@ class Mcdev {
158
158
  Util.startLogger();
159
159
  Util.logger.info('Create Delta Package ::');
160
160
  const properties = await config.getProperties();
161
- if (!(await config.checkProperties(properties))) {
162
- return null;
161
+ if (!properties) {
162
+ return;
163
163
  }
164
164
  if (argv.commitrange) {
165
165
  Util.logger.warn(
@@ -189,9 +189,10 @@ class Mcdev {
189
189
  static async selectTypes() {
190
190
  Util.startLogger();
191
191
  const properties = await config.getProperties();
192
- if (!(await config.checkProperties(properties))) {
193
- return null;
192
+ if (!properties) {
193
+ return;
194
194
  }
195
+
195
196
  await Cli.selectTypes(properties);
196
197
  }
197
198
 
@@ -207,11 +208,11 @@ class Mcdev {
207
208
  */
208
209
  static async upgrade() {
209
210
  Util.startLogger();
210
- const properties = await config.getProperties();
211
+ const properties = await config.getProperties(false, true);
211
212
  if (!properties) {
212
- Util.logger.error('No config found. Please run mcdev init');
213
- return false;
213
+ return;
214
214
  }
215
+
215
216
  if ((await InitGit.initGitRepo()).status === 'error') {
216
217
  return false;
217
218
  }
@@ -229,9 +230,7 @@ class Mcdev {
229
230
  }
230
231
  Util.OPTIONS._welcomeMessageShown = true;
231
232
 
232
- const color = Util.isRunViaVSCodeExtension
233
- ? { reset: '', bgWhite: '', fgBlue: '' }
234
- : Util.color;
233
+ const color = Util.color;
235
234
  /* eslint-disable no-console */
236
235
  if (process.env['USERDNSDOMAIN'] === 'DIR.SVC.ACCENTURE.COM') {
237
236
  // Accenture internal message
@@ -270,9 +269,8 @@ class Mcdev {
270
269
  Util.startLogger();
271
270
  Util.logger.info('mcdev:: Retrieve');
272
271
  const properties = await config.getProperties();
273
- if (!(await config.checkProperties(properties))) {
274
- // return null here to avoid seeing 2 error messages for the same issue
275
- return null;
272
+ if (!properties) {
273
+ return;
276
274
  }
277
275
 
278
276
  // assume a list was passed in and check each entry's validity
@@ -398,9 +396,10 @@ class Mcdev {
398
396
  selectedTypesArr = structuredClone(selectedTypesArr);
399
397
 
400
398
  const properties = await config.getProperties();
401
- if (!(await config.checkProperties(properties))) {
402
- return null;
399
+ if (!properties) {
400
+ return;
403
401
  }
402
+
404
403
  const buObject = await Cli.getCredentialObject(
405
404
  properties,
406
405
  cred === null ? null : cred + '/' + bu,
@@ -559,9 +558,10 @@ class Mcdev {
559
558
  Util.startLogger();
560
559
  Util.logger.info('mcdev:: Load BUs');
561
560
  const properties = await config.getProperties();
562
- if (!(await config.checkProperties(properties))) {
563
- return null;
561
+ if (!properties) {
562
+ return;
564
563
  }
564
+
565
565
  const buObject = await Cli.getCredentialObject(properties, credentialsName, true);
566
566
  if (buObject !== null) {
567
567
  BuHelper.refreshBUProperties(properties, buObject.credential);
@@ -579,9 +579,10 @@ class Mcdev {
579
579
  Util.startLogger();
580
580
  Util.logger.info('mcdev:: Document');
581
581
  const properties = await config.getProperties();
582
- if (!(await config.checkProperties(properties))) {
583
- return null;
582
+ if (!properties) {
583
+ return;
584
584
  }
585
+
585
586
  if (type && !MetadataTypeInfo[type]) {
586
587
  Util.logger.error(`:: '${type}' is not a valid metadata type`);
587
588
  return;
@@ -640,9 +641,10 @@ class Mcdev {
640
641
  }
641
642
  }
642
643
  const properties = await config.getProperties();
643
- if (!(await config.checkProperties(properties))) {
644
- return null;
644
+ if (!properties) {
645
+ return;
645
646
  }
647
+
646
648
  const buObject = await Cli.getCredentialObject(properties, businessUnit);
647
649
  if (!buObject) {
648
650
  return;
@@ -711,9 +713,10 @@ class Mcdev {
711
713
  return;
712
714
  }
713
715
  const properties = await config.getProperties();
714
- if (!(await config.checkProperties(properties))) {
715
- return null;
716
+ if (!properties) {
717
+ return;
716
718
  }
719
+
717
720
  const buObject = await Cli.getCredentialObject(properties, businessUnit);
718
721
  if (buObject !== null) {
719
722
  try {
@@ -760,9 +763,10 @@ class Mcdev {
760
763
  Util.startLogger();
761
764
  Util.logger.info('mcdev:: describe SOAP');
762
765
  const properties = await config.getProperties();
763
- if (!(await config.checkProperties(properties))) {
764
- return null;
766
+ if (!properties) {
767
+ return;
765
768
  }
769
+
766
770
  const credential = Object.keys(properties.credentials)[0];
767
771
  businessUnit ||=
768
772
  credential + '/' + Object.keys(properties.credentials[credential].businessUnits)[0];
@@ -807,9 +811,10 @@ class Mcdev {
807
811
  static async badKeys(businessUnit) {
808
812
  Util.startLogger();
809
813
  const properties = await config.getProperties();
810
- if (!(await config.checkProperties(properties))) {
811
- return null;
814
+ if (!properties) {
815
+ return;
812
816
  }
817
+
813
818
  const buObject = await Cli.getCredentialObject(properties, businessUnit);
814
819
  if (buObject !== null) {
815
820
  Util.logger.info('Gathering list of Name<>External Key mismatches (bad keys)');
@@ -884,9 +889,10 @@ class Mcdev {
884
889
  'mcdev:: [DEPRECATED] Retrieve as Template [DEPRECATED] - use "retrieve" + "buildTemplate" instead'
885
890
  );
886
891
  const properties = await config.getProperties();
887
- if (!(await config.checkProperties(properties))) {
888
- return null;
892
+ if (!properties) {
893
+ return;
889
894
  }
895
+
890
896
  if (!Util._isValidType(selectedType)) {
891
897
  return;
892
898
  }
@@ -924,6 +930,10 @@ class Mcdev {
924
930
  }
925
931
  const initialAssetNumber = typeKeyList['asset']?.length || 0;
926
932
  const properties = await config.getProperties();
933
+ if (!properties) {
934
+ return;
935
+ }
936
+
927
937
  const buObject = await Cli.getCredentialObject(properties, businessUnit);
928
938
  Util.logger.info(
929
939
  'Searching for additional dependencies that were linked via ContentBlockByKey, ContentBlockByName and ContentBlockById'
@@ -1032,6 +1042,9 @@ class Mcdev {
1032
1042
  const initiallySelectedTypesArr = Object.keys(typeKeyList);
1033
1043
 
1034
1044
  const properties = await config.getProperties();
1045
+ if (!properties) {
1046
+ return;
1047
+ }
1035
1048
  const buObject = await Cli.getCredentialObject(properties, businessUnit);
1036
1049
  for (const type of initiallySelectedTypesArr) {
1037
1050
  MetadataTypeInfo[type].properties = properties;
@@ -1138,6 +1151,9 @@ class Mcdev {
1138
1151
 
1139
1152
  // redirect templates to temporary folder when executed via build()
1140
1153
  const properties = await config.getProperties();
1154
+ if (!properties) {
1155
+ return;
1156
+ }
1141
1157
  const templateDirBackup = properties.directories.template;
1142
1158
  properties.directories.template = '.mcdev/template/';
1143
1159
 
@@ -1145,7 +1161,6 @@ class Mcdev {
1145
1161
  await this.buildTemplate(businessUnitTemplate, typeKeyCombo, null, marketTemplate);
1146
1162
 
1147
1163
  if (typeof Util.OPTIONS.purge !== 'boolean') {
1148
- const properties = await config.getProperties();
1149
1164
  // deploy folder is in targets for definition creation
1150
1165
  // recommend to purge their content first
1151
1166
  Util.OPTIONS.purge = await confirm({
@@ -1190,6 +1205,9 @@ class Mcdev {
1190
1205
  Util.startLogger();
1191
1206
  Util.logger.info('mcdev:: Build Template from retrieved files');
1192
1207
  const properties = await config.getProperties();
1208
+ if (!properties) {
1209
+ return;
1210
+ }
1193
1211
  const buObject = await Cli.getCredentialObject(properties, businessUnit);
1194
1212
  if (!Util.checkMarketList(marketArr, properties)) {
1195
1213
  return;
@@ -1317,6 +1335,9 @@ class Mcdev {
1317
1335
  Util.startLogger();
1318
1336
  Util.logger.info('mcdev:: Build Definition from Template');
1319
1337
  const properties = await config.getProperties();
1338
+ if (!properties) {
1339
+ return;
1340
+ }
1320
1341
  if (!Util.checkMarketList(marketArr, properties)) {
1321
1342
  return;
1322
1343
  }
@@ -1331,7 +1352,7 @@ class Mcdev {
1331
1352
 
1332
1353
  if (Util.OPTIONS.purge) {
1333
1354
  const buObject = await Cli.getCredentialObject(properties, businessUnit);
1334
- Builder.purgeDeployFolder(buObject.credential + '/' + buObject.businessUnit);
1355
+ await Builder.purgeDeployFolder(buObject.credential + '/' + buObject.businessUnit);
1335
1356
  } else {
1336
1357
  Util.logger.info(` ☇ skipping purge of folder`);
1337
1358
  }
@@ -1365,6 +1386,9 @@ class Mcdev {
1365
1386
  Util.logger.info('mcdev:: Build Definition from Template Bulk');
1366
1387
 
1367
1388
  const properties = await config.getProperties();
1389
+ if (!properties) {
1390
+ return;
1391
+ }
1368
1392
  try {
1369
1393
  Util.verifyMarketList(listName, properties);
1370
1394
  } catch (ex) {
@@ -1380,7 +1404,7 @@ class Mcdev {
1380
1404
  return;
1381
1405
  }
1382
1406
  if (Util.OPTIONS.purge) {
1383
- Builder.purgeDeployFolderList(listName);
1407
+ await Builder.purgeDeployFolderList(listName);
1384
1408
  } else {
1385
1409
  Util.logger.info(` ☇ skipping purge of folder`);
1386
1410
  }
@@ -1406,8 +1430,8 @@ class Mcdev {
1406
1430
  Util.startLogger();
1407
1431
  Util.logger.info('mcdev:: getFilesToCommit');
1408
1432
  const properties = await config.getProperties();
1409
- if (!(await config.checkProperties(properties))) {
1410
- return null;
1433
+ if (!properties) {
1434
+ return;
1411
1435
  }
1412
1436
  if (!Util._isValidType(selectedType)) {
1413
1437
  return;
@@ -1539,6 +1563,9 @@ class Mcdev {
1539
1563
  this.setOptions({ referenceFrom, referenceTo });
1540
1564
 
1541
1565
  const properties = await config.getProperties();
1566
+ if (!properties) {
1567
+ return;
1568
+ }
1542
1569
  if (!Util.isValidBU(properties, businessUnit)) {
1543
1570
  return;
1544
1571
  }
@@ -1596,6 +1623,9 @@ class Mcdev {
1596
1623
  */
1597
1624
  static async fixKeys(businessUnit, selectedTypes, keys) {
1598
1625
  const properties = await config.getProperties();
1626
+ if (!properties) {
1627
+ return;
1628
+ }
1599
1629
  // make sure validation rules dont keep us from fixing the keys
1600
1630
  this.setOptions({ skipValidation: true });
1601
1631
  let reRetrieveAll = false;
@@ -1797,9 +1827,8 @@ class Mcdev {
1797
1827
  return resultObj;
1798
1828
  }
1799
1829
  const properties = await config.getProperties();
1800
- if (!(await config.checkProperties(properties))) {
1801
- // return null here to avoid seeing 2 error messages for the same issue
1802
- return resultObj;
1830
+ if (!properties) {
1831
+ return;
1803
1832
  }
1804
1833
  for (const selectedType of selectedTypesArr || Object.keys(selectedTypesObj)) {
1805
1834
  Util.logger.info(`mcdev:: ${methodName} ${selectedType}`);
@@ -1924,6 +1953,9 @@ class Mcdev {
1924
1953
  */
1925
1954
  static async #runOnBU(methodName, cred, bu, type, keyArr) {
1926
1955
  const properties = await config.getProperties();
1956
+ if (!properties) {
1957
+ return;
1958
+ }
1927
1959
  const resultArr = [];
1928
1960
  const buObject = await Cli.getCredentialObject(
1929
1961
  properties,
@@ -1983,6 +2015,9 @@ class Mcdev {
1983
2015
  */
1984
2016
  static async #retrieveKeysWithLike(selectedType, buObject) {
1985
2017
  const properties = await config.getProperties();
2018
+ if (!properties) {
2019
+ return;
2020
+ }
1986
2021
 
1987
2022
  // cache depenencies
1988
2023
  const deployOrder = Util.getMetadataHierachy([selectedType]);
@@ -2050,6 +2085,9 @@ class Mcdev {
2050
2085
  */
2051
2086
  static async #fixKeys(cred, bu, type, keyArr) {
2052
2087
  const properties = await config.getProperties();
2088
+ if (!properties) {
2089
+ return;
2090
+ }
2053
2091
  let actuallyFixedKeys = [];
2054
2092
  const resultArr = [];
2055
2093
 
@@ -2133,6 +2171,9 @@ class Mcdev {
2133
2171
  */
2134
2172
  static async #replaceCbReference(cred, bu, type, keyArr) {
2135
2173
  const properties = await config.getProperties();
2174
+ if (!properties) {
2175
+ return;
2176
+ }
2136
2177
  let updatedKeys = [];
2137
2178
  const resultArr = [];
2138
2179
 
@@ -402,7 +402,7 @@ class DataExtension extends MetadataType {
402
402
  }
403
403
 
404
404
  // find all shared data extensions
405
- if (!this.deployedSharedKeys.length) {
405
+ if (!this.deployedSharedKeys?.length) {
406
406
  Util.logger.debug(
407
407
  `Skipping fixShared logic because no Shared Data Extensions were updated`
408
408
  );
@@ -290,25 +290,42 @@ class Journey extends MetadataType {
290
290
  );
291
291
  // break;
292
292
  }
293
- default: {
294
- // Quicksend, Transactional dont have versions
295
- const response = await super.deleteByKeyREST(
293
+ case 'Quicksend': {
294
+ // Quicksend doesnt have versions
295
+ const isDeleted = await super.deleteByKeyREST(
296
+ '/interaction/v1/interactions/' + id,
297
+ key,
298
+ false
299
+ );
300
+ return isDeleted;
301
+ }
302
+ case 'Transactional': {
303
+ // Transactional dont have versions
304
+ const isDeleted = await super.deleteByKeyREST(
296
305
  '/interaction/v1/interactions/' + id,
297
306
  key,
298
307
  false
299
308
  );
300
- if (response && cachedJourney.definitionType === 'Transactional') {
309
+ const transactionalEmailKey =
310
+ cachedJourney.activities[0]?.configurationArguments?.triggeredSendKey;
311
+ if (isDeleted) {
301
312
  const msg = [];
302
313
  if (cachedJourney.activities[0]?.configurationArguments?.triggeredSendKey) {
303
314
  msg.push(
304
315
  `transactionalEmail "${cachedJourney.activities[0].configurationArguments.triggeredSendKey}"`
305
316
  );
306
317
  }
307
- if (msg.length) {
308
- Util.logger.info(` - Remember to also delete linked ${msg.join(' and ')}`);
309
- }
310
318
  }
311
- return response;
319
+ if (isDeleted && transactionalEmailKey) {
320
+ Util.logger.info(
321
+ ` - deleted ${TransactionalEmail.definition.type}: ${transactionalEmailKey} (SFMC auto-deletes the related transactionalEmail of ${this.definition.type} ${key})`
322
+ );
323
+ TransactionalEmail.buObject = this.buObject;
324
+ TransactionalEmail.properties = this.properties;
325
+ TransactionalEmail.client = this.client;
326
+ TransactionalEmail.postDeleteTasks(transactionalEmailKey);
327
+ }
328
+ return isDeleted;
312
329
  }
313
330
  }
314
331
  }
@@ -416,6 +433,10 @@ class Journey extends MetadataType {
416
433
  */
417
434
  static async postRetrieveTasks(metadata) {
418
435
  // folder
436
+ if (metadata.r__folder_Path && Util.OPTIONS.publish) {
437
+ // if we re-retrieve this as part of deploy with --publish then the cached version will already have been processed
438
+ return metadata;
439
+ }
419
440
  super.setFolderPath(metadata);
420
441
 
421
442
  switch (metadata.definitionType) {
@@ -2288,6 +2309,7 @@ class Journey extends MetadataType {
2288
2309
  toBeRetrievedTypes.map((item) => item + 's').join(', ')
2289
2310
  );
2290
2311
  await retriever.retrieve(toBeRetrievedTypes, eventTransEmailCombo);
2312
+ // TODO find r__automation_key in events and retrieve these automations as well
2291
2313
  }
2292
2314
  }
2293
2315
  } catch (ex) {
@@ -2857,17 +2857,17 @@ class MetadataType {
2857
2857
  * Gets executed before deploying metadata
2858
2858
  *
2859
2859
  * @param {'retrieve'|'buildDefinition'|'deploy'} method used to select the right config
2860
- * @param {MetadataTypeItem | CodeExtractItem} item a single metadata item
2860
+ * @param {MetadataTypeItem | CodeExtractItem} originalItem a single metadata item
2861
2861
  * @param {string} targetDir folder where files for deployment are stored
2862
2862
  * @returns {Promise.<MetadataTypeItem | CodeExtractItem>} Promise of a single metadata item
2863
2863
  */
2864
- static async validation(method, item, targetDir) {
2864
+ static async validation(method, originalItem, targetDir) {
2865
2865
  if (!this.properties.options?.validation?.[method]) {
2866
- return item;
2866
+ return originalItem;
2867
2867
  }
2868
2868
  // if the fix parameter was set, allow validation rules to override the metadata
2869
- const originalItem = item;
2870
- item = Util.OPTIONS.fix ? item : structuredClone(item);
2869
+ /** @type {MetadataTypeItem | CodeExtractItem} */
2870
+ let item = Util.OPTIONS.fix ? originalItem : structuredClone(originalItem);
2871
2871
  /** @type {MetadataTypeItem} */
2872
2872
  const metadataItem = item.json && item.codeArr ? item.json : item;
2873
2873
  const codeArr = item.codeArr || null;
@@ -2902,36 +2902,43 @@ class MetadataType {
2902
2902
 
2903
2903
  // run validation rules
2904
2904
  const warnings = [];
2905
+ let fixed = false;
2905
2906
  for (const rule of Object.keys(validationRules)) {
2906
2907
  if (
2907
2908
  validationConfig[rule] &&
2908
2909
  validationConfig[rule] !== 'off' &&
2909
2910
  !this.definition.skipValidation?.[rule]
2910
2911
  ) {
2911
- const passed = await validationRules[rule].passed();
2912
+ const mode = Util.OPTIONS.fix ? 'fix' : validationConfig[rule];
2913
+ const passed = await validationRules[rule].passed(mode);
2914
+ if (mode === 'fix') {
2915
+ // potentially fixed really
2916
+ fixed = true;
2917
+ }
2912
2918
  if (!passed) {
2913
- if (!Util.OPTIONS.skipValidation && validationConfig[rule] === 'error') {
2914
- if (!Util.OPTIONS.fix || passed === false) {
2915
- throw new Error(validationRules[rule].failedMsg);
2916
- } else if (Util.OPTIONS.fix && passed === null) {
2917
- // ensure this item no longer exists outside of the validation rule
2918
- item = null;
2919
- warnings.push(
2920
- ` ☇ filtered item via validation rule --fix: ` +
2921
- validationRules[rule].failedMsg
2922
- );
2923
- }
2924
- } else if (Util.OPTIONS.skipValidation || validationConfig[rule] === 'warn') {
2925
- if (!Util.OPTIONS.fix || passed === false) {
2919
+ if (mode === 'fix') {
2920
+ if (passed === false) {
2926
2921
  warnings.push(validationRules[rule].failedMsg);
2927
- } else if (Util.OPTIONS.fix && passed === null) {
2922
+ } else if (passed === null) {
2928
2923
  // ensure this item no longer exists outside of the validation rule
2929
2924
  item = null;
2930
2925
  warnings.push(
2931
- ` ☇ filtered item via validation rule --fix: ` +
2926
+ ` ☇ filtered item via validation rule fix: ` +
2932
2927
  validationRules[rule].failedMsg
2933
2928
  );
2929
+ break;
2934
2930
  }
2931
+ } else if (
2932
+ !Util.OPTIONS.skipValidation &&
2933
+ validationConfig[rule] === 'error' &&
2934
+ passed === false
2935
+ ) {
2936
+ throw new Error(validationRules[rule].failedMsg);
2937
+ } else if (
2938
+ (Util.OPTIONS.skipValidation || validationConfig[rule] === 'warn') &&
2939
+ passed === false
2940
+ ) {
2941
+ warnings.push(validationRules[rule].failedMsg);
2935
2942
  }
2936
2943
  }
2937
2944
  }
@@ -2943,7 +2950,7 @@ class MetadataType {
2943
2950
  );
2944
2951
  }
2945
2952
  // only return "fixed" item if --fix is set, otherwise return the original item
2946
- return Util.OPTIONS.fix ? item : originalItem;
2953
+ return Util.OPTIONS.fix || fixed ? item : originalItem;
2947
2954
  }
2948
2955
  }
2949
2956
 
@@ -990,6 +990,12 @@ export default {
990
990
  retrieving: true,
991
991
  template: true,
992
992
  },
993
+ 'triggers[].metaData.scheduleState': {
994
+ isCreateable: true,
995
+ isUpdateable: true,
996
+ retrieving: true,
997
+ template: true,
998
+ },
993
999
  version: {
994
1000
  isCreateable: false,
995
1001
  isUpdateable: true,
@@ -46,6 +46,9 @@ const config = {
46
46
  if (await File.pathExists(Util.configFileName)) {
47
47
  try {
48
48
  config.properties = await File.readJSON(Util.configFileName);
49
+ if (!isInit && !(await this.checkProperties(config.properties, silent))) {
50
+ return;
51
+ }
49
52
  } catch (ex) {
50
53
  Util.logger.error(`${ex.code}: ${ex.message}`);
51
54
  return;
@@ -94,6 +97,9 @@ const config = {
94
97
  );
95
98
  return;
96
99
  }
100
+ } else if (!silent && !isInit) {
101
+ Util.logger.error(`Could not find ${Util.configFileName} in ${process.cwd()}.`);
102
+ Util.logger.error(`Run 'mcdev init' to initialize your project.\n`);
97
103
  }
98
104
  return config.properties;
99
105
  },
@@ -450,7 +450,7 @@ const DevOps = {
450
450
  // if --purge was defined and there is more than one source-target mapping, execute the purge up front to avoid deleting the package that was created by a prior mapping in this same run
451
451
  for (const sourceMlName of sourceMarketListArr) {
452
452
  /** @type {string} */
453
- Builder.purgeDeployFolderList(sourceTargetMapping[sourceMlName]);
453
+ await Builder.purgeDeployFolderList(sourceTargetMapping[sourceMlName]);
454
454
  }
455
455
  Util.OPTIONS.purge = false;
456
456
  }
package/lib/util/file.js CHANGED
@@ -196,7 +196,7 @@ const File = {
196
196
  let formatted;
197
197
  const properties = await config.getProperties();
198
198
  if (
199
- (properties.options.formatOnSave && Util.OPTIONS.format === undefined) ||
199
+ (properties?.options?.formatOnSave && Util.OPTIONS.format === undefined) ||
200
200
  Util.OPTIONS.format
201
201
  ) {
202
202
  formatted =
@@ -239,7 +239,7 @@ const File = {
239
239
  beautify_beautyAmp: async function (content, formatHTML = true) {
240
240
  const properties = await config.getProperties();
241
241
  if (
242
- (properties.options.formatOnSave && Util.OPTIONS.format === undefined) ||
242
+ (properties?.options?.formatOnSave && Util.OPTIONS.format === undefined) ||
243
243
  Util.OPTIONS.format
244
244
  ) {
245
245
  // logs trough console only for the moment.
@@ -338,7 +338,7 @@ const File = {
338
338
 
339
339
  formatted = await prettier.format(content, FileFs.prettierConfig);
340
340
  } catch (ex) {
341
- if (properties.options.formatErrorLog) {
341
+ if (properties?.options?.formatErrorLog) {
342
342
  // save prettier errror into log file
343
343
  // Note: we have to filter color codes from prettier's error message before saving it to file
344
344
  /* eslint-disable no-control-regex */
package/lib/util/util.js CHANGED
@@ -39,9 +39,6 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
39
39
  * Util that contains logger and simple util methods
40
40
  */
41
41
  export const Util = {
42
- isRunViaVSCodeExtension:
43
- process.env.VSCODE_AMD_ENTRYPOINT === 'vs/workbench/api/node/extensionHostProcess' || // run via VSCode extension
44
- process.env.VSCODE_CRASH_REPORTER_PROCESS_TYPE === 'extensionHost',
45
42
  authFileName: '.mcdev-auth.json',
46
43
  boilerplateDirectory: '../../boilerplate',
47
44
  configFileName: '.mcdevrc.json',
@@ -359,8 +356,8 @@ export const Util = {
359
356
  // debug: 5,
360
357
  // silly: 6
361
358
  // }
359
+
362
360
  if (
363
- this.isRunViaVSCodeExtension || // run via VSCode extension
364
361
  process.env.FORK_PROCESS_ID || // run via Git-Fork
365
362
  process.env.PATH.toLowerCase().includes('sourcetree') // run via Atlassian SourceTree
366
363
  ) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcdev",
3
- "version": "7.7.0",
3
+ "version": "7.7.1",
4
4
  "description": "Accenture Salesforce Marketing Cloud DevTools",
5
5
  "author": "Accenture: joern.berkefeld, douglas.midgley, robert.zimmermann, maciej.barnas",
6
6
  "license": "MIT",
@@ -155,5 +155,5 @@
155
155
  "verification"
156
156
  ]
157
157
  },
158
- "version": "7.7.0"
158
+ "version": "7.7.1"
159
159
  }
@@ -12,30 +12,7 @@ const projectRoot = projectRootHelper.join(path.sep) + path.sep;
12
12
  const parser = new XMLParser();
13
13
  const attributeParser = new XMLParser({ ignoreAttributes: false });
14
14
  /** @type {typeof Util.color} */
15
- let color;
16
-
17
- /* eslint-disable unicorn/prefer-ternary */
18
- if (Util.isRunViaVSCodeExtension) {
19
- // when we execute the test in a VSCode extension host, we don't want CLI color codes.
20
- // @ts-expect-error hacky way to get rid of colors - ts doesn't appreciate the hack
21
- color = new Proxy(
22
- {},
23
- {
24
- /**
25
- * catch-all for color
26
- *
27
- * @returns {string} empty string
28
- */
29
- get() {
30
- return '';
31
- },
32
- }
33
- );
34
- } else {
35
- // test is executed directly in a command prompt. Use colors.
36
- color = Util.color;
37
- }
38
- /* eslint-enable unicorn/prefer-ternary */
15
+ const color = Util.color;
39
16
 
40
17
  export const tWarn = `${color.bgYellow}${color.fgBlack}TEST-WARNING${color.reset}`;
41
18
  export const tError = `${color.bgRed}${color.fgBlack}TEST-ERROR${color.reset}`;