FAQ - Developer-Controlled Packages (DCPs) - Spring ‘18

Q. What is Packaging?

Q. What are the benefits of DCPs over change sets and ANT Migration Tool?

Q. What are the different types of packages and which one should I use?

Q. How do I build and deploy a new app using DCPs? What’s my Hello World App for DCPs?

Q. How can I organize my unpackaged metadata using DCP?

Q. What are some of the common packaging operations?

Q. How can I specify attributes in the sfdx-project.json file for managing my DCPs?

Q. What types of metadata are supported in a DCP?

Q. What is a namespace and should I use one with my DCP?

Q. How do I iterate on my DCP? What happens when I add, edit and delete DCP metadata?

Q. What are the implications of modifying a DCP’s metadata in installed orgs?

Q. Who owns the DCPs?

Q. How and where can I install my DCP?

Q. How can I find out packages installed / deployed in my org?

Q. How can I use Salesforce CLI to perform package-related operations?

Q. Can my packages depend on one another?

Q. How can I specify dependencies among DCPs?

Q. Are package dependencies enforced during install time?

Q. Can you give me an example of an sfdx-project.json file with many interdependent packages?

Q. How can I delete my package and package versions?

Q. How can I remove metadata from my package?

Q. How do I work with Version Numbers?

Q. What is the difference between beta package versions and released package versions?

Q. What are Locked Packages? Can I use them?

Q. If I am an ISV, what type of packaging should I use?

Q. Can I downgrade my package?

Q. What is the relationship between version control system and packages?

Q. How can I get more info about Salesforce DX and DCPs?

Q. What is Packaging?

As part of Salesforce DX, in Spring ‘18, we are launching Developer-Controlled Packages (DCPs) as an open beta. We’re bringing you, our enterprise customers, a new type of packaging option - DCPs - designed with you and your use cases in mind.

DCPs offer a new mechanism to deploy your metadata to Salesforce orgs. We believe DCPs provide distinct advantages over current technologies like change sets and the ANT Migration Tool (See here for the benefits of DCPs over current technologies).

Among other things, DCPs try to answer these two key questions:

  1. How does package development make it easier for me to package, deploy, and maintain new apps on the Salesforce Platform?
  2. How can I organize my existing unpackaged metadata in production orgs to adopt modular development practices that Salesforce DX prescribes?

Before we move ahead, it helps to clarify what we mean by unpackaged metadata.

Broadly speaking, the metadata in your production org can be categorized into three buckets:

  1. The set of metadata that Salesforce provides - such as  Sales Cloud, Service Cloud, etc. The Account object or the Case object falls under this category.
  2. Metadata that is part of AppExchange packages installed in the production org.
  3. Other metadata. This can be a Custom Field or Apex Trigger that you added to the Account object, the customizations that you made to an AppExchange app, or a brand new app that your team built in-house. This is the sum-total of all custom stuff that you have built over the years in your org. This category of metadata is referred to as unpackaged metadata in this FAQ.

It also helps to clarify what we mean by package and package version.

A Package is a container for Salesforce metadata. You can add metadata to a package and take a snapshot of it any time. This snapshot is called a package version. You can create package versions any number of times. Each package version, once created, is immutable. You can install a package version in any Salesforce environment - scratch orgs, sandbox orgs, or production orgs. Installing a package version deploys the metadata that was specified when the package version was created.

(Back to the table of contents)

Q. What are the benefits of DCPs over change sets and ANT Migration Tool?

The following are some key benefits of DCPs:

  1. The metadata that you specify when you create a package version for a DCP is the same metadata that is contained in your Salesforce DX project and version control system. DCPs promote the source-driven development approach and use the metadata format that Salesforce DX uses.
  2. With package versions, you have an immutable, versionable artifact that can be used in CI, UAT, etc. The same artifact that passes all your CI tests and UAT can be installed in your production orgs.
  3. DCPs promote modular development where you can organize your functionality into logical, modular, interdependent units, and use packaging for deployment and organization. You get all the good things that come with modular, iterative development practices.
  4. You can express dependencies among DCPs. With this capability, you can embrace a modular approach where each DCP represents a set of metadata that represents a distinct unit of functionality.
  5. DCPs can be tracked in the installed org because they show up as installed packages with a set of associated metadata. So, in the production org, you can view which metadata belongs to which package. Whether it’s during staging or deployment, DCPs ease the task of tracking what is part of an artifact compared to existing technologies like change sets.
  6. DCPs provide a repeatable, scriptable and trackable way to manage change as you develop functionality using Salesforce DX.

