Part 3: Advanced use of the Migration tools: Recycling Developer Orgs

In the previous parts of this blog series, the basic use of the migration tools and how they could be used to seup a developer org were explained.  In this blog post I intend to delve a bit deeper into how to use the tools so that the developer orgs can be recycled and reused for future development.  Reusing the same developer orgs removes the time and effort needed to create new developer and helps ensure all development is done with similar org types and settings enabled.


In order to recycle the orgs we need to be able to remove all code from the org so that it is just the basic org with minimal content.  In the previous blog post there was a simple form of this done to remove sample code that comes shipped in new developer orgs but in this post we will explain how to remove all the code and content that may have been added to the org during development.


Can’t we just use the Migration Tools and a destructiveChange.xml?

Unfortunately not!  While it may seem obvious just to create a destructiveChanges.xml that lists all of the content in the org and just run the deploy (undeploy really), this will not work if you have a more complex code base.  The migration tools are not good at resolving dependencies and relationships.  If you have references between pages, components,  static resources, custom fields, rollup fields and reports etc you may find that the undeploy fails as it does not resolve the dependencies correctly and hence cannot remove all the content listed.

To remove the content from the org we need to first find all the content that is in the org, remove any dependencies and then undeploy all of the content.

Retrieve of the Metadata Content

We can retrieve the content we want by specifying the items we want in a package.xml file but if we don’t know what content is in the org, how can we create the package.xml in the first place?  Although many of the types we can specify in the package.xml can be starred (<members>*</members>) which will return all of those types in the org, many types like reports or custom fields on standard objects do not support the starred syntax.  This poses a problem because how can we empty an org if we don’t know all of the items that need to be removed.  However, there are some features we can use to get the types and content available in an org.

The Salesforce Migration Tools have a task called sf:describeMetadata that will list all of the types that are available in an org.  To make this task easier to work with we created an ant macrodef for it:

This task will create a file, specified by the file attribute, that contains entries like the following for every type available in the org:

There is an additional task in the Salesforce Migration Tools that will allow you to find out all the instances of a specified type in an org called sf:listMetadata.  The output of this target is a file that contains the metadata for all instances of the the type specified.  The following is an example of the output of sf:listMetadata for the type objects:


Similar to the sf:describeMetadata task, we can create a macrodef that makes the sf:listMetadata task easier to use as it defaults some the attributes required and alters the output into a format that is easier for us to work with:


With these 2 metadata macros we can identify the entire contents of the org by listing the metadata for all types in the org.  However there is a complication we must deal with; some content like reports are contained in folders and the list metadata task cannot list all the content for all folders, it can only list the content for a specified folder using the folder attribute.  If we want to retrieve all of the content then we need to be able to identify all of the folders but currently the Salesforce Migration tools do not support this so we need another way to achieve it.  The Command Line Interface (CLI) from Dave Carroll is a great utility that can help us query the reports using SOQL.  This utility is excellent and I may do blog post in future covering its use in detail but for the moment we will just use it to query report content.

Download CLI and save it in the lib directory of your project.  Then add the following 2 tasks to your build.xml:


These tasks will allow SOQL queries to be run and the result stored in a property specified in the outputproperty attribute.  With the soql task it is possible to retrieve all the content from an org dynamically.  The following four tasks are wrapper tasks that use JavaScript to call the other tasks in order to retrieve all of the content from an org.  The target retrieve.all.metadata at the end simply uses these tasks to retieve the metadata listing for all content in the org into the temp directory:


The various metadata listing files can be used to create a package.xml file that can be used to retrieve the entire contents of the org.  The following target will create the package.xml and retrieve all of the content into the temp directory.

If you run this new retrieve.all.content target and then browse in the temp directory now you will see metadata files for all of the content in your org.

Break Dependencies in the Code / Metadata

Now that we have all of the content we can break all of the dependencies in the metadata so that we can undeploy all of the content.  This will leave a clean developer org that can be reused for future development without the need to create a new developer org.  

To break the dependencies we need to blank the code for triggers, classes, pages, components and formulas and deploy them to the org.  We can clear the code with regular expressions and simple XSLT operations.

The regular expression for clearing triggers is very simple, we simply need to remove all content between the first curly brace { and the closing curly brace }.  The following reset.triggers target adds a space to the start of every line in the trigger files, removes any comments, removes all line breaks and then removes any content after the first opening curly brace and replaces it with a closing brace, effectively clearing all the trigger content.

A very similar target can be used to clear classes, however this target needs to strip any @RestResource notation that may be at the top of the file.


The Visualforce pages and components can also be cleared using regular expressions but in these case we just replace the entire content of the file with empty <apex:page/> or <apex:component/> elements.  The following tasks are used for this purpose:


The formulas on custom fields can be cleared using an XSLT operation.  The formulas are not cleared really but we set them to return default primitive values so that there are no dependencies on other org content.  The following xslt file, saved as reset.formulas.xslt in the xslt directory, will reset the formulas of all custom fields in your org.

This XSLT can be applied to the object files to reset the formulas using the following target:

Now we have all the targets we need to reset the content we can create a target to deploy all of the cleared content, which will break all the dependencies.  

Once the deploy is complete, we can use an undeploy to remove all of the custom content which will leave the org clean of all content and ready for reuse.  In order to undeploy the content we need an empty package.xml and a destructiveChanges.xml listing the content that needs to be removed.  Creating an empty package.xml involves a very simple XSLT operation on the package.xml retrieved in the temp directory (save this file as empty.package.xml in the xslt directory):

We can create the destructiveChanges.xml with an XSLT operation also but this is a bit more complicated as we need to omit the Salesforce standard content that cannot be removed from an org.  The following XSLT file omits the standard content from the package.xml should be saved as destructive.changes.xslt in the xslt directory:

The above two XSLT files are used to create the package.xml and the destructiveChanges.xml that will remove all the custom content in the org.  The follow target removes all of the content:

Once this undeploy.content target is run the org is clean of all custom content is ready for reuse.  Although the steps to get this point may have seemed long winded and complicated, you now have a procedure that can be reused on any number of orgs so they can be recycled.

Although this blog post may seem long and somewhat complicated, the targets and tasks created will be applicable to all developer orgs and can be used a utility to recycle orgs.  As previously mentioned recycling orgs saves time and eliminates the need to configure orgs when starting new development work.


Leave a Reply