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.
Files changed (135) hide show
  1. package/.eslintrc.json +67 -7
  2. package/.github/ISSUE_TEMPLATE/bug.yml +5 -1
  3. package/.github/ISSUE_TEMPLATE/task.md +1 -1
  4. package/.github/PULL_REQUEST_TEMPLATE.md +5 -3
  5. package/.github/dependabot.yml +14 -0
  6. package/.github/workflows/code-analysis.yml +57 -0
  7. package/.husky/commit-msg +10 -0
  8. package/.husky/post-checkout +5 -0
  9. package/.husky/pre-commit +2 -1
  10. package/.prettierrc +8 -0
  11. package/.vscode/settings.json +1 -1
  12. package/LICENSE +2 -2
  13. package/README.md +134 -45
  14. package/boilerplate/config.json +5 -11
  15. package/boilerplate/files/.prettierrc +8 -0
  16. package/boilerplate/files/.vscode/extensions.json +0 -1
  17. package/boilerplate/files/.vscode/settings.json +28 -2
  18. package/boilerplate/files/README.md +2 -2
  19. package/boilerplate/forcedUpdates.json +10 -0
  20. package/boilerplate/npm-dependencies.json +5 -5
  21. package/docs/dist/documentation.md +2795 -1724
  22. package/jsconfig.json +1 -1
  23. package/lib/Builder.js +166 -75
  24. package/lib/Deployer.js +244 -96
  25. package/lib/MetadataTypeDefinitions.js +2 -0
  26. package/lib/MetadataTypeInfo.js +2 -0
  27. package/lib/Retriever.js +61 -84
  28. package/lib/cli.js +133 -25
  29. package/lib/index.js +242 -563
  30. package/lib/metadataTypes/AccountUser.js +101 -95
  31. package/lib/metadataTypes/Asset.js +677 -248
  32. package/lib/metadataTypes/AttributeGroup.js +23 -12
  33. package/lib/metadataTypes/Automation.js +456 -357
  34. package/lib/metadataTypes/Campaign.js +33 -93
  35. package/lib/metadataTypes/ContentArea.js +31 -11
  36. package/lib/metadataTypes/DataExtension.js +391 -376
  37. package/lib/metadataTypes/DataExtensionField.js +131 -54
  38. package/lib/metadataTypes/DataExtensionTemplate.js +22 -4
  39. package/lib/metadataTypes/DataExtract.js +67 -50
  40. package/lib/metadataTypes/DataExtractType.js +14 -8
  41. package/lib/metadataTypes/Discovery.js +21 -16
  42. package/lib/metadataTypes/Email.js +32 -12
  43. package/lib/metadataTypes/EmailSendDefinition.js +85 -80
  44. package/lib/metadataTypes/EventDefinition.js +69 -47
  45. package/lib/metadataTypes/FileTransfer.js +78 -54
  46. package/lib/metadataTypes/Filter.js +11 -4
  47. package/lib/metadataTypes/Folder.js +149 -117
  48. package/lib/metadataTypes/FtpLocation.js +14 -8
  49. package/lib/metadataTypes/ImportFile.js +69 -69
  50. package/lib/metadataTypes/Interaction.js +19 -4
  51. package/lib/metadataTypes/List.js +54 -13
  52. package/lib/metadataTypes/MetadataType.js +687 -479
  53. package/lib/metadataTypes/MobileCode.js +46 -0
  54. package/lib/metadataTypes/MobileKeyword.js +114 -0
  55. package/lib/metadataTypes/Query.js +204 -103
  56. package/lib/metadataTypes/Role.js +76 -61
  57. package/lib/metadataTypes/Script.js +146 -82
  58. package/lib/metadataTypes/SetDefinition.js +20 -8
  59. package/lib/metadataTypes/TriggeredSendDefinition.js +78 -58
  60. package/lib/metadataTypes/definitions/Asset.definition.js +21 -10
  61. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +12 -0
  62. package/lib/metadataTypes/definitions/Automation.definition.js +10 -5
  63. package/lib/metadataTypes/definitions/Campaign.definition.js +44 -1
  64. package/lib/metadataTypes/definitions/DataExtension.definition.js +4 -0
  65. package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +6 -0
  66. package/lib/metadataTypes/definitions/DataExtract.definition.js +18 -14
  67. package/lib/metadataTypes/definitions/Discovery.definition.js +12 -0
  68. package/lib/metadataTypes/definitions/EmailSendDefinition.definition.js +4 -0
  69. package/lib/metadataTypes/definitions/EventDefinition.definition.js +22 -0
  70. package/lib/metadataTypes/definitions/FileTransfer.definition.js +4 -0
  71. package/lib/metadataTypes/definitions/Filter.definition.js +4 -0
  72. package/lib/metadataTypes/definitions/Folder.definition.js +6 -0
  73. package/lib/metadataTypes/definitions/FtpLocation.definition.js +4 -0
  74. package/lib/metadataTypes/definitions/ImportFile.definition.js +10 -5
  75. package/lib/metadataTypes/definitions/Interaction.definition.js +4 -0
  76. package/lib/metadataTypes/definitions/MobileCode.definition.js +163 -0
  77. package/lib/metadataTypes/definitions/MobileKeyword.definition.js +253 -0
  78. package/lib/metadataTypes/definitions/Query.definition.js +4 -0
  79. package/lib/metadataTypes/definitions/Role.definition.js +5 -0
  80. package/lib/metadataTypes/definitions/Script.definition.js +4 -0
  81. package/lib/metadataTypes/definitions/SetDefinition.definition.js +28 -0
  82. package/lib/metadataTypes/definitions/TriggeredSendDefinition.definition.js +4 -0
  83. package/lib/retrieveChangelog.js +7 -6
  84. package/lib/util/auth.js +117 -0
  85. package/lib/util/businessUnit.js +55 -66
  86. package/lib/util/cache.js +194 -0
  87. package/lib/util/cli.js +90 -116
  88. package/lib/util/config.js +302 -0
  89. package/lib/util/devops.js +240 -50
  90. package/lib/util/file.js +120 -191
  91. package/lib/util/init.config.js +195 -69
  92. package/lib/util/init.git.js +45 -50
  93. package/lib/util/init.js +72 -59
  94. package/lib/util/init.npm.js +48 -39
  95. package/lib/util/util.js +280 -564
  96. package/package.json +44 -33
  97. package/test/dataExtension.test.js +152 -0
  98. package/test/mockRoot/.mcdev-auth.json +8 -0
  99. package/test/mockRoot/.mcdevrc.json +67 -0
  100. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/childBU_dataextension_test.dataExtension-meta.json +39 -0
  101. package/test/mockRoot/deploy/testInstance/testBU/dataExtension/testDataExtension.dataExtension-meta.json +23 -0
  102. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +11 -0
  103. package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.sql +4 -0
  104. package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.json +11 -0
  105. package/test/mockRoot/deploy/testInstance/testBU/query/testQuery.query-meta.sql +4 -0
  106. package/test/query.test.js +149 -0
  107. package/test/resourceFactory.js +142 -0
  108. package/test/resources/1111111/dataFolder/retrieve-response.xml +43 -0
  109. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +18 -0
  110. package/test/resources/9999999/automation/v1/queries/get-response.json +24 -0
  111. package/test/resources/9999999/automation/v1/queries/post-response.json +18 -0
  112. package/test/resources/9999999/dataExtension/build-expected.json +51 -0
  113. package/test/resources/9999999/dataExtension/create-expected.json +23 -0
  114. package/test/resources/9999999/dataExtension/create-response.xml +54 -0
  115. package/test/resources/9999999/dataExtension/retrieve-expected.json +51 -0
  116. package/test/resources/9999999/dataExtension/retrieve-response.xml +47 -0
  117. package/test/resources/9999999/dataExtension/template-expected.json +51 -0
  118. package/test/resources/9999999/dataExtension/update-expected.json +55 -0
  119. package/test/resources/9999999/dataExtension/update-response.xml +52 -0
  120. package/test/resources/9999999/dataExtensionField/retrieve-response.xml +93 -0
  121. package/test/resources/9999999/dataExtensionTemplate/retrieve-response.xml +303 -0
  122. package/test/resources/9999999/dataFolder/retrieve-response.xml +65 -0
  123. package/test/resources/9999999/query/build-expected.json +8 -0
  124. package/test/resources/9999999/query/get-expected.json +11 -0
  125. package/test/resources/9999999/query/patch-expected.json +11 -0
  126. package/test/resources/9999999/query/post-expected.json +11 -0
  127. package/test/resources/9999999/query/template-expected.json +8 -0
  128. package/test/resources/auth.json +32 -0
  129. package/test/resources/rest404-response.json +5 -0
  130. package/test/resources/retrieve-response.xml +21 -0
  131. package/test/utils.js +107 -0
  132. package/types/mcdev.d.js +301 -0
  133. package/CHANGELOG.md +0 -126
  134. package/PULL_REQUEST_TEMPLATE.md +0 -19
  135. package/test/util/file.js +0 -51