(Back to the table of contents)


Q. What are the different types of packages and which one should I use?

You may have heard of many package-related terms - managed packages, Package 2, DCPs, unmanaged packages, second-generation packages. Let’s demystify these now. See here if you are wondering what a package really is.

First-Generation Packaging

Before Salesforce DX came along, we had two types of packages:

Second-Generation Packaging (aka Packaging 2 or Salesforce DX Packaging)

With Salesforce DX, we are launching Packaging 2 or Second-Generation Packages. With Salesforce DX, we want packaging to work as well for customers as they do for partners.

Developer-Controlled Packages (DCPs) are designed for customers to organize metadata into packages and facilitate testing, deployment, and upgrades. There are two flavors of DCPs - locked and unlocked. For now, use the unlocked flavor of DCPs as they are open beta and can be installed anywhere. Locked DCPs will stay in Pilot mode for a while and can only be installed in sandbox orgs and scratch orgs.

Managed Second-generation packages (Managed 2GPs) are geared more towards Salesforce partners who want to develop and list apps on AppExchange. While Managed 2GPs are beta, there are certain key parity features (Push Upgrades, LMA, ability to list on AppExchange, patch versions, etc.) that are missing in them. So, if you are a Salesforce Partner, your best bet is to continue with First-Generation Managed Packages until we build those feature parity items in managed 2GPs. See here for more info if you are an ISV.

To summarize in one sentence, if you are a Salesforce customer, contractor, consultant or Systems Integrator, the only type of packaging that matters to you is Unlocked DCPs, which are available to you, NOW!

(Back to the table of contents)

Q. How do I build and deploy a new app using DCPs? What’s my Hello World App for DCPs?

In less than 5 minutes, you can build and test your Hello World App to get a feel for DCPs. The only precondition is that you have a Salesforce DX environment set up with Salesforce CLI and that you have enabled Dev Hub and Packaging 2 in your Dev Hub Org. If you haven’t done it already, refer to this documentation.

Follow these simple steps and you have for yourself a DCP!

  1. Set up a directory on your local machine and copy the sample repo. Let’s presume this is the app that your team is building for meeting a business need.

git clone https://github.com/dreamhouseapp/dreamhouse-sfdx.git

cd dreamhouse-sfdx/

git checkout spring18

(If you want more info about the DreamHouse app, see here)

  1. Authenticate to your Dev Hub org.

sfdx force:auth:web:login --setdefaultdevhubusername

  1. Create a Developer-Controlled Package.

sfdx force:package2:create --containeroptions Unlocked --nonamespace --name Dreamhouse-App

  1. Edit the "packageDirectories" section of the sfdx-project.json file in your project and for the “id” field, enter the 0Ho ID that you got from step 3. This identifies a unique package ID for this DCP. Enter proper value for versionName and versionNumber as shown below:

"id": "0HoB0000000009OKAQ",

"versionName": "Spring - 2018",

"versionNumber": "1.0.0.NEXT" (see here for more info about version numbers)

  1. Create a package version. When you create a package version, you are associating metadata with your package. Over the course of time, you create many, many package versions for a given DCP. Once created, a package version serves as an immutable artifact containing a specific set of metadata. This is the same metadata that you specify at the package version creation step.

sfdx force:package2:version:create --directory force-app --wait 10

In this example, force-app is the directory in which your package metadata is located in Salesforce DX format. The other pieces of information needed for package version creation are stored in sfdx-project.json.

  1. Create a scratch org where you can install the package.

sfdx force:org:create --noancestors --nonamespace --definitionfile config/project-scratch-def.json --setalias sub1 --setdefaultusername

  1. Install the package in the scratch org.

sfdx force:package:install --id <04t_id_from_step_5> --wait 10

  1. Open the scratch org in the browser.

sfdx force:org:open

  1. In the scratch org, go to Setup -> Installed Packages, where you can see that the package has been installed.

  1. Click the Package Name and the View Components button to validate that the components present in the project are now deployed as part of the DCP.

Congratulations! You have now created and installed your first DCP!

(Back to the table of contents)


Q. How can I organize my unpackaged metadata using DCP?

