mcdev 9.0.2 → 9.0.3

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.
Files changed (47) hide show
  1. package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
  2. package/.github/copilot-instructions.md +85 -0
  3. package/.github/pr-labeler.yml +3 -3
  4. package/.github/workflows/coverage-base-update.yml +2 -2
  5. package/.github/workflows/coverage.yml +1 -1
  6. package/.github/workflows/npm-publish.yml +51 -2
  7. package/.github/workflows/sync-milestone.yml +55 -0
  8. package/.husky/post-checkout +1 -1
  9. package/@types/lib/Retriever.d.ts.map +1 -1
  10. package/@types/lib/metadataTypes/DataExtension.d.ts +2 -0
  11. package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
  12. package/@types/lib/metadataTypes/DataExtensionField.d.ts +25 -0
  13. package/@types/lib/metadataTypes/DataExtensionField.d.ts.map +1 -1
  14. package/@types/lib/metadataTypes/Filter.d.ts +1 -1
  15. package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
  16. package/@types/lib/metadataTypes/MetadataType.d.ts +10 -0
  17. package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
  18. package/@types/lib/metadataTypes/definitions/Filter.definition.d.ts +1 -1
  19. package/@types/lib/util/cli.d.ts.map +1 -1
  20. package/lib/Retriever.js +2 -1
  21. package/lib/index.js +2 -2
  22. package/lib/metadataTypes/DataExtension.js +59 -0
  23. package/lib/metadataTypes/DataExtensionField.js +114 -0
  24. package/lib/metadataTypes/Journey.js +82 -39
  25. package/lib/metadataTypes/MetadataType.js +24 -8
  26. package/lib/metadataTypes/definitions/Filter.definition.js +2 -3
  27. package/lib/util/cli.js +3 -0
  28. package/package.json +10 -10
  29. package/test/general.test.js +11 -11
  30. package/test/mockRoot/.mcdevrc.json +1 -1
  31. package/test/mockRoot/deploy/testInstance/testBU/journey/testExisting_journey_updatecontact_sharedDE.journey-meta.json +108 -0
  32. package/test/resources/1111111/dataExtension/template_sharedDE-expected.json +53 -0
  33. package/test/resources/9999999/automation/v1/queries/get-response.json +17 -0
  34. package/test/resources/9999999/interaction/v1/interactions/get-response.json +40 -2
  35. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_journey_updatecontact/get-response.json +4 -4
  36. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_journey_updatecontact_sharedDE/get-response.json +119 -0
  37. package/test/resources/9999999/interaction/v1/interactions/key_testExisting_journey_updatecontact_sharedDE/put-response.json +110 -0
  38. package/test/resources/9999999/journey/get-updatecontact-sharedDE-expected.json +108 -0
  39. package/test/resources/9999999/journey/put-updatecontact-sharedDE-expected.json +108 -0
  40. package/test/resources/9999999/query/get_sharedDE-expected.json +11 -0
  41. package/test/resources/9999999/query/get_sharedDE-expected.sql +7 -0
  42. package/test/resources/9999999/query/template_sharedDE-expected.json +8 -0
  43. package/test/resources/9999999/query/template_sharedDE-expected.sql +7 -0
  44. package/test/type.attributeSet.test.js +41 -0
  45. package/test/type.automation.test.js +1 -1
  46. package/test/type.journey.test.js +108 -6
  47. package/test/type.query.test.js +105 -8
@@ -52,5 +52,46 @@ describe('type: attributeSet', () => {
52
52
  );
53
53
  return;
54
54
  });
