Conversation
|
Thanks for the contribution! Unfortunately we can't verify the commit author(s): Aparna Goyal <r***@A***.com>. One possible solution is to add that email to your GitHub account. Alternatively you can change your commits to another email and force push the change. After getting your commits associated with your GitHub account, sign the Salesforce Inc. Contributor License Agreement and this Pull Request will be revalidated. |
Add SDR support for Data Cloud dataspace-scoped metadata (CalculatedInsight, DataModelObject). Their on-disk shape differs from every existing type: each component is a pair of generic .json files - a payload <name>.json and a <name>.meta.json sidecar - nested under a d360/dataspace/<dataspace>/<typeDir>/ wrapper, with no -meta.xml. The component fullName is dataspace-scoped (<dataspace>.<name>). - registry: register the two types with dataspaceScoped adapter/transformer strategies and index the `json` suffix so bare .json files resolve as metadata. - resolve: DataspaceScopedSourceAdapter derives the <dataspace>.<name> fullName from the path and folds the .meta.json sidecar into its payload component. - convert: DataspaceScopedMetadataTransformer preserves the full d360/... path in both directions and co-writes the sidecar alongside the payload. - collections: expandDataspaceScopedComponentSet builds the minimal deploy closure from each component's sidecar retrieveWith set.
aparnagoy
force-pushed
the
d360-dataspace-scoped-metadata
branch
from
September 21, 2026 21:23
e8279ce to
8f238d7
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: support Data Cloud (D360) dataspace-scoped metadata types
Summary
Adds first-class SDR support for Data Cloud dataspace-scoped metadata types.
These types do not fit any existing adapter/transformer because their on-disk
representation is unlike every other metadata type:
.jsonfiles (there is no-meta.xml):‹name›.json— the payload (the component definition).‹name›.meta.json— a sidecar carrying relationship metadata(
componentType,componentName,dataspaceName,retrieveWith,dependsOn).d360/dataspace/‹dataspace›/‹typeDir›/that must be preserved verbatim.‹dataspace›.‹name›(e.g.
‹ComponentType›:‹dataspace›.‹name›), where‹dataspace›is the pathsegment immediately above the type directory.
The registry, resolver, converter, and deploy-closure logic are taught to handle
that shape end-to-end, in both retrieve (metadata → source) and deploy
(source → metadata) directions.
The runtime pieces are type-agnostic: they derive everything from the path
shape and the sidecar convention, so onboarding an additional dataspace-scoped
type is a registry change (a type entry plus a directory mapping), never a
code change. This keeps the design open for extension and closed for
modification — new types plug in without touching the adapter, transformer, or
closure logic.
Design
Three new pieces of behavior, wired through the existing strategy indirection so
no core class is modified. All three share the single adapter/transformer
strategy id
d360:metadataRegistry.jsond360adapter + transformer strategies; index thejsonsuffix so bare.jsonfiles are recognized as metadata; strict directory names disambiguate one type's‹typeDir›from another's.D360SourceAdapter‹dataspace›.‹name›fullName from the path; treat the.meta.jsonsidecar as part of its sibling payload component (never a component of its own).D360MetadataTransformerd360/…path in both directions and co-write the sidecar alongside the payload.expandD360ComponentSetretrieveWithset.Why the
jsonsuffix index mattersResolution gates every file through
isMetadata(), which callsregistry.getTypeBySuffix(extName(path)). A suffix that is not present in theglobal
suffixesindex is silently skipped, so bare.jsonfiles were neverconsidered metadata. Indexing
jsonis what lets these components resolve atall;
resolveTypethen disambiguates the concrete type per-directory via thestrict folder name (each type's registered
directoryName), so a single sharedjsonsuffix mapping serves every dataspace-scoped type.Sidecar handling and the name-collision guard
baseName()splits on the first., so‹name›.jsonand‹name›.meta.jsonboth reduce to
‹name›.D360SourceAdapter.populate()therefore mustexclude
*.meta.json; otherwise the sidecar would resolve to the samedataspace-scoped name as the payload and collide. The sidecar is not lost — the
transformer re-emits it verbatim next to the payload on write.
retrieveWithvsdependsOnThe sidecar declares two distinct relationship lists:
retrieveWith— the components that travel together with this one as asingle deployable unit. This is what the deploy closure walks.
dependsOn— informational metadata about what a component references(the components it points at). It is not used to build the closure.
End-to-end flow (across repos)
The stack is always user → CLI → SDR → Core (server). The CLI is the command
entry point, SDR is the library that resolves/converts/packages the components
and computes the deploy closure, and Core owns the on-disk/wire contract (it
emits the two-file layout and the server-populated
retrieveWithon retrieve,and validates/applies the unit on deploy). SDR carries no per-type logic — the
d360strategy is selected purely from the registry.plugin-deploy-retrieveretrieveWithclosure before handing off to SDR.source-deploy-retrieve(this PR)D360SourceAdapter+D360MetadataTransformerthat resolve/convert the two-file layout both directions, andexpandD360ComponentSetwhich computes the deploy closure.d360/…payload +.meta.jsonsidecar and populates each component'sretrieveWith. On deploy validates and applies the unit.What crosses the SDR boundary
ComponentSet+ org connectionD360SourceAdapter), converts metadata → source (D360MetadataTransformer.toSourceFormat), co-writes the.meta.jsonsidecarRetrieveResult+FileResponse[]fullprojectComponentSet+requestedComponentSet(+ registry)d360members by sidecarcomponentName, walksretrieveWithtransitivelyComponentSet(requested + closure)ComponentSet+ org connectionD360MetadataTransformer.toMetadataFormat), packages the zip, submits the Metadata API deploy, pollsDeployResultsf project retrieve start— metadata → sourcesequenceDiagram actor User participant CLI as CLI (plugin-deploy-retrieve) participant SDR as SDR (source-deploy-retrieve) participant Core as Core (server) User->>CLI: sf project retrieve start --metadata ‹Type›:‹dataspace›.‹name› CLI->>SDR: ComponentSetBuilder.build(requested) → componentSet.retrieve(org) SDR->>Core: Metadata API retrieve request Core-->>SDR: unpackaged.zip (payload + .meta.json sidecar,<br/>server-populated retrieveWith) SDR->>SDR: resolve (D360SourceAdapter) + convert to source (D360MetadataTransformer.toSourceFormat) SDR-->>CLI: RetrieveResult + FileResponse[] CLI-->>User: writes force-app/main/default/d360/dataspace/…<br/>(payload + sidecar), prints resultCall stack inside SDR (retrieve):
sf project deploy start— source → metadatasequenceDiagram actor User participant CLI as CLI (plugin-deploy-retrieve) participant SDR as SDR (source-deploy-retrieve) participant Core as Core (server) User->>CLI: sf project deploy start --source-dir … CLI->>SDR: ComponentSetBuilder.build(requested) SDR-->>CLI: requested ComponentSet CLI->>CLI: hasD360Components(requested)? CLI->>SDR: ComponentSetBuilder.build(whole project) → full CLI->>SDR: expandD360ComponentSet(full, requested, registry) SDR-->>CLI: requested + transitive retrieveWith closure CLI->>SDR: componentSet.deploy(org) (MetadataApiDeploy) SDR->>Core: Metadata API deploy (payload + sidecar under d360/…) Core-->>SDR: DeployResult SDR-->>CLI: DeployResult CLI-->>User: prints resultCall stack inside SDR (deploy):
Call stack (resolution & conversion detail)
Resolution (retrieve):
Conversion (both directions):
Deploy closure:
Testing
yarn build(compile + lint) — green.yarn test(unit suite) — green.sf project retrieve startwrites the payload +.meta.jsonsidecar for a retrieved component and its co-emittedretrieveWithpeers underforce-app/main/default/d360/dataspace/‹dataspace›/‹typeDir›/, and the reversedeploy direction reproduces the same layout in the mdapi package.