Step 1 - Extract a small set of unpackaged, self-contained metadata from your production org and convert it to Salesforce DX format using mdapi:retrieve and mdapi:convert commands.

How to identify this set of self-contained metadata is a bit of a science and a bit of an art. You can try and select metadata that represents an app, or customization to an AppExchange app, or customizations to Sales Cloud or an Account object, or some set of metadata that represents a functional unit (e.g.: a library of apex classes). We know this is a challenging task. We plan to produce material to help in this. See this blog series that talks about DX and DCPs.

Step 2 - Push this metadata to a scratch org using source:push and validate that this is the metadata that you want to be part of a new DCP. If you are missing some metadata, go back to Step 1.

Step 3 - Create a DCP using this metadata (see here for how to create a DCP). Make sure this DCP has no namespace (supply the --nonamespace flag to the force:package2:create command). See here for more info about namespaces and packages.

Step 4 - Test the DCP in CI and UAT environments. If you encounter issues, you may have to go back to Step 1 and validate that you have the right set of metadata. Once the DCP has passed all CI runs and UAT on sandboxes, install the DCP in the production org. This installation does NOT deploy new metadata as what’s contained in the DCP is already present in the production org. But what this does is “migrate” the metadata from the unpackaged set to the DCP so that it is now part of the DCP in the production org. From this point forward, you can iterate over this metadata set using the DCP.

These steps, along with the specification of dependencies among DCPs, can help in organizing all of the unpackaged metadata into a set of interdependent DCPs.

(Back to the table of contents)

Q. What are some of the common packaging operations?

Package Creation

A package is a container of metadata. When you create a package, such as a DCP, you specify some characteristic info about the package: name, description, namespace associated with it, package type (unlocked for now), and so on. Associating metadata with a package occurs at the package version creation step.

Package Version Creation

As your development team is working on some functionality, you, as a release manager, may want to take periodic snapshots of the functionality when it is in a functional state. Such snapshots are package versions. You can create any number of package versions. Each version, once created, is immutable.

Package Install

A package install is an operation whereby the metadata of a package is deployed in the target org. A package install is actually a package version install - it is the deployment of metadata contained in a specific package version of a package. A package is typically associated with 100s or even 1,000s of package versions. When you install a package, you specify which one of the many versions you intend to install. Install and deploy mean the same in this context.

Package Upgrade

Installing a version on top of a previously installed package version is a package upgrade. When you perform a package upgrade, the metadata of the new package version is deployed to the org. The package upgrade process can add new metadata to the org, modify existing metadata, and may even delete some metadata depending on what’s there in the new version of the package.

Package Downgrade

See here for more info about package downgrades.

Package Uninstall

This is an operation where you are deleting the metadata and associated data related to an installed package.

See here for how you can perform these operations using the Salesforce CLI.

(Back to the table of contents)


Q. How can I specify attributes in the sfdx-project.json file for managing my DCPs?

See this example below for a section of sfdx-project.json file

(this deliberately avoids package dependencies to keep things simple. See here for a simple example of package dependencies and here for a more complex scenario)

"packageDirectories": [

       {

           "path": "revenue-app",

           "default": true,

           "id": "0HoB00000004CFpKAM",

           "versionName": "version 1.0",

           "versionDescription": "Spring 2018 Release",

           "versionNumber": "1.0.0.NEXT",

           "features": "MultiCurrency,PersonAccounts",

           "orgPreferences": {

               "enabled": [...],

               "disabled": [...]

           }

       },

       {

           "path": "logic",

          …

       }

]

path (required field) - root folder where the source metadata of the package is stored in the local workspace in Salesforce DX format

id (required field) - this is the package id that starts with 0Ho. The output of the force:package2:create command provides this ID.

versionName (required field) and versionDescription (optional field) - name and description of the package version that you’re creating.

versionNumber  (required field) - version number in major.minor.patch.build format where each one of these is a whole number. See here for more info about package versions.

features and orgPreferences - these are features and org preferences required for the metadata in the DCP. See here for more info.

 (Back to the table of contents)


Q. What types of metadata are supported in a DCP?

Most metadata that is supported by Salesforce DX is supported in a DCP. See here for more information.

 (Back to the table of contents)


Q. What is a namespace and should I use one with my DCP?