package/test/utils.js ADDED
@@ -0,0 +1,107 @@
1
+ const File = require('../lib/util/file');
2
+ const path = require('node:path');
3
+ const axios = require('axios');
4
+ const MockAdapter = require('axios-mock-adapter');
5
+ const auth = require('../lib/util/auth');
6
+ const Util = require('../lib/util/util');
7
+
8
+ // for some reason doesnt realize below reference
9
+ // eslint-disable-next-line no-unused-vars
10
+ const fsmock = require('mock-fs');
11
+ let apimock;
12
+ const authResources = require('./resources/auth.json');
13
+ const resourceFactory = require('./resourceFactory');
14
+
15
+ /**
16
+ * gets file from Retrieve folder
17
+ *
18
+ * @param {string} customerKey of metadata
19
+ * @param {string} type of metadata
20
+ * @returns {Promise.<string>} file in string form
21
+ */
22
+ exports.getActualFile = (customerKey, type) =>
23
+ File.readJSON(`./retrieve/testInstance/testBU/${type}/${customerKey}.${type}-meta.json`);
24
+ /**
25
+ * gets file from Deploy folder
26
+ *
27
+ * @param {string} customerKey of metadata
28
+ * @param {string} type of metadata
29
+ * @returns {Promise.<string>} file in string form
30
+ */
31
+ exports.getActualDeployFile = (customerKey, type) =>
32
+ File.readJSON(`./deploy/testInstance/testBU/${type}/${customerKey}.${type}-meta.json`);
33
+ /**
34
+ * gets file from Template folder
35
+ *
36
+ * @param {string} customerKey of metadata
37
+ * @param {string} type of metadata
38
+ * @returns {Promise.<string>} file in string form
39
+ */
40
+ exports.getActualTemplate = (customerKey, type) =>
41
+ File.readJSON(`./template/${type}/${customerKey}.${type}-meta.json`);
42
+
43
+ /**
44
+ * gets file from resources folder which should be used for comparison
45
+ *
46
+ * @param {number} mid of Business Unit
47
+ * @param {string} type of metadata
48
+ * @param {string} action of SOAP request
49
+ * @returns {Promise.<string>} file in string form
50
+ */
51
+ exports.getExpectedFile = (mid, type, action) =>
52
+ File.readJSON(path.join('test', 'resources', mid, type, action + '-expected.json'));
53
+ /**
54
+ * setup mocks for API and FS
55
+ *
56
+ * @returns {void}
57
+ */
58
+ exports.mockSetup = () => {
59
+ Util.setLoggingLevel({ debug: true });
60
+ apimock = new MockAdapter(axios, { onNoMatch: 'throwException' });
61
+ // set access_token to mid to allow for autorouting of mock to correct resources
62
+ apimock.onPost(authResources.success.url).reply((config) => {
63
+ authResources.success.response.access_token = JSON.parse(config.data).account_id;
64
+ return [authResources.success.status, authResources.success.response];
65
+ });
66
+ apimock
67
+ .onPost(resourceFactory.soapUrl)
68
+ .reply((config) => resourceFactory.handleSOAPRequest(config));
69
+ apimock
70
+ .onAny(new RegExp(`^${escapeRegExp(resourceFactory.restUrl)}`))
71
+ .reply((config) => resourceFactory.handleRESTRequest(config));
72
+ fsmock({
73
+ '.prettierrc': fsmock.load(path.resolve(__dirname, '../boilerplate/files/.prettierrc')),
74
+ '.mcdevrc.json': fsmock.load(path.resolve(__dirname, 'mockRoot/.mcdevrc.json')),
75
+ '.mcdev-auth.json': fsmock.load(path.resolve(__dirname, 'mockRoot/.mcdev-auth.json')),
76
+ 'boilerplate/config.json': fsmock.load(
77
+ path.resolve(__dirname, '../boilerplate/config.json')
78
+ ),
79
+ deploy: fsmock.load(path.resolve(__dirname, 'mockRoot/deploy')),
80
+ test: fsmock.load(path.resolve(__dirname)),
81
+ });
82
+ };
83
+ /**
84
+ * resets mocks for API and FS
85
+ *
86
+ * @returns {void}
87
+ */
88
+ exports.mockReset = () => {
89
+ auth.clearSessions();
90
+ apimock.restore();
91
+ };
92
+ /**
93
+ * helper to return api history
94
+ *
95
+ * @returns {object} of API history
96
+ */
97
+ exports.getAPIHistory = () => apimock.history;
98
+
99
+ /**
100
+ * escapes string for regex
101
+ *
102
+ * @param {string} str to escape
103
+ * @returns {string} escaped string
104
+ */
105
+ function escapeRegExp(str) {
106
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
107
+ }
@@ -0,0 +1,301 @@
1
+ const SDK = require('sfmc-sdk');
2
+ /**
3
+ * @ignore
4
+ * @typedef {object} BuObject
5
+ * @property {string} clientId installed package client id
6
+ * @property {string} clientSecret installed package client secret
7
+ * @property {string} tenant subdomain part of Authentication Base Uri
8
+ * @property {string} [eid] Enterprise ID = MID of the parent BU
9
+ * @property {string} [mid] MID of the BU to work with
10
+ * @property {string} [businessUnit] name of the BU to interact with
11
+ * @property {string} [credential] name of the credential to interact with
12
+ */
13
+ /**
14
+ * @typedef {Object.<string, string>} TemplateMap
15
+ * @typedef {'accountUser'|'asset'|'attributeGroup'|'automation'|'campaign'|'contentArea'|'dataExtension'|'dataExtensionField'|'dataExtensionTemplate'|'dataExtract'|'dataExtractType'|'discovery'|'email'|'emailSendDefinition'|'eventDefinition'|'fileTransfer'|'filter'|'folder'|'ftpLocation'|'importFile'|'interaction'|'list'|'mobileCode'|'mobileKeyword'|'query'|'role'|'script'|'setDefinition'|'triggeredSendDefinition'} SupportedMetadataTypes
16
+ */
17
+
18
+ /**
19
+ * @typedef {Object.<string, any>} MetadataTypeItem
20
+ * @typedef {Object.<string, MetadataTypeItem>} MetadataTypeMap key=customer key
21
+ * @typedef {Object.<string, MetadataTypeMap>} MultiMetadataTypeMap key=Supported MetadataType
22
+ * @typedef {Object.<string, MetadataTypeItem[]>} MultiMetadataTypeList key=Supported MetadataType
23
+ * @typedef {{metadata:MetadataTypeMap,type:SupportedMetadataTypes}} MetadataTypeMapObj
24
+ * @typedef {{metadata:MetadataTypeItem,type:SupportedMetadataTypes}} MetadataTypeItemObj
25
+ * @typedef {Object.<number, MultiMetadataTypeMap>} Cache key=MID
26
+ */
27
+
28
+ /**
29
+ * @typedef {object} CodeExtractItem
30
+ * @property {MetadataTypeItem} json metadata of one item w/o code
31
+ * @property {CodeExtract[]} codeArr list of code snippets in this item
32
+ * @property {string[]} subFolder mostly set to null, otherwise list of subfolders
33
+ */
34
+ /**
35
+ * @typedef {object} CodeExtract
36
+ * @property {string[]} subFolder mostly set to null, otherwise subfolders path split into elements
37
+ * @property {string} fileName name of file w/o extension
38
+ * @property {string} fileExt file extension
39
+ * @property {string} content file content
40
+ * @property {'base64'} [encoding] optional for binary files
41
+ */
42
+ /**
43
+ * @typedef {object} QueryItem
44
+ * @property {string} name name
45
+ * @property {string} key key
46
+ * @property {string} description -
47
+ * @property {string} targetKey key of target data extension
48
+ * @property {string} createdDate e.g. "2020-09-14T01:42:03.017"
49
+ * @property {string} modifiedDate e.g. "2020-09-14T01:42:03.017"
50
+ * @property {'Overwrite'|'Update'|'Append'} targetUpdateTypeName defines how the query writes into the target data extension
51
+ * @property {0|1|2} [targetUpdateTypeId] mapped to targetUpdateTypeName via this.definition.targetUpdateTypeMapping
52
+ * @property {string} [targetId] Object ID of DE (removed before save)
53
+ * @property {string} [targetDescription] Description DE (removed before save)
54
+ * @property {boolean} isFrozen looks like this is always set to false
55
+ * @property {string} [queryText] contains SQL query with line breaks converted to '\n'. The content is extracted during retrieval and written into a separate *.sql file
56
+ * @property {string} [categoryId] holds folder ID, replaced with r__folder_Path during retrieve
57
+ * @property {string} r__folder_Path folder path in which this DE is saved
58
+ * @typedef {Object.<string, QueryItem>} QueryMap
59
+ * @typedef {object} CodeExtractItem
60
+ * @property {QueryItem} json metadata of one item w/o code
61
+ * @property {CodeExtract[]} codeArr list of code snippets in this item
62
+ * @property {string[]} subFolder mostly set to null, otherwise list of subfolders
63
+ */
64
+ /**
65
+ * @typedef {object} ScriptItem
66
+ * @property {string} name name
67
+ * @property {string} key key
68
+ * @property {string} description -
69
+ * @property {string} createdDate e.g. "2020-09-14T01:42:03.017"
70
+ * @property {string} modifiedDate e.g. "2020-09-14T01:42:03.017"
71
+ * @property {string} [script] contains script with line breaks converted to '\n'. The content is extracted during retrieval and written into a separate *.ssjs file
72
+ * @property {string} [categoryId] holds folder ID, replaced with r__folder_Path during retrieve
73
+ * @property {string} r__folder_Path folder path in which this DE is saved
74
+ * @typedef {Object.<string, ScriptItem>} ScriptMap
75
+ */
76
+ /**
77
+ * @typedef {Object.<string, any>} AssetItem
78
+ * @typedef {Object.<string, AssetItem>} AssetMap
79
+ * @typedef {'archive'|'asset'|'audio'|'block'|'code'|'document'|'image'|'message'|'other'|'rawimage'|'template'|'textfile'|'video'} AssetSubType
80
+ */
81
+ /**
82
+ * @typedef {object} DataExtensionFieldItem
83
+ * @property {string} [ObjectID] id
84
+ * @property {string} [CustomerKey] key in format [DEkey].[FieldName]
85
+ * @property {object} [DataExtension] -
86
+ * @property {string} DataExtension.CustomerKey key of DE
87
+ * @property {string} Name name of field
88
+ * @property {string} [Name_new] custom attribute that is only used when trying to rename a field from Name to Name_new
89
+ * @property {string} DefaultValue empty string for not set
90
+ * @property {true|false} IsRequired -
91
+ * @property {true|false} IsPrimaryKey -
92
+ * @property {string} Ordinal 1, 2, 3, ...
93
+ * @property {'Text'|'Number'|'Date'|'Boolean'|'Decimal'|'EmailAddress'|'Phone'|'Locale'} FieldType can only be set on create
94
+ * @property {string} Scale the number of places after the decimal that the field can hold; example: "0","1", ...
95
+ * @typedef {Object.<string, DataExtensionFieldItem>} DataExtensionFieldMap
96
+ */
97
+ /**
98
+ * @typedef {object} DataExtensionItem
99
+ * @property {string} CustomerKey key
100
+ * @property {string} Name name
101
+ * @property {string} Description -
102
+ * @property {string} [CreatedDate] iso format
103
+ * @property {string} [ModifiedDate] iso format
104
+ * @property {true|false} IsSendable -
105
+ * @property {true|false} IsTestable -
106
+ * @property {object} SendableDataExtensionField -
107
+ * @property {string} SendableDataExtensionField.Name -
108
+ * @property {object} SendableSubscriberField -
109
+ * @property {string} SendableSubscriberField.Name -
110
+ * @property {DataExtensionFieldItem[]} Fields list of DE fields
111
+ * @property {'dataextension'|'salesforcedataextension'|'synchronizeddataextension'|'shared_dataextension'|'shared_salesforcedataextension'} r__folder_ContentType retrieved from associated folder
112
+ * @property {string} r__folder_Path folder path in which this DE is saved
113
+ * @property {string} [CategoryID] holds folder ID, replaced with r__folder_Path during retrieve
114
+ * @property {string} [r__dataExtensionTemplate_Name] name of optionally associated DE template
115
+ * @property {object} [Template] -
116
+ * @property {string} [Template.CustomerKey] key of optionally associated DE teplate
117
+ * @typedef {Object.<string, DataExtensionItem>} DataExtensionMap
118
+ */
119
+ /**
120
+ * @typedef {object} AccountUserDocument
121
+ * @property {string} TYPE user.type__c
122
+ * @property {string} UserID user.UserID
123
+ * @property {string} AccountUserID user.AccountUserID
124
+ * @property {string} CustomerKey user.CustomerKey
125
+ * @property {string} Name user.Name
126
+ * @property {string} Email user.Email
127
+ * @property {string} NotificationEmailAddress user.NotificationEmailAddress
128
+ * @property {string} ActiveFlag user.ActiveFlag === true ? '✓' : '-'
129
+ * @property {string} IsAPIUser user.IsAPIUser === true ? '✓' : '-'
130
+ * @property {string} MustChangePassword user.MustChangePassword === true ? '✓' : '-'
131
+ * @property {string} DefaultBusinessUnit defaultBUName
132
+ * @property {string} AssociatedBusinessUnits__c associatedBus
133
+ * @property {string} Roles roles
134
+ * @property {string} UserPermissions userPermissions
135
+ * @property {string} LastSuccessfulLogin this.timeSinceDate(user.LastSuccessfulLogin)
136
+ * @property {string} CreatedDate user.CreatedDate
137
+ * @property {string} ModifiedDate user.ModifiedDate
138
+ */
139
+
140
+ /**
141
+ * @typedef {object} AutomationActivity
142
+ * @property {string} name name (not key) of activity
143
+ * @property {string} [objectTypeId] Id of assoicated activity type; see this.definition.activityTypeMapping
144
+ * @property {string} [activityObjectId] Object Id of assoicated metadata item
145
+ * @property {number} [displayOrder] order within step; starts with 1 or higher number
146
+ * @property {string} r__type see this.definition.activityTypeMapping
147
+ */
148
+ /**
149
+ * @typedef {object} AutomationStep
150
+ * @property {string} name description
151
+ * @property {string} [annotation] equals AutomationStep.name
152
+ * @property {number} [step] step iterator; starts with 1
153
+ * @property {number} [stepNumber] step iterator, automatically set during deployment
154
+ * @property {AutomationActivity[]} activities -
155
+ */
156
+ /**
157
+ * @typedef {object} AutomationSchedule REST format
158
+ * @property {number} typeId ?
159
+ * @property {string} startDate example: '2021-05-07T09:00:00'
160
+ * @property {string} endDate example: '2021-05-07T09:00:00'
161
+ * @property {string} icalRecur example: 'FREQ=DAILY;UNTIL=20790606T160000;INTERVAL=1'
162
+ * @property {string} timezoneName example: 'W. Europe Standard Time'; see this.definition.timeZoneMapping
163
+ * @property {number} [timezoneId] see this.definition.timeZoneMapping
164
+ */
165
+ /**
166
+ * @typedef {object} AutomationScheduleSoap SOAP format
167
+ * @property {object} Recurrence -
168
+ * @property {object} Recurrence.$ {'xsi:type': keyStem + 'lyRecurrence'}
169
+ * @property {'ByYear'} [Recurrence.YearlyRecurrencePatternType] * currently not supported by tool *
170
+ * @property {'ByMonth'} [Recurrence.MonthlyRecurrencePatternType] * currently not supported by tool *
171
+ * @property {'ByWeek'} [Recurrence.WeeklyRecurrencePatternType] * currently not supported by tool *
172
+ * @property {'ByDay'} [Recurrence.DailyRecurrencePatternType] -
173
+ * @property {'Interval'} [Recurrence.MinutelyRecurrencePatternType] -
174
+ * @property {'Interval'} [Recurrence.HourlyRecurrencePatternType] -
175
+ * @property {number} [Recurrence.YearInterval] 1..n * currently not supported by tool *
176
+ * @property {number} [Recurrence.MonthInterval] 1..n * currently not supported by tool *
177
+ * @property {number} [Recurrence.WeekInterval] 1..n * currently not supported by tool *
178
+ * @property {number} [Recurrence.DayInterval] 1..n
179
+ * @property {number} [Recurrence.HourInterval] 1..n
180
+ * @property {number} [Recurrence.MinuteInterval] 1..n
181
+ * @property {number} _interval internal variable for CLI output only
182
+ * @property {object} TimeZone -
183
+ * @property {number} TimeZone.ID AutomationSchedule.timezoneId
184
+ * @property {string} _timezoneString internal variable for CLI output only
185
+ * @property {string} StartDateTime AutomationSchedule.startDate
186
+ * @property {string} EndDateTime AutomationSchedule.endDate
187
+ * @property {string} _StartDateTime AutomationSchedule.startDate; internal variable for CLI output only
188
+ * @property {'EndOn'|'EndAfter'} RecurrenceRangeType set to 'EndOn' if AutomationSchedule.icalRecur contains 'UNTIL'; otherwise to 'EndAfter'
189
+ * @property {number} Occurrences only exists if RecurrenceRangeType=='EndAfter'
190
+ */
191
+ /**
192
+ * @typedef {object} AutomationItem
193
+ * @property {string} [id] Object Id
194
+ * @property {string} key key
195
+ * @property {string} name name
196
+ * @property {string} description -
197
+ * @property {'scheduled'|'triggered'} type Starting Source = Schedule / File Drop
198
+ * @property {'Scheduled'|'Running'|'Ready'|'Building'|'PausedSchedule'|'InactiveTrigger'} status -
199
+ * @property {AutomationSchedule} [schedule] only existing if type=scheduled
200
+ * @property {object} [fileTrigger] only existing if type=triggered
201
+ * @property {string} fileTrigger.fileNamingPattern file name with placeholders
202
+ * @property {number} fileTrigger.fileNamePatternTypeId -
203
+ * @property {string} fileTrigger.folderLocationText where to look for the fileNamingPattern
204
+ * @property {boolean} fileTrigger.isPublished ?
205
+ * @property {boolean} fileTrigger.queueFiles ?
206
+ * @property {boolean} fileTrigger.triggerActive -
207
+ * @property {object} [startSource] -
208
+ * @property {AutomationSchedule} [startSource.schedule] rewritten to AutomationItem.schedule
209
+ * @property {object} [startSource.fileDrop] rewritten to AutomationItem.fileTrigger
210
+ * @property {string} startSource.fileDrop.fileNamingPattern file name with placeholders
211
+ * @property {string} startSource.fileDrop.fileNamePatternTypeId -
212
+ * @property {string} startSource.fileDrop.folderLocation -
213
+ * @property {boolean} startSource.fileDrop.queueFiles -
214
+ * @property {number} startSource.typeId -
215
+ * @property {AutomationStep[]} steps -
216
+ * @property {string} r__folder_Path folder path
217
+ * @property {string} [categoryId] holds folder ID, replaced with r__folder_Path during retrieve
218
+ */
219
+ /**
220
+ * @typedef {Object.<string, AutomationItem>} AutomationMap
221
+ * @typedef {{metadata:AutomationMap,type:string}} AutomationMapObj
222
+ * @typedef {{metadata:AutomationItem,type:string}} AutomationItemObj
223
+ * @typedef {object} DeltaPkgItem
224
+ * @property {string} file relative path to file
225
+ * @property {number} changes changed lines
226
+ * @property {number} insertions added lines
227
+ * @property {number} deletions deleted lines
228
+ * @property {boolean} binary is a binary file
229
+ * @property {boolean} moved git thinks this file was moved
230
+ * @property {string} [fromPath] git thinks this relative path is where the file was before
231
+ * @property {SupportedMetadataTypes} type metadata type
232
+ * @property {string} externalKey key
233
+ * @property {string} name name
234
+ * @property {'move'|'add/update'|'delete'} gitAction what git recognized as an action
235
+ * @property {string} _credential mcdev credential name
236
+ * @property {string} _businessUnit mcdev business unit name inside of _credential
237
+ * @typedef {SDK} SDK
238
+ */
239
+
240
+ /**
241
+ * @typedef {object} skipInteraction signals what to insert automatically for things usually asked via wizard
242
+ * @property {string} client_id client id of installed package
243
+ * @property {string} client_secret client secret of installed package
244
+ * @property {string} auth_url tenant specific auth url of installed package
245
+ * @property {number} account_id MID of the Parent Business Unit
246
+ * @property {string} credentialName how you would like the credential to be named
247
+ * @property {string} gitRemoteUrl URL of Git remote server
248
+ */
249
+
250
+ /**
251
+ * @typedef {object} AuthObject
252
+ * @property {string} client_id client_id client_id for sfmc-sdk auth
253
+ * @property {string} client_secret client_secret for sfmc-sdk auth
254
+ * @property {number} account_id mid of business unit to auth against
255
+ * @property {string} auth_url authentication base url
256
+ */
257
+
258
+ /**
259
+ * @typedef {object} SoapRequestParams
260
+ * @property {string} [continueRequest] request id
261
+ * @property {object} [options] additional options (CallsInConversation, Client, ConversationID, Priority, RequestType, SaveOptions, ScheduledTime, SendResponseTo, SequenceCode)
262
+ * @property {*} clientIDs ?
263
+ * @property {SoapFilter} [filter] simple or complex
264
+ complex
265
+ * @property {boolean} [QueryAllAccounts] all BUs or just one
266
+ * @typedef {object} SoapFilter
267
+ * @property {string|SoapFilter} leftOperand string for simple or a new filter-object for complex
268
+ * @property {'AND'|'OR'|'equals'|'notEquals'|'isNull'|'isNotNull'|'greaterThan'|'lessThan'|'greaterThanOrEqual'|'lessThanOrEqual'|'between'|'IN'|'like'} operator various options
269
+ * @property {string|number|boolean|Array|SoapFilter} [rightOperand] string for simple or a new filter-object for complex; omit for isNull and isNotNull
270
+ */
271
+
272
+ /**
273
+ * @typedef {object} Mcdevrc
274
+ * @property {object} credentials list of credentials
275
+ * @property {object} options configure options for mcdev
276
+ * @property {object} directories configure directories for mcdev to read/write to
277
+ * @property {string} directories.businessUnits "businessUnits/"
278
+ * @property {string} directories.deploy "deploy/"
279
+ * @property {string} directories.docs "docs/"
280
+ * @property {string} directories.retrieve "retrieve/"
281
+ * @property {string} directories.template "template/"
282
+ * @property {string} directories.templateBuilds ["retrieve/", "deploy/"]
283
+ * @property {Object.<string, object>} markets templating variables grouped by markets
284
+ * @property {object} marketList combination of markets and BUs for streamlined deployments
285
+ * @property {object} metaDataTypes templating variables grouped by markets
286
+ * @property {string[]} metaDataTypes.retrieve define what types shall be downloaded by default during retrieve
287
+ * @property {string[]} metaDataTypes.documentOnRetrieve which types should be parsed & documented after retrieve
288
+ * @property {string} version mcdev version that last updated the config file
289
+ */
290
+
291
+ /**
292
+ * @typedef {object} Logger
293
+ * @property {Function} info (msg) print info message
294
+ * @property {Function} warn (msg) print warning message
295
+ * @property {Function} verbose (msg) additional messages that are not important
296
+ * @property {Function} debug (msg) print debug message
297
+ * @property {Function} error (msg) print error message
298
+ * @property {Function} errorStack (ex, msg) print error with trace message
299
+ */
300
+
301
+ module.exports = {};
package/CHANGELOG.md DELETED
@@ -1,126 +0,0 @@
1
- # Changelog
2
-
3
- Accenture SFMC DevTools follows [semantic versioning](https://semver.org/).
4
-
5
- ---
6
-
7
- ## [3.1.1](https://github.com/Accenture/sfmc-devtools/compare/v3.1.0...v3.1.1) - 2022-01-10
8
-
9
- **Bugfixes:**
10
-
11
- - [#160](https://github.com/Accenture/sfmc-devtools/issues/160) mcdev outputs bogus text since dependency colorjs got corrupted ( [background story](https://www.theverge.com/2022/1/9/22874949/developer-corrupts-open-source-libraries-projects-affected))
12
-
13
- **Chores:**
14
-
15
- - bumped cli-progress to 3.10.0 (removes colors dependency)
16
- - bumped winston to 3.3.4 (removes colors dependency)
17
-
18
- ---
19
-
20
- ## [3.1.0](https://github.com/Accenture/sfmc-devtools/compare/v3.0.3...v3.1.0) - 2021-12-27
21
-
22
- **Features:**
23
-
24
- - [#55](https://github.com/Accenture/sfmc-devtools/issues/55) added user / roles documentation
25
- - [#64](https://github.com/Accenture/sfmc-devtools/issues/64) Added `accountUser` (system users) support (retrieve)
26
- - [#103](https://github.com/Accenture/sfmc-devtools/issues/103) Add rename `dataExtensionField` option (via Name_new)
27
- - [#130](https://github.com/Accenture/sfmc-devtools/issues/130) offer `retrieveChangelog` option to other node packages including mcdev (see [retrieveChangelog.js](/lib/retrieveChangelog.js) for a how-to)
28
- - [#133](https://github.com/Accenture/sfmc-devtools/issues/133) `dataExtensionField` validation during DE update (see [README](README.md#722-addingupdating-fields-on-existing-data-extensions) for details)
29
- - [#136](https://github.com/Accenture/sfmc-devtools/issues/136) enable including mcdev in other node packages (see [README](README.md#26-using-mcdev-in-other-node-packages) for a how-to)
30
- - [#144](https://github.com/Accenture/sfmc-devtools/issues/144) added file type .ai to `asset` - thanks to @fbellgr
31
-
32
- **Bugfixes:**
33
-
34
- - [#112](https://github.com/Accenture/sfmc-devtools/issues/112) add (unknown) new type 783 to defintion of `importFile`
35
- - [#117](https://github.com/Accenture/sfmc-devtools/issues/117) `queries` not deployable when target is `shared DE`
36
- - [#118](https://github.com/Accenture/sfmc-devtools/issues/118) `automation` start not auto-retried during deploy
37
- - [#119](https://github.com/Accenture/sfmc-devtools/issues/119) fixed `list` dependency for importFile
38
- - [#122](https://github.com/Accenture/sfmc-devtools/issues/122) ECONNRESET on caching metadata during deploy
39
- - [#128](https://github.com/Accenture/sfmc-devtools/issues/128) `dataExtension` json not equal for retrieve/deploy
40
- - [#129](https://github.com/Accenture/sfmc-devtools/issues/129) `script` json not equal for retrieve/deploy
41
- - [#140](https://github.com/Accenture/sfmc-devtools/issues/140) avoid issues when retrieving `dataExtensions` that do not have a folder ID (edge case) - thanks to @fbellgr
42
- - [#144](https://github.com/Accenture/sfmc-devtools/issues/144) improved handling high volumes of `asset` - thanks to @fbellgr
43
- - [#149](https://github.com/Accenture/sfmc-devtools/issues/149) handle errors on upsert of data extensions gracefully
44
-
45
- **Chores:**
46
-
47
- - [#5](https://github.com/Accenture/sfmc-devtools/issues/5) removed postinstall msg after npm 7 dropped support for that
48
- - [#127](https://github.com/Accenture/sfmc-devtools/issues/127) bad message "info: updated automation: undefined"
49
- - [#132](https://github.com/Accenture/sfmc-devtools/issues/132) `dataExtension.SendableSubscriberField.Name` now has a slightly more readable value
50
- - [#137](https://github.com/Accenture/sfmc-devtools/issues/137) docs for installing a specific version were incorrect
51
- - [#138](https://github.com/Accenture/sfmc-devtools/issues/138) make issues and pull requests clickable in gitfork
52
- - change `mcdev document` to take the cred/BU first and then the type to align it with other commands
53
- - improved error handling of `document role` command
54
- - bumped cli-progress to 3.9.1
55
- - bumped eslint to 8.4.1
56
- - bumped eslint-plugin-mocha to 10.0.1
57
- - bumped eslint-plugin-prettier to 4.0.0
58
- - bumped fs-extra to 10.0.0
59
- - bumped husky to 7.0.4
60
- - bumped inquirer to 8.2.0
61
- - bumped jsdoc-to-markdown to 7.1.0
62
- - bumped lint-staged to 12.1.2
63
- - bumped mocha to 9.1.3
64
- - bumped mustache to 4.2.0
65
- - bumped prettier to 2.5.1
66
- - bumped semver to 7.3.5
67
- - bumped simple-git to 2.48.0
68
- - bumped yargs to 17.3.0
69
- - [#146](https://github.com/Accenture/sfmc-devtools/issues/146) remove AccountUser retrieve as a default retrieve option
70
-
71
- ---
72
-
73
- ## [3.0.3](https://github.com/Accenture/sfmc-devtools/compare/v3.0.2...v3.0.3) - 2021-08-11
74
-
75
- **Bugfixes:**
76
-
77
- - [#100](https://github.com/Accenture/sfmc-devtools/issues/100) Handle ECONNRESET errors across various types (incl. Data Extensions)
78
- - [#102](https://github.com/Accenture/sfmc-devtools/issues/102) block deployment attempt for synchronized Data Extensions with proper error message
79
- - [#104](https://github.com/Accenture/sfmc-devtools/issues/104) block deployment of shared data extensions on child BUs (existing solution broke somewhere down the line)
80
-
81
- **Chores:**
82
-
83
- - [#107](https://github.com/Accenture/sfmc-devtools/issues/107) rewrite folder to use generic update/create to help with ECONNRESET issue
84
- - [#108](https://github.com/Accenture/sfmc-devtools/issues/108) return full API error messages for create & update via SOAP
85
- - [#110](https://github.com/Accenture/sfmc-devtools/issues/110) improve error message for missing dependencies
86
- - bumped jsdoc-to-markdown to 7.0.1
87
- - bumped eslint-plugin-mocha to 9.0.0
88
- - bumped eslint-plugin-prettier to 3.4.0
89
- - bumped eslint-config-prettier to 8.3.0
90
- - bumped eslint to 7.32.0
91
- - enhanced Pull Request Template with note on `npm run docs`
92
-
93
- ---
94
-
95
- ## [3.0.2](https://github.com/Accenture/sfmc-devtools/compare/v3.0.1...v3.0.2) - 2021-08-03
96
-
97
- **Bugfixes:**
98
-
99
- - [#26](https://github.com/Accenture/sfmc-devtools/issues/26) retrieving asset subtypes via r ... asset-xyz actually saves result to disk
100
- - [#45](https://github.com/Accenture/sfmc-devtools/issues/45) connection errors for automations fixed
101
- - [#46](https://github.com/Accenture/sfmc-devtools/issues/46) (temp fix) campaigns break entire retrieve - disabled for now
102
- - [#48](https://github.com/Accenture/sfmc-devtools/issues/48) connection errors for dataExtensions and other types are now handled gracefully
103
- - [#49](https://github.com/Accenture/sfmc-devtools/issues/49) connection errors for asset subtypes no longer restart downloading all subtypes
104
- - [#51](https://github.com/Accenture/sfmc-devtools/issues/51) retrieving asset subtypes now always uses the default list of subtypes
105
- - [#52](https://github.com/Accenture/sfmc-devtools/issues/52) no more endless retries in case of connection errors
106
-
107
- ---
108
-
109
- ## [3.0.1](https://github.com/Accenture/sfmc-devtools/compare/v3.0.0...v3.0.1) - 2021-04-11
110
-
111
- **Bugfixes:**
112
-
113
- - fix [#4](https://github.com/Accenture/sfmc-devtools/issues/4): retrieveAsTemplate led to fatal error if target metadata was not found
114
- - migration from prior internal version was not handled gracefully before
115
-
116
- ---
117
-
118
- ## 3.0.0 - 2021-03-26
119
-
120
- Initial public release.
121
-
122
- ---
123
-
124
- ## 2.0.0 - 2020-02-03
125
-
126
- Initial Accenture-wide release.
@@ -1,19 +0,0 @@
1
- # PR details
2
-
3
- ## What is the purpose of this pull request? (put an "X" next to an item)
4
-
5
- - [ ] Documentation update
6
- - [ ] Bug fix
7
- - [ ] New metadata support
8
- - [ ] Enhanced metadata
9
- - [ ] Add a CLI option
10
- - [ ] Add something to the core
11
- - [ ] Other, please explain:
12
-
13
- ## What changes did you make? (Give an overview)
14
-
15
- ...
16
-
17
- ## Is there anything you'd like reviewers to focus on?
18
-
19
- ...
package/test/util/file.js DELETED
@@ -1,51 +0,0 @@
1
- const assert = require('chai').assert;
2
- const File = require('../../lib/util/file');
3
- const fs = require('fs-extra');
4
- const path = require('path');
5
-
6
- const dataDir = 'test_tmp/file/';
7
-
8
- describe('File', () => {
9
- after(() => {
10
- fs.removeSync(dataDir);
11
- });
12
- describe('#writeJSONToFile()', () => {
13
- it('should create json file and directory', async () => {
14
- assert.strictEqual(fs.existsSync(dataDir + 'test1.json'), false);
15
- const jsonContent = {
16
- string: 'abc',
17
- boolean: true,
18
- number: 5,
19
- array: ['asd', 4, 'asdf'],
20
- obj: {
21
- name: 'object',
22
- },
23
- };
24
- await File.writeJSONToFile(dataDir, 'test1', jsonContent);
25
- assert.deepEqual(fs.readJSONSync(dataDir + 'test1.json'), jsonContent);
26
- });
27
- });
28
- describe('#copyFile()', () => {
29
- it('should copy file from one path to another', async () => {
30
- const source = path.join(dataDir, 'sourceFile.txt');
31
- const target = path.join(dataDir, 'targetFile.txt');
32
- fs.writeFileSync(source, 'filecontent');
33
- assert.strictEqual(fs.existsSync(source), true);
34
- await File.copyFile(source, target);
35
- assert.strictEqual(fs.existsSync(target), true);
36
- assert.deepEqual(fs.readFileSync(source), fs.readFileSync(target));
37
- });
38
- it("should skip copy if source file doesn't exist", async () => {
39
- const source = path.join(dataDir, 'doesnt_exist_source.txt');
40
- const target = path.join(dataDir, 'doesnt_exist_target.txt');
41
- assert.strictEqual(fs.existsSync(source), false);
42
- const result = await File.copyFile(source, target);
43
- assert.strictEqual(fs.existsSync(target), false);
44
- assert.deepEqual(result, {
45
- status: 'skipped',
46
- statusMessage: 'deleted from repository',
47
- file: source,
48
- });
49
- });
50
- });
51
- });