The following solution involves two popolar SCM (SVN and Git), an always-on server (I use Windows, you may want to opt for the cloud) and a few free tools. You will need the Force.com Migration Tool, Apache Ant, and Java JDK. Start by setting things up with the following checklist:
-
Java JDK - http://www.oracle.com/technetwork/java/javase/downloads/index.html
-
Apache Ant - http://ant.apache.org/manual/install.html
-
Force.com Migration Tool - http://www.salesforce.com/us/developer/docs/daas/Content/forcemigrationtool_install.htm
-
Shell (or the Git Bash) - http://cygwin.com/install.html
I'm using SVN, so an SVN command line client that support the server version (which is above 1.7) is also necessary.
-
SVN Client - http://www.sliksvn.com/en/download
The next things is setting up working folder and scripts, you'll have:
myWorkingFolder
build.properties - Connection info
build.xml - Retrieve instructions
myScript.sh
build.properties content:
# build.properties
sf.serverurl = https://www.salesforce.com
sf.username = usr@domain.ext
sf.password = F4ncy!Pwd
sf.directory = Org
build.xml content:
<project name="MyProject" default="test" basedir="." xmlns:sf="antlib:com.salesforce">
<property file="build.properties"/>
<property environment="env"/>
<target name="getOrg">
<mkdir dir="Org"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}"
metadataType="AccountCriteriaBasedSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="AccountOwnerSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="ApexClass"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="ApexComponent"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="ApexPage"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="ApexTrigger"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="AssignmentRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CallCenter"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}"
metadataType="CampaignCriteriaBasedSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CampaignOwnerSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CaseCriteriaBasedSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CaseOwnerSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Community"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}"
metadataType="ContactCriteriaBasedSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="ContactOwnerSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CustomApplication"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CustomApplicationComponent"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CustomLabels"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CustomObject"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}"
metadataType="CustomObjectOwnerSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CustomObjectTranslation"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CustomPageWebLink"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CustomSite"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="CustomTab"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Dashboard"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Document"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="EmailTemplate"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Flow"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Group"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="HomePageComponent"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="HomePageLayout"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Layout"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}"
metadataType="LeadCriteriaBasedSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="LeadOwnerSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Letterhead"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}"
metadataType="OpportunityCriteriaBasedSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}"
metadataType="OpportunityOwnerSharingRule"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="PermissionSet"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Portal"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Profile"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Queue"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="RemoteSiteSetting"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Report"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="ReportType"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Role"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Scontrol"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="StaticResource"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Workflow"
retrieveTarget="${sf.directory}"/>
<sf:bulkRetrieve username="${sf.username}" password="${sf.password}"
serverurl="${sf.serverurl}" metadataType="Settings"
retrieveTarget="${sf.directory}"/>
</target>
</project>
run.cmd content:
svn checkout https://localhost:81/svn/myorg/trunk/ Org --depth=infinity --username bot
--password POOr+9jC --non-interactive --trust-server-cert
call ant getOrg
cd Org
svn propedit svn:ignore *.xml .
svn add --depth=infinity *
svn commit -m "Scheduled commit" --username bot --password B0tP4$$:)
Open the bash, run the the scripts, the results should be the following:
myWorkingFolder/
myOrg/ - Project
myOrg/.svn - SVN stuff (or .git for git stuff)
myOrg/*.* - Versioned metadata
If you want to schedule the script in Windows, all you need to do is open the command prompt; and run the bash executable passing the script path as parameter, note that the whole process takes place in the working directory.
Please note: the script is for demonstration purpose only and comes with no guarantees. Also, this may be out of date or I could have made mistakes Please leave a comment below and I'll be happy to fix it for you.