A namespace is a unique identifier that is owned by your company when you register it with Salesforce. If you associate a namespace (like Acme) with a DCP (see here for how to associate namespaces with Dev Hub), the API names of all metadata added to the DCP will have the prefix Acme__. Hence, namespaces offer a mechanism to name and organize metadata in your org.

Keep the following in mind when you think of namespaces and DCPs:

  1. Namespaces are optional for DCPs. There are many use cases where you won’t want to use namespaces with DCPs. If you intend to move your metadata from unpackaged state in your production org to DCPs (see here for more info), create DCPs without a namespace. That way, when the metadata is moved from unpackaged state to a DCP, the API name of the metadata elements won’t change.
  2. A Salesforce DX Dev Hub can be linked to multiple namespaces so it’s possible for you to use different namespaces for different DCPs.
  3. Multiple DCPs can be associated with the same namespace.
  4. A DCP can be associated with only one namespace.
  5. A DCP can be associated with a namespace only during package creation (force:package2:create) and cannot be changed, once associated.

 (Back to the table of contents)


Q. How do I iterate on my DCP? What happens when I add, edit and delete DCP metadata?

DCPs provide a very open framework for making metadata changes. Before we talk about these changes, make sure you understand the difference between a package and a package version. See here for more info. Also take a look at this for packaging  operations.

Versioning is one of the core differentiating features of packaging. It is versioning that enables iterative development, where you can continually update an artifact (DCP) in a controlled and manageable way in response to business needs (feature requests and bug fixes).

When it comes to versioning and changes introduced in versions, it is helpful to look at them from two angles - development stage and deployment stage.

Development and Build Stages

When you create a new package version of a DCP, you can introduce the following changes in relation to a previous package version:

  1. Add new metadata to the project workspace, such as  a new Lightning Page or a new Apex Controller
  2. Modify existing package metadata, such as updating a business process in response to end-user feedback or updating an Apex method to fix a bug.
  3. Delete existing package metadata, such as deleting two Visualforce pages as they are being replaced by Lightning Pages, deleting a custom field as it has become obsolete, etc.

The above-described changes can be applied in a variety of ways (Setup UI in scratch orgs, in VS Code, in Developer Console, etc.) and ultimately make it to the version control system for the project (See here for relationship between version control system and DCPs). The release manager then pulls in the right set of metadata to the local workspace and creates a new package version so that the package version captures these changes.

Deployment Stage

Let’s presume you are trying to deploy (aka install) v 2.0 of a DCP in an environment where v 1.0 is currently installed. During this package upgrade process, the following changes are applied:

  1. Metadata that is new in v2.0 in comparison to v1.0 are deployed or created in the target org.
  2. Metadata that has changed are applied. For example, if a Lightning Page or Apex Controller has been modified in v2.0, those modifications are applied as part of package upgrade.
  1. When it comes to metadata delete - this is the scenario where something (custom field or report or apex class) present in v1.0 was deleted in v2.0 - there are two possible outcomes. For the first class of metadata types, the metadata is deleted from the target org. For the second class of metadata types, the metadata is marked as deprecated. When metadata is marked deprecated, it is still part of the DCP but it shows up as deprecated when you look at the metadata in Setup so that it is easier for admins to track it and delete it from the org. We understand that this deletion of metadata in the installed org is a manual step that should be automated. In many scenarios, you may want the package upgrade process to automatically delete metadata that was removed from the package. We plan to make this process more automatable in future releases.

(Back to the table of contents)


Q. What are the implications of modifying a DCP’s metadata in installed orgs?

You have developed an unlocked DCP, taken it through all of the testing cycles - integration, user acceptance, etc. - and you are now ready to install it in your production org. One question that arises is, what happens if your admin has to make an emergency change to the metadata directly in the production org? For example, the admin might have noticed that some permission sets are granting too much access, a page layout is missing some critical fields, or a report is missing a key column. If this metadata is part of a DCP, should the admin contact the development team and take it through the full cycle of development, testing, UAT and then do the deployment? The answer is yes from a best practice of software development process perspective. But what if one or all of these changes need to be made right now!?

With unlocked DCPs, the admin has the flexibility to make all of these changes directly in production. The fact that these components belong to a DCP won’t restrict the flexibility that the admin has towards making changes. However, the admin has to ensure that the development team is informed of these changes. Once the development team is aware of these changes and incorporate them in the next version of the DCP, installing future versions of the DCP won’t undo the changes made by the admin in the production org. However, if the changes made directly in production are not applied to the metadata of the DCP by the development team, subsequent package installs or upgrades will overwrite the changes made in production.

