Skip to content

Commit a1b8b17

Browse files
Merge pull request #2552 from Accenture/copilot/fix-shared-de-warning
fix/1834 build does not find shared DEs when run on child BU
2 parents 9d8ee7e + a3fd702 commit a1b8b17

11 files changed

Lines changed: 232 additions & 12 deletions

File tree

@types/lib/metadataTypes/DataExtension.d.ts

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

@types/lib/metadataTypes/DataExtension.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

@types/lib/metadataTypes/MetadataType.d.ts

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

@types/lib/metadataTypes/MetadataType.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,12 +1004,12 @@ class Mcdev {
10041004
`Found ${additionalAssetDependencies.length - initialAssetNumber} additional assets linked via ContentBlockByX.`
10051005
);
10061006
}
1007-
// reset cache in case this is used progammatically somehow
1008-
Asset.getJsonFromFSCache = null;
10091007

10101008
// remove duplicates in main object after adding dependencies
10111009
typeKeyList[depType] = [...new Set(typeKeyList[depType])];
10121010
}
1011+
// reset cache regardless of whether assets were found, to avoid stale data in programmatic use
1012+
MetadataTypeInfo['asset'].getJsonFromFSCache = null;
10131013

10141014
return typeKeyList;
10151015
}

lib/metadataTypes/DataExtension.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { checkbox } from '@inquirer/prompts';
1919
* @typedef {import('../../types/mcdev.d.js').MetadataTypeMap} MetadataTypeMap
2020
* @typedef {import('../../types/mcdev.d.js').SoapRequestParams} SoapRequestParams
2121
* @typedef {import('../../types/mcdev.d.js').TemplateMap} TemplateMap
22+
* @typedef {import('../../types/mcdev.d.js').TypeKeyCombo} TypeKeyCombo
2223
*/
2324

2425
/**
@@ -1664,6 +1665,63 @@ class DataExtension extends MetadataType {
16641665
return super.getFilesToCommit(keyArr);
16651666
}
16661667
}
1668+
/**
1669+
* Hook called when dependency keys were not found in the child BU retrieve folder.
1670+
* Checks the `_ParentBU_` folder for shared or synchronized dataExtensions and emits
1671+
* readable warnings. Does NOT add the found items to the deployment package.
1672+
* Only active when running on a child BU (eid !== mid).
1673+
* Used by {@link MetadataType.getDependentFiles}.
1674+
*
1675+
* @param {string[]} notFound keys that were not found in the child BU retrieve folder
1676+
* @returns {Promise.<string[]>} keys that should still trigger the default "not found" warning
1677+
*/
1678+
static async handleNotFoundDependencies(notFound) {
1679+
// on parent BU, shared DE check is not applicable
1680+
if (this.buObject.eid === this.buObject.mid) {
1681+
return notFound;
1682+
}
1683+
const parentBUPath = File.normalizePath([
1684+
this.properties.directories.retrieve,
1685+
this.buObject.credential,
1686+
Util.parentBuName,
1687+
this.definition.type,
1688+
]);
1689+
const stillNotFound = [];
1690+
for (const key of notFound) {
1691+
const filePath = File.normalizePath([
1692+
parentBUPath,
1693+
File.filterIllegalFilenames(key) + '.' + this.definition.type + '-meta.json',
1694+
]);
1695+
let metadataItem;
1696+
try {
1697+
metadataItem = await File.readJson(filePath);
1698+
} catch {
1699+
stillNotFound.push(key);
1700+
continue;
1701+
}
1702+
const contentType = metadataItem.r__folder_ContentType;
1703+
if (contentType === 'shared_dataextension') {
1704+
Util.logger.warn(
1705+
`dataExtension '${key}' is a shared dataExtension stored in _ParentBU_. It cannot be included in the child BU deployment package.`
1706+
);
1707+
Util.logger.warn(
1708+
`References to it may need to be changed during deployment via mcdev templating or manually. To update the shared dataExtension itself, run build for the parent BU and deploy it separately.`
1709+
);
1710+
} else if (contentType === 'synchronizeddataextension') {
1711+
Util.logger.warn(
1712+
`dataExtension '${key}' is a synchronized dataExtension stored in _ParentBU_. It cannot be included in the child BU deployment package.`
1713+
);
1714+
Util.logger.warn(
1715+
`The reference to it likely needs to be changed during deployment via mcdev templating or manually.`
1716+
);
1717+
} else {
1718+
// regular dataExtension found on parent BU cannot be used from a child BU; treat as not found
1719+
stillNotFound.push(key);
1720+
}
1721+
}
1722+
return stillNotFound;
1723+
}
1724+
16671725
/**
16681726
* helper for {@link MetadataType.createOrUpdate}
16691727
*

lib/metadataTypes/MetadataType.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2785,14 +2785,17 @@ class MetadataType {
27852785
(key) => !multiTypeKeyList[this.definition.type].includes(key)
27862786
);
27872787
if (notFound && notFound.length) {
2788-
Util.logger.warn(
2789-
Util.getGrayMsg(
2790-
` ☇ skipping ${this.definition.type} dependenc${notFound.length === 1 ? 'y' : 'ies'} ${notFound.join(', ')}: Not found on your in your project folder.`
2791-
)
2792-
);
2793-
// make sure we don't search for it twice
2794-
notFoundList[this.definition.type] ||= [];
2795-
notFoundList[this.definition.type].push(...notFound);
2788+
const remainingNotFound = await this.handleNotFoundDependencies(notFound);
2789+
if (remainingNotFound.length) {
2790+
Util.logger.warn(
2791+
Util.getGrayMsg(
2792+
` ☇ skipping ${this.definition.type} dependenc${remainingNotFound.length === 1 ? 'y' : 'ies'} ${remainingNotFound.join(', ')}: Not found on your in your project folder.`
2793+
)
2794+
);
2795+
// make sure we don't search for it twice
2796+
notFoundList[this.definition.type] ||= [];
2797+
notFoundList[this.definition.type].push(...remainingNotFound);
2798+
}
27962799
}
27972800
return multiTypeKeyList;
27982801
}
@@ -2805,6 +2808,19 @@ class MetadataType {
28052808
*/
28062809
static getDependentFilesExtra(metadataItem, dependentTypeKeyCombo) {}
28072810

