diff --git a/src/utils/deploy.ts b/src/utils/deploy.ts index 5c5d8134..76d3792c 100644 --- a/src/utils/deploy.ts +++ b/src/utils/deploy.ts @@ -24,6 +24,7 @@ import { ComponentStatus, DeployResult, DestructiveChangesType, + expandD360ComponentSet, FileResponseSuccess, MetadataApiDeploy, MetadataApiDeployOptions, @@ -119,6 +120,22 @@ export async function buildComponentSet(opts: Partial, stl?: Sour }); } +/** True when the deploy includes at least one Data Cloud dataspace-scoped component. */ +const hasD360Components = (requested: ComponentSet): boolean => + [...requested.getSourceComponents()].some((c) => c.type.strategies?.adapter === 'd360'); + +/** + * A dataspace-scoped component's sidecar lists the peers it has to be deployed alongside, under + * `retrieveWith`. So when someone deploys one of these, we also pull in those peers (and their peers, + * and so on) — but nothing else from the project. To find them we resolve the whole project once, + * then hand back the requested set plus that closure. + */ +async function expandD360Closure(requested: ComponentSet, registry?: RegistryAccess): Promise { + // Resolve the whole project so we can look up the retrieveWith peers by their sidecar componentName. + const full = await ComponentSetBuilder.build({ sourcepath: await getPackageDirs() }); + return expandD360ComponentSet(full, requested, registry); +} + export async function executeDeploy( opts: Partial, project?: SfProject, @@ -166,6 +183,11 @@ export async function executeDeploy( registry = stl.registry; componentSet = await buildComponentSet(opts, stl); + // Dataspace-scoped components need their retrieveWith peers in the same deploy, so pull those in. + // Every other deploy leaves the component set untouched. + if (hasD360Components(componentSet)) { + componentSet = await expandD360Closure(componentSet, registry); + } if (componentSet.size === 0) { if (opts['source-dir'] ?? opts.manifest ?? opts.metadata ?? throwOnEmpty) { // the user specified something to deploy, but there isn't anything