(Back to the table of contents)


Q. Who owns the DCPs?

The Dev Hub in which the DCPs were developed is the owner of the DCP. The association between the dev hub and a DCP occurs when you execute the force:package2:create command. The Dev Hub org against which this command is run is the owner of the DCP.

Please keep in mind the following about Dev Hub and DCP:

  1. A Dev Hub can own many DCPs but a DCP is associated with one and only one Dev Hub.
  2. The Packaging 2 Beta checkbox should be checked in Setup -> Dev Hub page in the Dev Hub before force:package2:create command can be successfully executed.
  3. Once created, the ownership of a DCP cannot be transferred from one dev hub to another dev hub.
  4. When you are ready to create DCPs intended for production org use, please make sure they are created against your official Dev Hub org, not a trial Dev Hub org. If your Dev Hub org expires, your DCPs become inoperable.  

(Back to the table of contents)


Q. How and where can I install my DCP?

An unlocked DCP can be installed in any Salesforce environment - scratch orgs, sandbox orgs, trial orgs, and production orgs (see here for a note on beta vs released state of a package version).

A DCP can be installed in two different ways:

Salesforce CLI command

force:package:install --id <04t id> --targetusername <org where the DCP should be installed> 

The Salesforce UI

By appending the following to the browser URL: packaging/installPackage.apexp?p0=<04t id>

The 04t is the package version ID. This represents the version of the DCP to install. The 04t ID is returned when the force:package2:version:create Salesforce CLI command returns successfully. You can use force:package2:version:list command to get a list of package versions associated with a DCP.

See here if you want to know more about different packaging operations.

(Back to the table of contents)


Q. How can I find out packages installed / deployed in my org?

In any given org, you can obtain information about installed packages in one of the following ways.

Salesforce CLI

force:package:installed:list command

Salesforce UI

  1. Go to Setup
  2. In Setup, search for “Installed Packages”
  3. Go to Apps -> Installed Packages page
  4. The installed packages are listed in this page. Click on any package name to get more info about the package like version info, list of metadata present in the package, etc. This list shows info about installed packages of all types of packages.

See here for how to install a DCP in an org.

(Back to the table of contents)


Q. How can I use Salesforce CLI to perform package-related operations?

See here if you want to first understand what these operations are intended for.

Development-side Commands

Create a DCP - force:package2:create

Add, modify and remove metadata from a DCP - Update the workspace files

Get a listing of all DCPs - force:package2:list

Update info about a DCP - force:package2:update

Create a DCP version - force:package2:version:create

Obtain info about the status of a DCP version create request - force:package2:version:create:get

Obtain info about the status of all DCP version create requests - force:package2:version:create:list

Get a listing of all DCP versions - force:package2:version:list

Get detailed info about a single DCP version - force:package2:version:get

Update info about a DCP version - force:package2:version:update

Install-side Commands

Install a DCP - force:package:install

Status of an install request - force:package:install:get

Info about all installed packages in an org - force:package:installed:list

Uninstall a DCP - force:package:uninstall

Status of an uninstall request - force:package:uninstall:get

(Back to the table of contents)

Q. Can my packages depend on one another?

Yes, one of the value propositions of DCPs is that you can develop and maintain a set of interdependent packages. By supporting dependencies, DCPs promote modular development with a dependency framework.

The following are some of the main use cases around dependencies:

  1. A DCP depending on an AppExchange Package. This is the use case where you have purchased an AppExchange package and want to customize it. In such a scenario, the DCP that you are going to build will be dependent on the installed AppExchange package and will contain all of the customizations made to the AppExchange package. For E.g: you might have added additional custom fields to custom objects that are part of the AppExchange package, or have created new reports and dashboards to better visualize the information. All of these customizations can be part of a DCP.
  2. A DCP depending on another DCP. Maybe you are developing a Reimburse Me App to enable your employees to submit expense reports. This App depends on some backend integration functionality that has already been built that enables Payroll to take care of approved expenses. In such a scenario the Reimburse Me App DCP will depend on the Payroll Processor DCP.

 

Also, keep the following in mind when you think of package dependencies:

See here to see how you can express dependencies in sfdx-project.json and see here for a more advanced example.

(Back to the table of contents)


Q. How can I specify dependencies among DCPs?

