Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

I would like to clear out my development org of all artefacts on a regular basis and then do a deploy of the development package from my local source.

I realise there are retrieve and list tasks available as well as the destructive changes file that I could make use of. Unfortunately, I have found that constructing an appropriate build file to co-ordinate all this has become somewhat confusing. The radical approach might be spinning up a new org each time but that seems rather wasteful.

All suggestions would be greatly appreciated

share|improve this question

2 Answers 2

up vote 12 down vote accepted

You can do this using just the out-of-the-box Force.com Migration Tool.

As you noted, destroying metadata components is achieved with a destructiveChanges.xml definition. However this differs from package.xml in that it doesn't support wildcards (*) - so the intermediate hurdle is the generation of an explicit definition containing the names of all the metadata to destroy.

This explicit definition can be generated by putting all the organization's metadata into a named package and performing a retrieve, which converts the wildcards into actual component names.

Once you have the component names, you can deploy your destructiveChanges.xml with an empty package.xml and this will trash all the appropriate metadata in a single transaction.

Here's one I prepared earlier - drop this into your build.xml then run ant purge:

<target name="purge" description="Purges an organization of most customizations and components">
    <!-- Clean up any previous purge -->
    <delete dir="purge" />
    <mkdir dir="purge" />

    <!-- Prepare a wildcard package definition with as many metadata types as possible -->
    <echo file="purge/package.xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
        <Package xmlns="http://soap.sforce.com/2006/04/metadata">
            <types><members>*</members><name>AccountCriteriaBasedSharingRule</name></types>
            <types><members>*</members><name>AccountOwnerSharingRule</name></types>
            <types><members>*</members><name>AccountSharingRules</name></types>
            <types><members>*</members><name>AnalyticSnapshot</name></types>
            <types><members>*</members><name>ApexClass</name></types>
            <types><members>*</members><name>ApexComponent</name></types>
            <types><members>*</members><name>ApexPage</name></types>
            <types><members>*</members><name>ApexTrigger</name></types>
            <types><members>*</members><name>ApexTriggerCoupling</name></types>
            <types><members>*</members><name>AuthProvider</name></types>
            <types><members>*</members><name>BusinessProcess</name></types>
            <types><members>*</members><name>CallCenter</name></types>
            <types><members>*</members><name>CampaignCriteriaBasedSharingRule</name></types>
            <types><members>*</members><name>CampaignOwnerSharingRule</name></types>
            <types><members>*</members><name>CampaignSharingRules</name></types>
            <types><members>*</members><name>CaseCriteriaBasedSharingRule</name></types>
            <types><members>*</members><name>CaseOwnerSharingRule</name></types>
            <types><members>*</members><name>CaseSharingRules</name></types>
            <types><members>*</members><name>CompactLayout</name></types>
            <types><members>*</members><name>ConnectedApp</name></types>
            <types><members>*</members><name>ContactCriteriaBasedSharingRule</name></types>
            <types><members>*</members><name>ContactOwnerSharingRule</name></types>
            <types><members>*</members><name>ContactSharingRules</name></types>
            <types><members>*</members><name>CustomApplication</name></types>
            <types><members>*</members><name>CustomApplicationComponent</name></types>
            <types><members>*</members><name>CustomField</name></types>
            <types><members>*</members><name>CustomLabel</name></types>
            <types><members>*</members><name>CustomLabels</name></types>
            <types><members>*</members><name>CustomObject</name></types>
            <types><members>*</members><name>CustomObjectCriteriaBasedSharingRule</name></types>
            <types><members>*</members><name>CustomObjectOwnerSharingRule</name></types>
            <types><members>*</members><name>CustomObjectSharingRules</name></types>
            <types><members>*</members><name>CustomObjectTranslation</name></types>
            <types><members>*</members><name>CustomPageWebLink</name></types>
            <types><members>*</members><name>CustomTab</name></types>
            <types><members>*</members><name>Dashboard</name></types>
            <types><members>*</members><name>DataCategoryGroup</name></types>
            <types><members>*</members><name>Document</name></types>
            <types><members>*</members><name>EmailTemplate</name></types>
            <types><members>*</members><name>FieldSet</name></types>
            <types><members>*</members><name>FlexiPage</name></types>
            <types><members>*</members><name>Flow</name></types>
            <types><members>*</members><name>Group</name></types>
            <types><members>*</members><name>LeadCriteriaBasedSharingRule</name></types>
            <types><members>*</members><name>LeadOwnerSharingRule</name></types>
            <types><members>*</members><name>LeadSharingRules</name></types>
            <types><members>*</members><name>Letterhead</name></types>
            <types><members>*</members><name>ListView</name></types>
            <types><members>*</members><name>NamedFilter</name></types>
            <types><members>*</members><name>OpportunityCriteriaBasedSharingRule</name></types>
            <types><members>*</members><name>OpportunityOwnerSharingRule</name></types>
            <types><members>*</members><name>OpportunitySharingRules</name></types>
            <types><members>*</members><name>RecordType</name></types>
            <types><members>*</members><name>RemoteSiteSetting</name></types>
            <types><members>*</members><name>Report</name></types>
            <types><members>*</members><name>ReportType</name></types>
            <types><members>*</members><name>SamlSsoConfig</name></types>
            <types><members>*</members><name>Scontrol</name></types>
            <types><members>*</members><name>SharingReason</name></types>
            <types><members>*</members><name>StaticResource</name></types>
            <types><members>*</members><name>ValidationRule</name></types>
            <types><members>*</members><name>WebLink</name></types>
            <types><members>*</members><name>Workflow</name></types>
            <types><members>*</members><name>WorkflowAlert</name></types>
            <types><members>*</members><name>WorkflowApex</name></types>
            <types><members>*</members><name>WorkflowChatterPost</name></types>
            <types><members>*</members><name>WorkflowFieldUpdate</name></types>
            <types><members>*</members><name>WorkflowKnowledgePublish</name></types>
            <types><members>*</members><name>WorkflowOutboundMessage</name></types>
            <types><members>*</members><name>WorkflowQuickCreate</name></types>
            <types><members>*</members><name>WorkflowRule</name></types>
            <types><members>*</members><name>WorkflowSend</name></types>
            <types><members>*</members><name>WorkflowTask</name></types>
            <version>29.0</version>
        </Package>
    ]]></echo>

    <!--
     ! These metadata types are either unpackageable, or tricky because
     ! they are coupled to profiles (app) or users (permissionsets):
     ! <types><members>*</members><name>ApprovalProcess</name></types>
     ! <types><members>*</members><name>AssignmentRule</name></types>
     ! <types><members>*</members><name>AssignmentRules</name></types>
     ! <types><members>*</members><name>AutoResponseRule</name></types>
     ! <types><members>*</members><name>AutoResponseRules</name></types>
     ! <types><members>*</members><name>Community</name></types>
     ! <types><members>*</members><name>CustomSite</name></types>
     ! <types><members>*</members><name>EscalationRule</name></types>
     ! <types><members>*</members><name>EscalationRules</name></types>
     ! <types><members>*</members><name>HomePageComponent</name></types>
     ! <types><members>*</members><name>HomePageLayout</name></types>
     ! <types><members>*</members><name>InstalledPackage</name></types>
     ! <types><members>*</members><name>Layout</name></types>
     ! <types><members>*</members><name>PermissionSet</name></types>
     ! <types><members>*</members><name>Profile</name></types>
     ! <types><members>*</members><name>Queue</name></types>
     ! <types><members>*</members><name>QuickAction</name></types>
     ! <types><members>*</members><name>Role</name></types>
     ! <types><members>*</members><name>Settings</name></types>
     ! <types><members>*</members><name>SynonymDictionary</name></types>
     ! <types><members>*</members><name>WorkflowActionFlow</name></types>
     !-->

    <!-- Retrieve the wildcard package definition -->
    <sf:retrieve
    username="${sf.username}"
    password="${sf.password}"
    serverurl="https://login.salesforce.com"
    retrieveTarget="purge"
    unpackaged="purge/package.xml"
    pollWaitMillis="1000" />

    <!--
     ! These components retrieve ok, but attempting to deploy them throws:
     ! "Cannot create workflow directly; must create the CustomObject first"
     ! We delete them so they don't make their way into destructiveChanges.xml
     !-->
    <delete file="purge/workflows/Question.workflow" />
    <delete file="purge/workflows/Reply.workflow" />
    <delete file="purge/workflows/SocialPersona.workflow" />
    <delete file="purge/workflows/SocialPost.workflow" />

    <!-- Name the package definition -->
    <replace file="purge/package.xml">
        <replacetoken><![CDATA[</version>]]></replacetoken>
        <replacevalue><![CDATA[</version><fullName>Purge</fullName>]]></replacevalue>
    </replace>

    <!-- Re-deploy the now-named wildcard package definition -->
    <sf:deploy
    username="${sf.username}"
    password="${sf.password}"
    serverurl="https://login.salesforce.com"
    deployRoot="purge"
    purgeOnDelete="true"
    pollWaitMillis="1000" />

    <!-- Retrieve by name, giving us an explicit package definition -->
    <sf:retrieve
    username="${sf.username}"
    password="${sf.password}"
    serverurl="https://login.salesforce.com"
    retrieveTarget="purge"
    packageNames="Purge"
    pollWaitMillis="1000" />

    <!--
     ! Trash local components: we only needed them to get an explicit package definition.
     ! Now we turn the explicit package definition into explicit destructive changes, and
     ! blank out the package definition.
     !-->
    <delete includeEmptyDirs="true" dir="purge" includes="**/*" excludes="*.xml" />
    <copy file="purge/package.xml" tofile="purge/destructiveChanges.xml" />
    <echo file="purge/package.xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
        <Package xmlns="http://soap.sforce.com/2006/04/metadata">
            <version>29.0</version>
        </Package>
    ]]></echo>

    <!-- Perform explicit deploy over the top of the org which should delete all components -->
    <sf:deploy
    username="${sf.username}"
    password="${sf.password}"
    serverurl="https://login.salesforce.com"
    deployRoot="purge"
    purgeOnDelete="true"
    pollWaitMillis="1000" />

    <!-- Tidy up after ourselves -->
    <delete dir="purge" />
