mcdev 8.4.0 → 9.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/.github/ISSUE_TEMPLATE/bug.yml +2 -0
- package/.github/workflows/code-test.yml +3 -2
- package/.husky/commit-msg +1 -1
- package/.husky/post-checkout +4 -6
- package/.prettierrc +1 -1
- package/@types/lib/Deployer.d.ts.map +1 -1
- package/@types/lib/index.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Asset.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Automation.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataExtension.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Event.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Folder.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
- package/@types/lib/metadataTypes/List.d.ts +1 -1
- package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
- package/@types/lib/util/auth.d.ts.map +1 -1
- package/@types/lib/util/cli.d.ts.map +1 -1
- package/@types/lib/util/file.d.ts.map +1 -1
- package/@types/lib/util/init.config.d.ts.map +1 -1
- package/@types/lib/util/init.d.ts +1 -1
- package/@types/lib/util/init.d.ts.map +1 -1
- package/@types/lib/util/init.git.d.ts.map +1 -1
- package/@types/lib/util/util.d.ts +1 -0
- package/@types/lib/util/util.d.ts.map +1 -1
- package/lib/Deployer.js +5 -4
- package/lib/index.js +14 -14
- package/lib/metadataTypes/Asset.js +15 -9
- package/lib/metadataTypes/Automation.js +8 -10
- package/lib/metadataTypes/DataExtension.js +4 -3
- package/lib/metadataTypes/DataExtensionField.js +3 -3
- package/lib/metadataTypes/Event.js +6 -5
- package/lib/metadataTypes/Folder.js +28 -14
- package/lib/metadataTypes/Journey.js +2 -2
- package/lib/metadataTypes/List.js +1 -1
- package/lib/metadataTypes/MetadataType.js +17 -21
- package/lib/metadataTypes/User.js +2 -2
- package/lib/metadataTypes/definitions/Folder.definition.js +1 -1
- package/lib/util/auth.js +20 -24
- package/lib/util/businessUnit.js +1 -1
- package/lib/util/cli.js +2 -1
- package/lib/util/file.js +2 -1
- package/lib/util/init.config.js +3 -1
- package/lib/util/init.git.js +2 -1
- package/lib/util/init.js +2 -1
- package/lib/util/util.js +5 -3
- package/package.json +19 -19
- package/test/mockRoot/.mcdevrc.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/test_slash.asset-block-meta.html +12 -0
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/test_slash.asset-block-meta.json +29 -0
- package/test/resourceFactory.js +1 -1
- package/test/resources/9999999/asset/v1/content/assets/16992/get-response.json +60 -0
- package/test/resources/9999999/asset/v1/content/assets/post-response-key=test_slash.json +60 -0
- package/test/resources/9999999/asset/v1/content/assets/query/+post-response-assetType.idIN3,195,196,197,198,199,200,201,202,203,210,211,212,213-slashfolder.json +198 -0
- package/test/resources/9999999/asset/v1/content/categories/post-response.json +9 -0
- package/test/resources/9999999/asset-slashfolder-deploy/block/test_slash.asset-block-meta.html +12 -0
- package/test/resources/9999999/asset-slashfolder-deploy/block/test_slash.asset-block-meta.json +29 -0
- package/test/resources/9999999/dataFolder/+retrieve-ContentTypeINasset,asset-shared,cloudpages-slashfolder-response.xml +136 -0
- package/test/resources/9999999/dataFolder/create-ContentType=asset,Name=testFolder_samePath,ParentFolderID=89397-response.xml +33 -0
- package/test/resources/9999999/dataFolder/create-response.xml +33 -0
- package/test/resources/9999999/dataFolder/retrieve-samePathOtherBU-response.xml +564 -0
- package/test/resources/9999999/folder-deploy-samepath/Content Builder/testFolder_samePath.folder-meta.json +9 -0
- package/test/resources/9999999/folder-deploy-slash/Content Builder/Headers%2FFolders.folder-meta.json +9 -0
- package/test/type.folder.test.js +157 -0
- package/tsconfig.json +1 -1
- package/tsconfig.npmScripts.json +1 -1
- package/tsconfig.precommit.json +1 -1
package/test/type.folder.test.js
CHANGED
|
@@ -6,6 +6,7 @@ import chaiFiles from 'chai-files';
|
|
|
6
6
|
import cache from '../lib/util/cache.js';
|
|
7
7
|
import * as testUtils from './utils.js';
|
|
8
8
|
import handler from '../lib/index.js';
|
|
9
|
+
import { Util } from '../lib/util/util.js';
|
|
9
10
|
chai.use(chaiFiles);
|
|
10
11
|
|
|
11
12
|
describe('type: folder', () => {
|
|
@@ -17,6 +18,38 @@ describe('type: folder', () => {
|
|
|
17
18
|
testUtils.mockReset();
|
|
18
19
|
});
|
|
19
20
|
|
|
21
|
+
describe('Retrieve ================', () => {
|
|
22
|
+
it('Should retrieve an asset whose folder name contains a slash and escape the slash in r__folder_Path', async () => {
|
|
23
|
+
// GIVEN the SFMC folder "bla/blub" (child of Content Builder) and an asset in that folder
|
|
24
|
+
await testUtils.copyFile(
|
|
25
|
+
'dataFolder/+retrieve-ContentTypeINasset,asset-shared,cloudpages-slashfolder-response.xml',
|
|
26
|
+
'dataFolder/retrieve-ContentTypeINasset,asset-shared,cloudpages-response.xml'
|
|
27
|
+
);
|
|
28
|
+
await testUtils.copyFile(
|
|
29
|
+
'asset/v1/content/assets/query/+post-response-assetType.idIN3,195,196,197,198,199,200,201,202,203,210,211,212,213-slashfolder.json',
|
|
30
|
+
'asset/v1/content/assets/query/post-response-assetType.idIN3,195,196,197,198,199,200,201,202,203,210,211,212,213.json'
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const retrieve = await handler.retrieve('testInstance/testBU', ['asset-block']);
|
|
34
|
+
// THEN
|
|
35
|
+
assert.equal(process.exitCode, 0, 'retrieve should not have thrown an error');
|
|
36
|
+
assert.equal(
|
|
37
|
+
retrieve['testInstance/testBU'].asset
|
|
38
|
+
? Object.keys(retrieve['testInstance/testBU'].asset).length
|
|
39
|
+
: 0,
|
|
40
|
+
5,
|
|
41
|
+
'five assets expected in retrieve response (4 existing + 1 new test_slash)'
|
|
42
|
+
);
|
|
43
|
+
// Verify the retrieved asset has the escape char (∕) in r__folder_Path, not a real slash
|
|
44
|
+
assert.equal(
|
|
45
|
+
retrieve['testInstance/testBU'].asset?.test_slash?.r__folder_Path,
|
|
46
|
+
'Content Builder/bla' + Util.folderNameSlashEscapeChar + 'blub',
|
|
47
|
+
'r__folder_Path should use ∕ (U+2215) to escape the slash in the folder name'
|
|
48
|
+
);
|
|
49
|
+
return;
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
20
53
|
describe('Deploy ================', () => {
|
|
21
54
|
it('Should create automation & dataExtension folders', async () => {
|
|
22
55
|
// prepare
|
|
@@ -103,5 +136,129 @@ describe('type: folder', () => {
|
|
|
103
136
|
);
|
|
104
137
|
return;
|
|
105
138
|
});
|
|
139
|
+
|
|
140
|
+
it('Should create folder when same path exists in another Business Unit', async () => {
|
|
141
|
+
// prepare
|
|
142
|
+
// Use folder deploy data with an asset folder path
|
|
143
|
+
testUtils.copyToDeploy('folder-deploy-samepath', 'folder');
|
|
144
|
+
// Use a modified retrieve response that includes 'Content Builder/testFolder_samePath'
|
|
145
|
+
// from a different BU (Client.ID=1111111). ContentType 'asset' is in folderTypesFromParent
|
|
146
|
+
// so it will be cached even though it belongs to another BU - simulating the bug scenario
|
|
147
|
+
await testUtils.copyFile(
|
|
148
|
+
'dataFolder/retrieve-samePathOtherBU-response.xml',
|
|
149
|
+
'dataFolder/retrieve-response.xml'
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const deployed = await handler.deploy('testInstance/testBU', ['folder']);
|
|
153
|
+
// THEN
|
|
154
|
+
assert.equal(process.exitCode, 0, 'deploy should not have thrown an error');
|
|
155
|
+
|
|
156
|
+
// check what was deployed - 'Content Builder/testFolder_samePath' should be created
|
|
157
|
+
// even though it exists in another BU (1111111)
|
|
158
|
+
const deployedFolderPaths = deployed['testInstance/testBU']?.folder
|
|
159
|
+
? Object.values(deployed['testInstance/testBU']?.folder).map((f) => f.Path)
|
|
160
|
+
: [];
|
|
161
|
+
assert.include(
|
|
162
|
+
deployedFolderPaths,
|
|
163
|
+
'Content Builder/testFolder_samePath',
|
|
164
|
+
"'Content Builder/testFolder_samePath' should have been created in current BU, not skipped because it exists in another BU"
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const createRestCallouts = testUtils.getRestCallout(
|
|
168
|
+
'post',
|
|
169
|
+
'/asset/v1/content/categories',
|
|
170
|
+
true
|
|
171
|
+
);
|
|
172
|
+
// 'Content Builder/testFolder_samePath' must be created in current BU via REST
|
|
173
|
+
// (not skipped due to same path in other BU)
|
|
174
|
+
assert.ok(
|
|
175
|
+
createRestCallouts?.some(
|
|
176
|
+
(c) => c.name === 'testFolder_samePath' && c.parentId === 89397
|
|
177
|
+
),
|
|
178
|
+
"'Content Builder/testFolder_samePath' folder creation callout not found - folder was incorrectly skipped"
|
|
179
|
+
);
|
|
180
|
+
return;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('Should create a folder whose name contains a slash character (direct folder deploy)', async () => {
|
|
184
|
+
// GIVEN a folder deploy file named Headers%2FFolders.folder-meta.json with Name "Headers/Folders"
|
|
185
|
+
// (the % encoding represents the actual '/' in the SFMC folder name)
|
|
186
|
+
testUtils.copyToDeploy('folder-deploy-slash', 'folder');
|
|
187
|
+
|
|
188
|
+
const deployed = await handler.deploy('testInstance/testBU', ['folder']);
|
|
189
|
+
// THEN
|
|
190
|
+
assert.equal(process.exitCode, 0, 'deploy should not have thrown an error');
|
|
191
|
+
|
|
192
|
+
// Verify the deployed path uses the escape char (∕) not the real slash
|
|
193
|
+
const deployedFolderPaths = deployed['testInstance/testBU']?.folder
|
|
194
|
+
? Object.values(deployed['testInstance/testBU']?.folder).map((f) => f.Path)
|
|
195
|
+
: [];
|
|
196
|
+
assert.include(
|
|
197
|
+
deployedFolderPaths,
|
|
198
|
+
'Content Builder/Headers' + Util.folderNameSlashEscapeChar + 'Folders',
|
|
199
|
+
'deployed folder path should use escape char for the slash in folder name'
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// Verify that the REST Create callout uses the REAL slash character in the name field
|
|
203
|
+
// (not the escape character), so that SFMC creates a folder named "Headers/Folders"
|
|
204
|
+
const createRestCallouts = testUtils.getRestCallout(
|
|
205
|
+
'post',
|
|
206
|
+
'/asset/v1/content/categories',
|
|
207
|
+
true
|
|
208
|
+
);
|
|
209
|
+
assert.ok(
|
|
210
|
+
createRestCallouts?.some(
|
|
211
|
+
(c) => c.name === 'Headers/Folders' && c.parentId === 89397
|
|
212
|
+
),
|
|
213
|
+
"REST create for 'Headers/Folders' should use the real slash in name, not the escape char"
|
|
214
|
+
);
|
|
215
|
+
// Verify the escape char was NOT sent as the folder name
|
|
216
|
+
assert.ok(
|
|
217
|
+
!createRestCallouts?.some(
|
|
218
|
+
(c) => c.name === 'Headers' + Util.folderNameSlashEscapeChar + 'Folders'
|
|
219
|
+
),
|
|
220
|
+
'REST create should NOT use the escape char in the name field'
|
|
221
|
+
);
|
|
222
|
+
return;
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('Should create a folder whose name contains a slash when triggered via r__folder_Path from an asset', async () => {
|
|
226
|
+
// GIVEN an asset deploy with r__folder_Path pointing to a subfolder whose name contains a slash
|
|
227
|
+
// The escape char (∕) in r__folder_Path separates the slash-in-name from path separators
|
|
228
|
+
testUtils.copyToDeploy('asset-slashfolder-deploy', 'asset');
|
|
229
|
+
|
|
230
|
+
const deployed = await handler.deploy('testInstance/testBU', ['asset']);
|
|
231
|
+
// THEN
|
|
232
|
+
assert.equal(process.exitCode, 0, 'deploy should not have thrown an error');
|
|
233
|
+
|
|
234
|
+
// Verify the asset was deployed
|
|
235
|
+
assert.equal(
|
|
236
|
+
deployed['testInstance/testBU']?.asset
|
|
237
|
+
? Object.keys(deployed['testInstance/testBU']?.asset).length
|
|
238
|
+
: 0,
|
|
239
|
+
1,
|
|
240
|
+
'one asset should have been deployed'
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// Verify the auto-generated folder was created via REST with the REAL slash in the name field
|
|
244
|
+
// (not the escape char), so SFMC creates a folder named "bla/blub"
|
|
245
|
+
const createRestCallouts = testUtils.getRestCallout(
|
|
246
|
+
'post',
|
|
247
|
+
'/asset/v1/content/categories',
|
|
248
|
+
true
|
|
249
|
+
);
|
|
250
|
+
assert.ok(
|
|
251
|
+
createRestCallouts?.some((c) => c.name === 'bla/blub' && c.parentId === 89397),
|
|
252
|
+
"REST create for 'Content Builder/bla∕blub' should send name 'bla/blub' with real slash"
|
|
253
|
+
);
|
|
254
|
+
// Verify the escape char was NOT sent as the folder name
|
|
255
|
+
assert.ok(
|
|
256
|
+
!createRestCallouts?.some(
|
|
257
|
+
(c) => c.name === 'bla' + Util.folderNameSlashEscapeChar + 'blub'
|
|
258
|
+
),
|
|
259
|
+
'REST create should NOT use the escape char in the name field'
|
|
260
|
+
);
|
|
261
|
+
return;
|
|
262
|
+
});
|
|
106
263
|
});
|
|
107
264
|
});
|
package/tsconfig.json
CHANGED
package/tsconfig.npmScripts.json
CHANGED