See here to know more about package dependencies.

You express dependencies within the packageDirectories section of sfdx-project.json.

The following are the different types of supported dependencies

A DCP depending on another package in the same dev hub

"dependencies": [

   {

      "packageId": "0HoB0000000009EKAQ",

      "versionNumber": "2.5.0.LATEST"

    }

]

This expresses that the current DCP depends on another package of version number 2.5 with package id 0HoB0000000009EKAQ. This package can be a managed second-generation package or another DCP. By using the keyword LATEST, you can iterate on the base and dependent package versions simultaneously.

A DCP depending on another package developed in a different dev hub

There are two main use cases for this:

"dependencies": [

   {

      "subscriberPackageVersionId" : "04tB0000000J6iZ"

    }

]

This expresses that the current DCP depends on another package with package version id 04tB0000000J6iZ. This is the way to specify dependencies if the package that the current DCP depends on, was developed in a different dev hub.

For a more complex scenario of package dependencies, please see here.

(Back to the table of contents)

Q. Are package dependencies enforced during install time?

  1. Package dependencies are used during development time. E.g.: if you are developing DCPs and if your apex class in package dcp-y is invoking another apex class that is present in package dcp-x, you should express that dcp-y depends on dcp-x for the package version creation of dcp-y to succeed. (See here for how to express these dependencies)

  1. Package dependencies are enforced at installation time in the sense that if dcp-y depends on dcp-x, you will have to install dcp-x before you can install dcp-y; otherwise the installation of dcp-y fails with an error message. Also, you have to ensure that the appropriate versions of the package are installed in the org. For E.g.: if dcp-y ver 4.0 has a Lightning Page that uses an apex controller from dcp-x ver 3.0, attempting to install dcp-y ver 4.0 fails in an org where dcp-x ver 2.0 is installed. In a future release, we are exploring ways in which this experience can be improved. For E.g.: maybe we explicitly list out which versions of what packages have to be installed before installing dcp-y, especially if dcp-y depends on multiple packages. Better still, we can install the packages that dcp-y depends on, if those packages are not present.

(Back to the table of contents)


Q. Can you give me an example of an sfdx-project.json file with many interdependent packages?

See here to know more about package dependencies. See here for a simple example of package dependencies.

Let’s consider the following scenario:

  1. DCP Reimburse Me App depends on two DCPs - Expense Manager and Travel Booker. Expense Manager depends on an apex library built in-house as a DCP - Utils. Travel Booker is a DCP that extends a purchased AppExchange App Travel Anywhere!

packageDirectories section of sfdx-project.json file for Travel Booker DCP

(working on ver 3.2 of the Travel Booker DCP that depends on ver 4.5 of Travel Anywhere! AppExchange package installed in production org. The package version id of ver 4.5 of the AppExchange App is 04tB0000000IB1EIAW)

{

"path": "travel-booker",

         "id": "0HoB00000004CFuKAM",

"versionName": "v 3.2",

"versionDescription": "Summer 2018 Release",

"versionNumber": "3.2.0.NEXT",

"dependencies": [

{

"subscriberPackageVersionId" : "04tB0000000IB1EIAW"

}

]            

}

packageDirectories section of sfdx-project.json file for Expense Manager DCP

(working on ver 4.7 of the Expense Manager DCP that depends on ver 2.6 of Utils DCP whose package2 id is 0HoB00000004CFpKAL)

{

"path": "expense-manager",

         "id": "0HoB00000004CFuKAN",

"versionName": "v 4.7",

"versionDescription": "Summer 2018 Release",

"versionNumber": "4.7.0.NEXT",

"dependencies": [

{

"packageId": "0HoB00000004CFpKAL",

"versionNumber": "2.6.0.LATEST"

}

]            

}


packageDirectories section of sfdx-project.json file for Reimburse Me DCP

(working on ver 3.8 of the Reimburse Me DCP that depends on ver 3.2 of Travel Booker DCP and ver 4.7 of Expense Manager DCP)

Note: you have to declare all of the transitive dependencies in the order in which these DCPs should be installed from a dependency stand-point.

