3

I'm trying to run the following code:

cci task run deploy --path force-app\main\default\objects\ExpensivePackage__Their_Custom_Object__c --org my_scratch_org_alias

Against an ExpensivePackage__Their_Custom_Object__c folder that looks like this:

.
├── fields
│   └── My_Custom_Field__c.field-meta.xml
└── ExpensivePackage__Their_Custom_Object__c.object-meta.xml

I tried deploying it without the object definition, but Salesforce yelled at me because the definition of My_Custom_Field__c included <trackHistory>true</trackHistory>.

Update of CustomField ExpensivePackage__Their_Custom_Object__c.My_Custom_Field__c: Error on line 3, col 13: The entity: ExpensivePackage__Their_Custom_Object__c does not have    
                    history tracking enabled

If I add an object definition and just do this for its body:

<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
    <enableHistory>true</enableHistory>
</CustomObject>

I get errors like:

Update of CustomObject ExpensivePackage__Their_Custom_Object__c: Error: Must specify a non-empty label for the CustomObject

Or if I add a dummy label (not really something I want to do, lest I accidentally deploy it to production one day when the package has changed ... I'd rather leave label-setting to the managed package!)

Update of CustomObject ExpensivePackage__Their_Custom_Object__c: Error: Must specify a non-empty plural label for the CustomObject

Or if I dummy plural-label it:

Update of CustomObject ExpensivePackage__Their_Custom_Object__c: Error: Must specify a nameField of type Text or AutoNumber

What do I need to do to get <enableHistory>true</enableHistory> for ExpensivePackage__Their_Custom_Object__c deployed into my existing scratch org, which has that package installed, and not putz around with things I have no business touching?

(Note: if this isn't easy to get to work with a command that deploys files I'm just playing with into an existing scratch org, I'm open to wiping it out & rebuilding it. It takes 30 minutes to install all the packages, but if it works, it works.)

1 Answer 1

6

This is a frustratingly tricky area. There's one simple (but somewhat fragile) solution, and one programmatic (but reliable) solution.

Simple But Fragile

You need to pull down (via, for example, sfdx force:source:retrieve -m CustomObject:YourObject) the metadata for the manage package object. (You can do that with Custom Objects).

Then, you strip the custom object metadata down to the bare minimum needed to deploy. Remove all the custom fields, list views, anything else that's in there. (When the source is in SFDX format, these will of course be separate files). It's not particularly easy to spot the minimal metadata for deployment, so you may need to do a little experimenting - I believe you'll need to include the label and plural label fields and the deployment status.

Then, add your modification and deploy it.

Why is this fragile? Because the managed package can change some of those values that you're now storing in your static metadata out from under you, and you'll start getting confusing error messages suggesting that you're trying to update a managed component - because from the Metadata API's point of view, you are! What you've stored locally is different from what's in the org.

Of course, you can fix that at the time it occurs just by bringing your stored metadata up-to-date with the latest version of the managed package, but it's confusing and tedious.

Programmatic But Stable

CumulusCI has a framework called Metadata ETL whose raison d'etre is to make these kinds of transformations safe and stable. It works by retrieving a specific element of metadata from the org, applying a targeted transformation to the XML, and then redeploying the whole component.

You could write a Metadata ETL class to transform a Custom Object by setting the value of the trackHistory element. This would be pretty easy and follow the same pattern as some of the out-of-the-box Metadata ETL classes in CumulusCI - figure on 30-50 lines of Python.

This would be a valuable tool for many users of CumulusCI, so if you or any other reader is interested in building it, please feel free to get in touch and I would be happy to support through the process of code review and contribution to the open source project.

You'd then include that task in your flows, like dev_org, as part of the org setup.

1
  • 1
    Of course, if not already using CumulusCI this could be achieved with Apex scripting executed in an sfdx CLI call. More code to write, naturally, but may perhaps fit better with existing infrastructure. We took the "fragile" approach it must be said, since it is quick, easy and works 99.9999% of the time without any additional scripting, just a separate packageDirectory in the sfdx project to exclude this from packaging in 2GP.
    – Phil W
    Commented Dec 15, 2021 at 7:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .