Ant Migration Tool: Refreshing Metadata
Salesforce consultants & developers may work on multiple projects in a given workweek. As outside help you cannot always control the development processes that are being utilized by the clients you are assisting. As such, you need to be flexible with your own development flows so you can contribute quickly without disrupting the customer's internal project team.
As the title suggests, you can use the Ant Migration Tool to refresh local Salesforce metadata files without manually removing the files or folders. This is tremendously useful if your development flow includes using Git to track file changes.
The first thing you will need is for Ant to be installed and configured on your computer. I've gone through the steps in another post.
Conceptually, this is what we are trying to accomplish with this example:
- Retrieve the metadata listed within an unmanaged package from a Salesforce Org
- Check if any metadata files within the local file structure are not present in the retrieved metadata
- Remove the files from the local file structure that are no longer present in Salesforce
- Overwrite the remaining local files with the metadata files retrieved from Salesforce
If you happen to be new to the concepts or use of the Ant Migration Tool then you should be aware that I am modifying the folder structure from the original developer documentation installation instructions in order to highlight the logic that is required to make this example work.
The file structure that speaks to our example is as follows:
The "src" directory is where all of the metadata will reside after the instructions are carried out by Ant.
The Salesforce Organization with which ant will be working is defined in the build.properties file:
# build.properties
#
#Salesforce organization login credentials
sf.username = first.last@example.com
sf.password = 7M3rGt7phk90?dV5Ekxyelwpoasjfekci_urfc23
#unmanaged package in source org
sf.pkgName = Id Converter
#https://login.salesforce.com OR https://test.salesforce.com
sf.serverurl = https://login.salesforce.com
sf.maxPoll = 100
The instructions that Ant follows are defined in the build.xml file:
<project name="Retrieve Example for Salesforce Developers" default="retrievePackage" basedir="." xmlns:sf="antlib:com.salesforce">
<property file="build.properties" /><!-- use properties defined in build.properties -->
<property name="src" value="C:\Desktop\org\app\retrievalTarget"/><!-- directory for interacting with Salesforce metadata API - this directory will be deleted at the end of the script -->
<property name="trgt" value="C:\Desktop\org\app\src"/><!-- directory for interacting with Git Repository -->
<!-- set default values for username, password and session - forces unset values to be treated as empty -->
<!-- without this, ant expressions such as ${sf.username} will be treated literally -->
<condition property="sf.username" value=""> <not> <isset property="sf.username"/> </not> </condition>
<condition property="sf.password" value=""> <not> <isset property="sf.password"/> </not> </condition>
<taskdef resource="com/salesforce/antlib.xml" uri="antlib:com.salesforce" /><!-- include ant-salesforce.jar -->
<!-- retrieve metadata for package named in sf.pkgName -->
<target name="retrievePackage">
<echo>Create the directory for the source metadata</echo>
<mkdir dir="${src}"/>
<echo>Retrieve the Salesforce metadata for the ${sf.pkgName} package</echo>
<sf:retrieve username="${sf.username}" password="${sf.password}" serverurl="${sf.serverurl}" maxPoll="${sf.maxPoll}" retrieveTarget="${src}" packageNames="${sf.pkgName}"/>
<!-- find files which are in directory target but not in source -->
<echo>Remove files that are no longer packaged in Salesforce</echo>
<delete verbose="true"><!-- verbose means show the files being removed in the CLI -->
<fileset dir="${trgt}" id="onlyintarget">
<present present="srconly" targetdir="${src}"/>
</fileset>
</delete>
<echo>Move source files that have been modified to target</echo>
<move todir="${trgt}" verbose="true">
<fileset dir="${src}" id="differentab">
<different targetdir="${trgt}" ignoreFileTimes="true"/>
</fileset>
</move>
<echo>Delete the source directory</echo>
<delete dir="${src}"/>
</target>
</project>
The build.xml file has been modified so that it only includes the instructions for making this example work. However, you should know that you can keep the original build.xml file that comes from the Ant Migration Tool installation and simply add the XML from this example to it if you choose.
In this example we will be using an unmanaged package to dictate what metadata is being retrieved from the Org. Therefore, you must create a package within your Salesforce Org and add metadata to it before this logic can be implemented.
To run the logic, open the command prompt and navigate to the directory we've created for this example. From there execute the "ant retrievePackage" command.
C:\Desktop\org\app>ant retrievePackage
Buildfile: C:\Desktop\org\app\build.xml
retrievePackage:
[echo] Create the directory for the source metadata
[mkdir] Created dir: C:\Desktop\org\app\retrievalTarget
[echo] Retrieve the Salesforce metadata for the Id Converter package
[sf:retrieve] Request for a retrieve submitted successfully.
[sf:retrieve] Request ID for the current retrieve task: 09S0L000002MiIjUAK
[sf:retrieve] Waiting for server to finish processing the request...
[sf:retrieve] Request Status: InProgress
[sf:retrieve] Request Status: Succeeded
[sf:retrieve] Finished request 09S0L000002MiIjUAK successfully.
[echo] Remove files that are no longer packaged in Salesforce
[echo] Move source files that have been modified to target
[echo] Delete the source directory
[delete] Deleting directory C:\Desktop\org\app\retrievalTarget
BUILD SUCCESSFUL
Total time: 13 seconds
C:\Desktop\org\app>