{

"path": "reimburse-me",

         "id": "0HoB00000004CFuKAP",

"versionName": "v 3.8",

"versionDescription": "Summer 2018 Release",

"versionNumber": "3.8.0.NEXT",

"dependencies": [

{

"subscriberPackageVersionId" : "04tB0000000IB1EIAW"

},

{

"packageId": "0HoB00000004CFuKAM",

"versionNumber": "3.2.0.LATEST"

},

{

"packageId": "0HoB00000004CFpKAL",

"versionNumber": "2.6.0.LATEST"

},

{

"packageId": "0HoB00000004CFuKAN",

"versionNumber": "4.7.0.LATEST"

}

]            

}

sfdx-project.json file for All of these 4 DCPs

If the 4 DCPs (Reimburse Me, Expense Manager, Travel Manager and Utils) are developed in a single SFDX project workspace, the sfdx-project.json will be a merge of the above snippets.

{

  "namespace": "",

  "sfdcLoginUrl": "https://login.salesforce.com",

  "sourceApiVersion": "42.0",

  "packageDirectories": [

{

"path": "reimburse-me",

                 "id": "0HoB00000004CFuKAP",

...          

},

{

"path": "expense-manager",

                 "id": "0HoB00000004CFuKAN",

...            

},

{

"path": "travel-booker",

         "id": "0HoB00000004CFuKAM",

...

},

{

"path": "utils",

         "id": "0HoB00000004CFpKAL",

...

},

  ]

}

(Back to the table of contents)


Q. How can I delete my package and package versions?

It is currently not possible to delete package or package versions. In a future release, we will provide capabilities for the same. For now, you can rename them (using force:package2:update and force:package2:version:update Salesforce CLI commands) to denote that you are no longer using them.

Click here for more info about packaging operations.

(Back to the table of contents)


Q. How can I remove metadata from my package?

If you want to delete some metadata from your DCP because you no longer need that metadata, then you can delete that metadata from your local workspace, create a new package version and install that version in the production org. That process will delete the metadata in the production org. There are some limitations with respect to what gets deleted. Please see here for more details.

However, remove is different from delete. It refers to removing some metadata from a DCP because that metadata does not naturally belong to the DCP. You may want to make that metadata unpackaged and add it to another DCP. This remove capability does not exist in Spring ‘18. Safe Harbor, we plan to provide this capability in Summer ‘18.

(Back to the table of contents)


Q. How do I work with Version Numbers?

A package version is an immutable artifact that is a snapshot of a package with a specific set of metadata. A package version is created with a successful execution of the force:package2:version:create command. Every package version (see here for more info about package and package versions) you create has a unique version number. The version number is in the major.minor.patch.build number format where major, minor, patch and build are integers.

Here are some things to keep in mind with respect to version numbers:

  1. You specify the version number in the versionNumber field in sfdx-project.json. This is a required field.
  2. You increment version numbers so you keep track of changes. You typically increment major number for major releases and minor number for minor releases.
  3. Patch number is reserved for a feature that we want to develop in a future release. Keep it as 0 for now.
  4. If your team is working on a specific release (E.g.:ver 3.5), you may find the process of updating build number laborious especially if you are using CI to create package versions. We recommend that you use the NEXT keyword to simplify this. When you specify NEXT as in 1.3.0.NEXT, we auto-increment the build number for you.  

(Back to the table of contents)


Q. What is the difference between beta package versions and released package versions?

When you create a package version using force:package2:version:create, we set the state of the package version to beta. Beta package versions are internal test candidates that are used in test cycles including CI. To prevent a beta package version from being inadvertently installed in production orgs, we prevent the installation of beta package versions in any org that is not a scratch org, sandbox org or Developer Edition org.

As part of your development process, you end up creating lots and lots of package versions that are all of beta state. When a package version passes all tests including UAT (User Acceptance Testing), you can promote that package version to be a release candidate by issuing the following CLI command:

force:package2:version:update --package2versionid <05i package version id> --setasreleased

A package version promoted to released state can be installed in any org.

For a given major.minor.patch package version number (see here for more info about version numbers), there can be at most one package version in released state. Once you set a package version to released state, you cannot undo that operation.

(Back to the table of contents)


Q. What are Locked Packages? Can I use them?

There are two types of Developer Controlled Packages (DCPs):

The key aspect that is common between these two types of DCPs is that the changes made by the development team wins. i.e. despite any changes made in the installed org, when a package upgrade is done, the contents of the package version overwrite what’s in the org.

The main difference between Locked and Unlocked DCPs is when it comes to modifications that can be made in installed orgs. With Locked DCPs, most changes are locked down so that the metadata deployed as part of a locked DCP is read-only. In the case of unlocked DCPs, the metadata deployed as part of a DCP is editable and deletable.

