Understanding Build Orgs, Part 3: Manipulating the Build Org
- David Reed
Series: Understanding Build Orgs
This discussion is derived from my experience building packages, writing packaging clients via the public API, and inspecting the public source code of the SFDX CLI. No internal or proprietary information about the Salesforce packaging system is included.
This third part of the series, which began with Understanding Build Orgs: Environmental Dependencies, What does
unpackagedMetadata do for a 2GP?, and Understanding Build Orgs: How a Build Org is Built, brings us to a close by getting as deep into the guts of the second-generation package (2GP) build org as we can get. Specifically, we'll tease out a thread we found at the end of Part 2: the fact that there's a Metadata API ZIP payload deployed into the build org before our packaged source.
Let's recall from Part 1 and 2 that there are a couple of thorny edge cases in terms of environmental dependencies that we haven't yet figured out how to serve, or serve well. In particular, we'll follow up on the challenge of packages that have dependencies on Standard Value Set entries.
In Part 2, we observed
... the settings bundle is deployed into the org. We know that
settings.zipis synthesized by the SFDX CLI from
objectSettingsinto Metadata API-format source. But that behavior is client-side, not part of the API as such. What if we could talk directly to the API, and put something other than those elements into
Let's dig into that possibility and see if it helps address our complicated use cases.
To do this experiment, I'm using CumulusCI, because it's easier for me to hack on. We'll need to actually make some code changes to run experiments against the behavior of
settings.zip. If you're not a Python engineer, that's fine! I'll walk through the contours of how we get this test ability.
CumulusCI's package upload semantics are a little bit different than those of SFDX, but for our purposes, we don't need to worry much about the differences. We'll use the
create_package_version task. That task already implements package upload by creating
Package2VersionRequest records, and it already re-implements the strategy used by the SFDX CLI to turn
settings.zip. Let's see what happens if we change that logic around a bit.
Working around line 400, in the logic that constructs a
Package2VersionRequest, we drop a little extra code:
This code looks for a new option,
settings_metadata_path. If there's a path given, it ignores the
objectSettings keys in the build org definition, and instead reads metadata directly from disk into the
settings.zip member of our
That gives us a route to pipe whatever metadata we wish into the API. Let's see what the API chooses to do with it.
We'll go back to the
standard-value-sets example. Recall that the original behavior we saw was this:
cci task run create_package_version \ --package-name "Standard-Value-Sets" \ --package-type Unlocked \ --org dev
[02/22/23 21:19:21] [Error]: Package creation failed with error: Error: Case.Customer Support Case: Picklist value: Evaluating not found
Let's see if we can get that package to create by stuffing some extra metadata in
We add a new metadata directory,
standard-value-sets-unpackaged. We include this metadata in that directory as
standardValueSets/CaseStatus.standardValueSet-meta.xml, configuring the Case Status picklist to match expectations.
false New true New false Working false Working false Escalated false Escalated false Closed false Closed true Evaluating false Evaluating true
Now, if I use my new code to inject this metadata into the build org as
cci task run create_package_version \ --package-name "Standard-Value-Sets" \ --package-type Unlocked \ --org dev \ --force-upload True \ --settings-metadata-path standard-value-sets-unpackaged
I get back:
[02/22/23 21:22:24] Created package version: Package2 Id: 0Ho4p0000000xxxCAQ Package2Version Id: 05i4p0000000xxxAAM SubscriberPackageVersion Id: 04t4p0000020xxxAAA Version Number: 0.0.0.2 Dependencies: 
Sure enough - the platform deployed my Case Status metadata during the build, and it satisfied my build-time dependency on that
Evaluating picklist value.
Did it work? Is the package actually viable? Let's set up an org with the picklist values we want, and install the package:
cci task run deploy --path standard-value-sets-unpackaged --org dev cci task run install_managed --version 04t4p0000020xxxAAA --org dev
Installing Package 04t4p0000020xxxAAA [02/22/23 21:41:59] In Progress [02/22/23 21:42:02] Success
Here's what we find under Support Processes in Setup:
Our picklist value reference is in the package!
Where does this leave us?
Well, it's an interesting capability we've discovered: injecting any metadata we like into the 2GP build org. It gives us another view into the build process, and reinforces a link between the 1GP and 2GP stories. We could, of course, do this same thing with a 1GP packaging org!
I wouldn't rely on it for a production 2GP managed package. This behavior is undocumented and not committed. It could certainly change tomorrow. But if's a technique I will keep in my back pocket when, as is often the case, I'm experimenting with 2GPs as testing tools.
And it's just kind of neat.