If you haven’t used the Force.com migration tool to move metadata from one org to another you are missing out. While there are several ways to move metadata between orgs the Force.com migration tool is powerful and a great addition to your Salesforce toolbelt.
When working with Salesforce to migrate metadata the Force.com migration tool synonymously referred to as Ant. Getting your machine setup involves Java, the Ant build tool, and the Force.com migration tool jar.
After you install all the prerequisites and get force.com migration tool working the TLDR main pieces are:
- ant-salesforce.jar: allows you to use ant to interact with the Salesforce metadata API
- Every release has a new version which relates to the release API
- build.properties: your credentials and login endpoints
- build.xml: the commands[targets] you can run
- package.xml: your list of metadata to retrieve or deploy
- destructiveChanges.xml: remove metadata from your org, separate from deploy
- destructiveChangesPre.xml: remove metadata before your package deploys
- destructiveChangesPost.xml: remove metadata after your package deploys
As you work with retrieving and deploying metadata you will find and possibly build a few things that are a little less used but still certainly useful.
A few I’m going to talk about here are:
- Retrieving the package.xml of a change set
- Retrieving foldered metadata like reports
- Execute a shell script from an ant build.xml
There may be several ways to get this kind of information but this can be another tool you put in your tool box.
After you’ve used the retrieve and deploy tasks, which you will use a lot, look at the readme for some other less commonly used but powerful tasks like listMetadata.
I used listMetadata this week to get a specific list of CustomMetadata. I entered the metadataType as CustomMetadata in my build.xml for the target listMetadata.
From the command line I executed that target
$ ant listMetadata
Which gave me an output listing all the CustomMetadata in my org with the following format
[sf:listMetadata] FileName: customMetadata/Mapping.Education_Call.md
[sf:listMetadata] FullName/Id: Mapping.Education_Call/m02c00000007XyOAAU
[sf:listMetadata] Manageable State: unmanaged
[sf:listMetadata] Namespace Prefix: null
[sf:listMetadata] Created By (Name/Id): David Meyer/00541000002a2BUAAY
[sf:listMetadata] Last Modified By (Name/Id): David Meyer/00541000002a2BUAAY
I used that to filter what I was looking for and output only the Names I was interested in.
I’ve found this useful to quickly get a list of metadata to include in my package.xml
Sometimes the member names are not straightforward with some characters needing to be encoded in your package.xml
listMetadata is quick way to get exactly that, lists of different metadata types in your org which you can use in a variety of ways. Share with your friends, build into scripts, whatever you like.
Retrieving the package.xml of a change set
You may have some colleagues that put together a massive change set to move from one org to another and now you want to move that same stuff from the org it was moved to on to a third org. Instead of rebuilding a change set you can get the content of that change set. The package.xml that could be used as well as the current state of the metadata associated to that package.xml
Get the name of your Change Set
Create a target in your build.xml that creates a directory and retrieves the Named Package
Execute your target from the command line
Which will retrieve a package.xml and the metadata listed in the Change Set
Retrieving foldered metadata like reports
Looking at the metadata types you can retrieve you will notice some are allowed to be retrieved with a wildcard, ApexClass, and others have to be explicitly listed, CustomLabel.
Others like reports need even more detail. The name of the report and the name of the folder.
The challenge is to get the reports and the folders.
On my Mac I am going to use a shell script, some templates, the listMetadata task, and a bulkRetrieve task to retrieve all the report folders and the reports they contain.
We’ll use listMetadata to retrieve all the report folders using the ReportFolder metadata type. Once we’ve got all the folders we’ll loop through that list using bulkRetrieve to get all the reports in that folder. Each call using bulkRetrieve generates a package.xml for that folder so after we’ve retrieved all the reports for all the folders we’ll traverse our foldered directories and build a package.xml that includes all the Reports/files.
You can find the code on github.
To get started, I navigate to the directory where my files are located
open build.properties and populate my credentials along with the path to my ant-salesforce.jar
open a terminal window and execute the getAll.sh script passing as a parameter the type of foldered metadata you want to retrieve [Report,EmailTemplate,Dashboard,Document]
The script puts the passed in parameter $1 in the ‘which’ variable
which api version number to be used in scripts
tmpPkgXml: the file we will use to build our ultimate package.xml
buildFile: this will contain a target with all our bulkRetrieve commands to get the foldered metadata
srcPath: the path where we will retrieve our metadata to
The line that starts with folders=( makes listMetadata call using the file get-folders.xml.
The result of the call is that all the folders for the specified metadata type are stored as an array in ‘folders’
We iterate through the array
adding bulkRetrieve tasks for each folder to get-Reports.xml
Then we execute the target retrieveType we just built. Retrieving all the reports
Finally we write the begining of our final package.xml
Traverse all the files and write the members to our package.xml
and close our package
Execute a shell script from an ant build.xml
Now that we can run this shell script to get our metadata we may want to invoke it from an ant process. To do that we could add a target[run-getAllsh] to a build xml specifying the path to our script and the argument we’ve been passing [Report]
All good fun with the Force.com migration tool, ant, and a shell script.