55
+
56
+ it('Should resolve shared dataExtensions in attributeSet when retrieved together with dataExtension', async () => {
57
+ // WHEN
58
+ // this test verifies the fix for: shared DEs not resolved if attributeSet+dataExtension is retrieved together
59
+ const retrieve = await handler.retrieve('testInstance/testBU', [
60
+ 'dataExtension',
61
+ 'attributeSet',
62
+ ]);
63
+
64
+ // THEN
65
+ assert.equal(process.exitCode, 0, 'retrieve should not have thrown an error');
66
+ assert.equal(
67
+ retrieve['testInstance/testBU'].attributeSet
68
+ ? Object.keys(retrieve['testInstance/testBU'].attributeSet).length
69
+ : 0,
70
+ 28,
71
+ 'only 28 attributeSets expected in retrieve response'
72
+ );
73
+ // get results from cache
74
+ const result = cache.getCache();
75
+ assert.equal(
76
+ result.attributeSet ? Object.keys(result.attributeSet).length : 0,
77
+ 28,
78
+ 'only 28 attributeSets expected in cache'
79
+ );
80
+
81
+ // verify that shared DE was resolved correctly in attributeSet (this is the key bug fix check)
82
+ assert.deepEqual(
83
+ await testUtils.getActualJson('testExisting_dataExtensionShared', 'attributeSet'),
84
+ await testUtils.getExpectedJson('9999999', 'attributeSet', 'retrieve'),
85
+
86
+ 'returned metadata was not equal expected - shared DE should be resolved even when dataExtension is retrieved together with attributeSet'
87
+ );
88
+
89
+ assert.equal(
90
+ testUtils.getAPIHistoryLength(),
91
+ 9,
92
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
93
+ );
94
+ return;
95
+ });
55
96
  });
56
97
  });