Locked DCPs work best with organizations where there is a desire to prevent any changes to be made directly in production orgs. Organizations adopting locked DCPs are willing to go through the process (make changes to metadata, build a new DCP version, test and deploy to production) for any changes, including emergency changes to metadata.

Unlocked DCPs work best with organizations where there is a desire to support changes to be made directly in production orgs for emergency use cases - E.g.: a permission set has incorrect set of permissions, a workflow rule is broken, a Flow needs to be deactivated immediately, a report is missing a key column that should be added asap. Organizations adopting unlocked DCPs are willing to set up a process where admins communicate unplanned changes applied directly in production orgs with the development team so that subsequent versions of the DCP incorporate the changes made in production.

Unlocked DCPs are open beta in Spring ‘18 meaning they can be installed in any org. For the next few releases, locked DCPs stay in pilot mode - they can only be installed in scratch org or sandbox orgs.

We recommend that you use unlocked DCPs and wait for us to launch locked DCPs in GA mode.

(Back to the table of contents)

Q. If I am an ISV, what type of packaging should I use?

If you are an ISV that develops and lists apps on AppExchange, here are our recommendations (See here for info about different types of packages):

  1. Continue to use first-generation managed packages (1GPs) for now when it comes to listing and distributing apps to customers.
  2. In current and upcoming releases, we are working on enabling the listing of second-generation packages (managed 2GPs) on AppExchange and building feature parity with first-generation managed packages - features like LMA and push upgrades. Until we can develop these features and launch managed second-generation packages as GA, your best bet is to continue with first-gen packages.
  3. You can definitely consider second-generation managed packages (managed 2GPs) during development cycle. You can build and test your metadata using scratch orgs and 2GPs and use 1GPs for final rounds of testing and building the official release candidate. This will help you take the benefits of managed 2GPs in development stages.
  4. DCPs are designed primarily keeping customer use cases in mind. There could be scenarios where DCPs are helpful to ISVs as well. Familiarize yourself with what DCPs can do and see if they map to some of your use cases.

(Back to the table of contents)


Q. Can I downgrade my package?

In the context of packaging, a downgrade is installing a lower version of a package on top of a higher version. For E.g.: this is when you try to install ver 2.0 of your DCP in an org where ver 4.0 has been installed. When you downgrade a package, the following occurs:

  1. The metadata of the package version (ver 2.0 in this example) is deployed to the target org.
  2. Any metadata that is present as part of the DCP in the installed org (ver 4.0 metadata in this example) is modified, deleted or deprecated based on whether they are present in the version being installed. For E.g.: an apex class will be modified to the ver 2.0 copy of it as part of the downgrade. If a custom object foo__c is not present in ver 2.0 but present in ver 4.0, foo__c is marked deprecated (See here for more info about what deprecated means in this context). If a report object is not present in ver 2.0 but present in ver 4.0, the report is deleted from the org.

You should consider any downgrade of a package carefully. Package downgrades can fail due to dependency scenarios. For E.g.: if ver 4.0 has an apex class that is referenced by another apex class in a different DCP, downgrading to ver 2.0 would fail with a user-friendly error message if that apex class is not present in ver 2.0 of the DCP.

(Back to the table of contents)


Q. What is the relationship between version control system and packages?

When it comes to Developer Controlled Packages (DCPs), the source of truth is your version control system (vcs). Having said that, DCPs or packages in general don’t explicitly link to a vcs. The step where you link the metadata that you want in a package to your DCP is in the force:package2:version:create step and that requires the directory name of your SFDX project, not a vcs repo. Here are some best practices you can follow to ensure your vcs tracks changes made to your DCPs:

  1. Use the --tag field in the force:package2:version:create or force:package2:version:update commands to store any vcs related tagging information.
  2. Use version control system commits to tag the set of metadata that was associated with a particular successful package version creation. This way, your version control system knows the state of metadata for any given package version.

(Back to the table of contents)


Q. How can I get more info about Salesforce DX and DCPs?

We have lots of additional information that goes into the details of how to work with Salesforce DX and DCPs. Following are some helpful resources:

Last but not the least, please join our Trailblazer Communities where so many developers like you are collaborating with fellow developers in their Salesforce DX journey.

(Back to the table of contents)