</target>

(You will need to set sf.username and sf.password as properties or command line parameters)

If the task is a little too long to read, it boils down to a four step process:

  1. use a (wildcard) package.xml to retrieve all components in the org,

  2. re-deploy those components using a named package as a handle,

  3. retrieve the now-named package to convert your wildcards into an explicit package definition,

  4. turn the (explicit) package.xml into destructiveChanges.xml and deploy it, which deletes all components named within

To avoid the first three steps, it might have been tempting to use the listMetadata task to generate the destructiveChanges.xml, however its output is not XML nor the deployable format required.

Additionally there are some tricky metadata types that are coupled to Profiles (eg CustomApplication) or coupled to Users (eg PermissionSet). If these give you trouble, you can leave them out of the purge.

Note: per comment, make sure Force.com isn't the 'Default App' on any profiles before running

share|improve this answer
1  
Thanks very much for this! - after removing the default force.com application from my org, it worked first time out of the box. –  max Jan 20 at 18:04
    
Hello there, could you advise where did you get from or how did you generate a wildcard package definition with as many metadata types as possible list? –  Daniel Sokolowski Sep 3 at 1:42

There is an undeploy script here that may be of some help to you.

You could also consider making use of developer sandboxes which you can delete / refresh yourself, although there are some differences between developer sandboxes and true DE orgs.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.