@@ -681,7 +681,7 @@ describe('type: automation', () => {
681
681
  await handler.retrieve('testInstance/testBU');
682
682
  assert.equal(process.exitCode, 0, 'retrieve should not have thrown an error');
683
683
 
684
- const expectedApiCallsRetrieve = 109;
684
+ const expectedApiCallsRetrieve = 111;
685
685
  assert.equal(
686
686
  testUtils.getAPIHistoryLength(),
687
687
  expectedApiCallsRetrieve,
@@ -26,7 +26,7 @@ describe('type: journey', () => {
26
26
  const result = cache.getCache();
27
27
  assert.equal(
28
28
  result.journey ? Object.keys(result.journey).length : 0,
29
- 5,
29
+ 6,
30
30
  'unexpected number of journeys'
31
31
  );
32
32
  assert.deepEqual(
@@ -44,9 +44,52 @@ describe('type: journey', () => {
44
44
  await testUtils.getExpectedJson('9999999', 'journey', 'get-transactionalEmail'),
45
45
  'returned JSON was not equal expected'
46
46
  );
47
+ assert.deepEqual(
48
+ await testUtils.getActualJson(
49
+ 'testExisting_journey_updatecontact_sharedDE',
50
+ 'journey'
51
+ ),
52
+ await testUtils.getExpectedJson('9999999', 'journey', 'get-updatecontact-sharedDE'),
53
+ 'returned JSON was not equal expected'
54
+ );
47
55
  assert.equal(
48
56
  testUtils.getAPIHistoryLength(),
49
- 29,
57
+ 31,
58
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
59
+ );
60
+ return;
61
+ });
62
+
63
+ it('Should retrieve journeys with dataExtension type simultaneously (mcdev retrieve cred/bu -m journey dataExtension)', async () => {
64
+ // WHEN - both types at once, no keys: unrelated DEs present alongside UPDATECONTACTDATA DEs
65
+ await handler.retrieve('testInstance/testBU', ['journey', 'dataExtension']);
66
+ // THEN
67
+ assert.equal(process.exitCode, 0, 'retrieve should not have thrown an error');
68
+ // get results from cache
69
+ const result = cache.getCache();
70
+ assert.equal(
71
+ result.journey ? Object.keys(result.journey).length : 0,
72
+ 6,
73
+ 'unexpected number of journeys (includes local-DE and shared-DE UPDATECONTACTDATA journeys)'
74
+ );
75
+ // Verify UPDATECONTACTDATA activity with local DE is correctly resolved
76
+ assert.deepEqual(
77
+ await testUtils.getActualJson('testExisting_journey_updatecontact', 'journey'),
78
+ await testUtils.getExpectedJson('9999999', 'journey', 'get-updatecontact'),
79
+ 'returned JSON was not equal expected for journey with local DE updatecontact activity'
80
+ );
81
+ // Verify UPDATECONTACTDATA activity with shared DE is correctly resolved
82
+ assert.deepEqual(
83
+ await testUtils.getActualJson(
84
+ 'testExisting_journey_updatecontact_sharedDE',
85
+ 'journey'
86
+ ),
87
+ await testUtils.getExpectedJson('9999999', 'journey', 'get-updatecontact-sharedDE'),
88
+ 'returned JSON was not equal expected for journey with shared DE updatecontact activity'
89
+ );
90
+ assert.equal(
91
+ testUtils.getAPIHistoryLength(),
92
+ 34,
50
93
  'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
51
94
  );
52
95
  return;
@@ -167,6 +210,39 @@ describe('type: journey', () => {
167
210
  return;
168
211
  });
169
212
 
213
+ it('Should retrieve a journey containing an UPDATECONTACTDATA activity referencing a shared DE with key', async () => {
214
+ // WHEN
215
+ await handler.retrieve(
216
+ 'testInstance/testBU',
217
+ ['journey'],
218
+ ['testExisting_journey_updatecontact_sharedDE']
219
+ );
220
+ // THEN
221
+ assert.equal(process.exitCode, 0, 'retrieve should not have thrown an error');
222
+ // get results from cache
223
+ const result = cache.getCache();
224
+ assert.equal(
225
+ result.journey ? Object.keys(result.journey).length : 0,
226
+ 1,
227
+ 'only 1 journeys expected'
228
+ );
229
+
230
+ assert.deepEqual(
231
+ await testUtils.getActualJson(
232
+ 'testExisting_journey_updatecontact_sharedDE',
233
+ 'journey'
234
+ ),
235
+ await testUtils.getExpectedJson('9999999', 'journey', 'get-updatecontact-sharedDE'),
236
+ 'returned JSON was not equal expected'
237
+ );
238
+ assert.equal(
239
+ testUtils.getAPIHistoryLength(),
240
+ 20,
241
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
242
+ );
243
+ return;
244
+ });
245
+
170
246
  it('Should retrieve a Transactional Email journey with key', async () => {
171
247
  // WHEN
172
248
  await handler.retrieve('testInstance/testBU', ['journey'], ['testExisting_temail']);
@@ -504,6 +580,32 @@ describe('type: journey', () => {
504
580
  );
505
581
  return;
506
582
  });
583
+
584
+ it('Should update a journey with UPDATECONTACT activity referencing a shared DE', async () => {
585
+ // WHEN
586
+ await handler.deploy(
587
+ 'testInstance/testBU',
588
+ ['journey'],
589
+ ['testExisting_journey_updatecontact_sharedDE']
590
+ );
591
+ // THEN
592
+ assert.equal(process.exitCode, 0, 'deploy should not have thrown an error');
593
+ // confirm updated item
594
+ assert.deepEqual(
595
+ await testUtils.getActualJson(
596
+ 'testExisting_journey_updatecontact_sharedDE',
597
+ 'journey'
598
+ ),
599
+ await testUtils.getExpectedJson('9999999', 'journey', 'put-updatecontact-sharedDE'),
600
+ 'returned metadata was not equal expected for update journey with shared DE updatecontact activity'
601
+ );
602
+ assert.equal(
603
+ testUtils.getAPIHistoryLength(),
604
+ 22,
605
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
606
+ );
607
+ return;
608
+ });
507
609
  });
508
610
 
509
611
  describe('Templating ================', () => {
@@ -545,7 +647,7 @@ describe('type: journey', () => {
545
647
 
546
648
  assert.equal(
547
649
  testUtils.getAPIHistoryLength(),
548
- 29,
650
+ 31,
549
651
  'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
550
652
  );
551
653
  return;
@@ -741,7 +843,7 @@ describe('type: journey', () => {
741
843
 
742
844
  assert.equal(
743
845
  testUtils.getAPIHistoryLength(),
744
- 35,
846
+ 37,
745
847
  'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
746
848
  );
747
849
  return;
@@ -776,7 +878,7 @@ describe('type: journey', () => {
776
878
 
777
879
  assert.equal(
778
880
  testUtils.getAPIHistoryLength(),
779
- 35,
881
+ 37,
780
882
  'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
781
883
  );
782
884
  return;
@@ -811,7 +913,7 @@ describe('type: journey', () => {
811
913
 
812
914
  assert.equal(
813
915
  testUtils.getAPIHistoryLength(),
814
- 35,
916
+ 37,
815
917
  'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
816
918
  );
817
919
  return;
@@ -27,8 +27,8 @@ describe('type: query', () => {
27
27
  const result = cache.getCache();
28
28
  assert.equal(
29
29
  result.query ? Object.keys(result.query).length : 0,
30
- 4,
31
- 'only 4 queries expected'
30
+ 5,
31
+ 'only 5 queries expected'
32
32
  );
33
33
  // normal test
34
34
  assert.deepEqual(
@@ -54,6 +54,37 @@ describe('type: query', () => {
54
54
  return;
55
55
  });
56
56
 
57
+ it('Should resolve shared dataExtensions in query when retrieved together with dataExtension', async () => {
58
+ // WHEN
59
+ // this test verifies the fix for: shared DEs not resolved if query+dataExtension is retrieved together
60
+ await handler.retrieve('testInstance/testBU', ['dataExtension', 'query']);
61
+ // THEN
62
+ assert.equal(process.exitCode, 0, 'retrieve should not have thrown an error');
63
+ // get results from cache
64
+ const result = cache.getCache();
65
+ assert.equal(
66
+ result.query ? Object.keys(result.query).length : 0,
67
+ 5,
68
+ 'only 5 queries expected'
69
+ );
70
+ // verify that shared DE was resolved correctly in query (this is the key bug fix check)
71
+ assert.deepEqual(
72
+ await testUtils.getActualJson('testExisting_query_SharedDE', 'query'),
73
+ await testUtils.getExpectedJson('9999999', 'query', 'get_sharedDE'),
74
+ 'returned metadata was not equal expected - shared DE should be resolved even when dataExtension is retrieved together with query'
75
+ );
76
+ expect(
77
+ await testUtils.getActualFile('testExisting_query_SharedDE', 'query', 'sql')
78
+ ).to.equal(await testUtils.getExpectedFile('9999999', 'query', 'get_sharedDE', 'sql'));
79
+
80
+ assert.equal(
81
+ testUtils.getAPIHistoryLength(),
82
+ 8,
83
+ 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests'
84
+ );
85
+ return;
86
+ });
87
+
57
88
  it('Should retrieve one specific query by key', async () => {
58
89
  // WHEN
59
90
  await handler.retrieve('testInstance/testBU', ['query'], ['testExisting_query']);
@@ -92,8 +123,8 @@ describe('type: query', () => {
92
123
  const result = cache.getCache();
93
124
  assert.equal(
94
125
  result.query ? Object.keys(result.query).length : 0,
95
- 4,
96
- '4 queries in cache expected'
126
+ 5,
127
+ '5 queries in cache expected'
97
128
  );
98
129
  assert.deepEqual(
99
130
  await testUtils.getActualJson('testExisting_query', 'query'),
@@ -123,8 +154,8 @@ describe('type: query', () => {
123
154
  const result = cache.getCache();
124
155
  assert.equal(
125
156
  result.query ? Object.keys(result.query).length : 0,
126
- 4,
127
- '4 queries in cache expected'
157
+ 5,
158
+ '5 queries in cache expected'
128
159
  );
129
160
 
130
161
  expect(await testUtils.getActualFile('testExisting_query', 'query', 'sql')).to.not
@@ -165,8 +196,8 @@ describe('type: query', () => {
165
196
  const result = cache.getCache();
166
197
  assert.equal(
167
198
  result.query ? Object.keys(result.query).length : 0,
168
- 5,
169
- '5 queries expected in cache'
199
+ 6,
200
+ '6 queries expected in cache'
170
201
  );
171
202
  // confirm created item
172
203
  assert.deepEqual(
@@ -784,6 +815,72 @@ describe('type: query', () => {
784
815
  return;
785
816
  });
786
817
 
818
+ it('Should warn about shared dataExtension in _ParentBU_ when running buildTemplate with --dependencies on child BU', async () => {
819
+ // Retrieve shared DEs from _ParentBU_ to disk first
820
+ await handler.retrieve('testInstance/_ParentBU_', ['dataExtension']);
821
+ assert.equal(
822
+ process.exitCode,
823
+ 0,
824
+ '_ParentBU_ retrieve should not have thrown an error'
825
+ );
826
+ const expectedApiCallsParentBURetrieve = 4;
827
+ assert.equal(
828
+ testUtils.getAPIHistoryLength(),
829
+ expectedApiCallsParentBURetrieve,
830
+ 'Unexpected number of requests for _ParentBU_ dataExtension retrieve'
831
+ );
832
+
833
+ // Retrieve query from child BU (testBU)
834
+ await handler.retrieve('testInstance/testBU', ['query']);
835
+ assert.equal(
836
+ process.exitCode,
837
+ 0,
838
+ 'testBU query retrieve should not have thrown an error'
839
+ );
840
+ const expectedApiCallsTestBURetrieve = 5;
841
+ assert.equal(
842
+ testUtils.getAPIHistoryLength() - expectedApiCallsParentBURetrieve,
843
+ expectedApiCallsTestBURetrieve,
844
+ 'Unexpected number of requests for testBU query retrieve'
845
+ );
846
+
847
+ // Run buildTemplate with --dependencies: shared DE must show a warning, not be included in result
848
+ handler.setOptions({ dependencies: true, skipInteraction: true });
849
+ const templateResult = await handler.buildTemplate(
850
+ 'testInstance/testBU',
851
+ 'query',
852
+ ['testExisting_query_SharedDE'],
853
+ ['testSourceMarket']
854
+ );
855
+ assert.equal(process.exitCode, 0, 'buildTemplate should not have thrown an error');
856
+
857
+ // Verify query was templated
858
+ assert.equal(
859
+ templateResult.query ? templateResult.query.length : 0,
860
+ 1,
861
+ 'expected one query to be templated'
862
+ );
863
+ assert.deepEqual(
864
+ await testUtils.getActualTemplateJson('testExisting_query_SharedDE', 'query'),
865
+ await testUtils.getExpectedJson('9999999', 'query', 'template_sharedDE'),
866
+ 'returned query template JSON was not equal expected'
867
+ );
868
+ expect(
869
+ await testUtils.getActualTemplateFile('testExisting_query_SharedDE', 'query', 'sql')
870
+ ).to.equal(
871
+ await testUtils.getExpectedFile('9999999', 'query', 'template_sharedDE', 'sql')
872
+ );
873
+
874
+ // Verify shared DE was NOT included in template result (only a warning should be shown)
875
+ assert.equal(
876
+ templateResult.dataExtension ? templateResult.dataExtension.length : 0,
877
+ 0,
878
+ 'shared DE should not be included in the child BU template result - only a warning should be shown'
879
+ );
880
+
881
+ return;
882
+ });
883
+
787
884
  it('Should create a query template via buildTemplate and build it', async () => {
788
885
  // download first before we test buildTemplate
789
886
  await handler.retrieve('testInstance/testBU', ['query']);