2811+
/**
2812+
* Hook called when dependency keys were not found in the primary retrieve folder.
2813+
* Override in subtypes to show type-specific warnings (e.g. shared/synchronized dataExtensions).
2814+
* Keys returned by this method still receive the generic "not found" warning.
2815+
* Used by {@link MetadataType.getDependentFiles}.
2816+
*
2817+
* @param {string[]} notFound keys that could not be found in the retrieve folder
2818+
* @returns {Promise.<string[]>} keys that should still trigger the default "not found" warning
2819+
*/
2820+
static async handleNotFoundDependencies(notFound) {
2821+
return notFound;
2822+
}
2823+
28082824
/**
28092825
* helper for {@link MetadataType.getDependentFiles}
28102826
*
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"CustomerKey": "{{{prefix}}}dataExtensionShared",
3+
"DataRetentionPeriodLength": 6,
4+
"Description": "{{{description}}}",
5+
"Fields": [
6+
{
7+
"DefaultValue": "",
8+
"FieldType": "Text",
9+
"IsPrimaryKey": false,
10+
"IsRequired": false,
11+
"MaxLength": 50,
12+
"Name": "FirstName"
13+
},
14+
{
15+
"DefaultValue": "",
16+
"FieldType": "Text",
17+
"IsPrimaryKey": false,
18+
"IsRequired": false,
19+
"MaxLength": 50,
20+
"Name": "LastName"
21+
},
22+
{
23+
"DefaultValue": "",
24+
"FieldType": "EmailAddress",
25+
"IsPrimaryKey": false,
26+
"IsRequired": true,
27+
"MaxLength": 254,
28+
"Name": "EmailAddress"
29+
},
30+
{
31+
"DefaultValue": "",
32+
"FieldType": "Text",
33+
"IsPrimaryKey": true,
34+
"IsRequired": true,
35+
"MaxLength": 50,
36+
"Name": "ContactKey"
37+
}
38+
],
39+
"IsSendable": true,
40+
"IsTestable": true,
41+
"Name": "{{{prefix}}}dataExtensionShared",
42+
"ResetRetentionPeriodOnImport": false,
43+
"SendableDataExtensionField": {
44+
"Name": "ContactKey"
45+
},
46+
"SendableSubscriberField": {
47+
"Name": "Subscriber Key"
48+
},
49+
"c__dataRetentionPeriodUnitOfMeasure": "Months",
50+
"c__retentionPolicy": "individialRecords",
51+
"r__folder_ContentType": "shared_dataextension",
52+
"r__folder_Path": "Shared Items/Shared Data Extensions"
53+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "{{{prefix}}}query_SharedDE",
3+
"key": "{{{prefix}}}query_SharedDE",
4+
"description": "{{{description}}}",
5+
"r__dataExtension_key": "{{{prefix}}}dataExtensionShared",
6+
"targetUpdateTypeName": "Overwrite",
7+
"r__folder_Path": "Query"
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
SELECT
2+
SubscriberKey AS testField,
3+
TRIM(last_name) AS name
4+
FROM
5+
{{{prefix}}}dataExtensionShared
6+
WHERE
7+
country IN ({{{countryCodeIn}}})

0 commit comments

Comments
 (0)