Last active
November 24, 2020 22:37
-
-
Save mattandneil/94ff2f14b42c8d8e7d4e8008d591990c to your computer and use it in GitHub Desktop.
Salesforce Org Snapshot - Ant Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<macrodef name="snapshot" description="Snapshots all metadata in an organization - Revision 22"> | |
<attribute name="username" /> | |
<attribute name="password" /> | |
<attribute name="serverurl" default="https://login.salesforce.com" /> | |
<attribute name="outPath" default="temp/snapshot" description="Directory to write snapshot." /> | |
<sequential> | |
<!-- prompt user to confirm --> | |
<input message="This snapshot overwrites the following directory. Are you sure?" validargs="@{outPath}" /> | |
<!-- cache to avoid repeat logins --> | |
<local name="login.tmp" /> | |
<tempfile property="login.tmp" prefix="login" suffix=".tmp" createfile="true" deleteonexit="true" /> | |
<local name="describeMetadataResult.tmp" /> | |
<tempfile property="describeMetadataResult.tmp" prefix="describeMetadataResult" suffix=".tmp" createfile="true" deleteonexit="true" /> | |
<!-- determines org shape --> | |
<record name="${login.tmp}" action="start" /> | |
<sf:describeMetadata serverurl="@{serverurl}" username="@{username}" password="@{password}" resultFilePath="${describeMetadataResult.tmp}" trace="true" /> | |
<record name="${login.tmp}" action="stop" /> | |
<!-- parse endpoint --> | |
<local name="loginUrl" /> | |
<loadfile property="loginUrl" srcFile="${login.tmp}"> | |
<filterchain><tokenfilter><filetokenizer/><replaceregex flags="gs" pattern=".*(https://[^/]+).*" replace="\1" /></tokenfilter></filterchain> | |
</loadfile> | |
<!-- parse session --> | |
<local name="sessionId" /> | |
<loadfile property="sessionId" srcFile="${login.tmp}"> | |
<filterchain><tokenfilter><filetokenizer/><replaceregex flags="gs" pattern=".*<sessionId>([^<]+)</sessionId>.*" replace="\1" /></tokenfilter></filterchain> | |
</loadfile> | |
<local name="metadataTypes.tmp" /> | |
<tempfile property="metadataTypes.tmp" prefix="metadataTypes" suffix=".tmp" createfile="true" deleteonexit="true" /> | |
<!-- clean metadata descriptions --> | |
<concat destFile="${metadataTypes.tmp}"> | |
<fileset file="${describeMetadataResult.tmp}" /> | |
<filterchain> | |
<linecontainsregexp><regexp pattern="ChildObjects|XMLName" /></linecontainsregexp> | |
<tokenfilter><replacestring from="," to="${line.separator}"/></tokenfilter> | |
<tokenfilter><replacestring from="ChildObjects: " to=""/></tokenfilter> | |
<tokenfilter><replacestring from="XMLName: " to=""/></tokenfilter> | |
<tokenfilter><replacestring from="*" to=""/></tokenfilter> | |
<tokenfilter><ignoreblank/></tokenfilter> | |
<sortfilter/> | |
</filterchain> | |
</concat> | |
<macrodef name="listMetadataForSnapshot"> | |
<attribute name="loginUrl" /> | |
<attribute name="sessionId" /> | |
<attribute name="metadataType" /> | |
<attribute name="folder" default="" /> | |
<sequential> | |
<echo>Listing each @{metadataType} @{folder}</echo> | |
<local name="listMetadataResult.tmp" /> | |
<tempfile property="listMetadataResult.tmp" prefix="@{metadataType}" suffix=".tmp" createfile="true" deleteonexit="true" /> | |
<echo file="${listMetadataResult.tmp}" /> | |
<sf:listMetadata serverurl="@{loginUrl}" sessionid="@{sessionId}" metadataType="@{metadataType}" resultFilePath="${listMetadataResult.tmp}" folder="@{folder}" /> | |
<concat destFile="@{outPath}/package.xml" append="true"> | |
<header filtering="false"><![CDATA[<types><name>@{metadataType}</name>]]></header> | |
<fileset file="${listMetadataResult.tmp}" /> | |
<filterchain> | |
<linecontains><contains value="FullName/Id"/></linecontains> | |
<tokenfilter> | |
<replaceregex pattern="FullName/Id: ([^/]+)/([^/]+)/([^/]+)" replace="<members>\1/\2</members>" /> | |
<replaceregex pattern="FullName/Id: ([^/]+)\.([^/]+)/([^/]+)" replace="<members>\1.\2</members>" /> | |
<replaceregex pattern="FullName/Id: ([^/]+)/([^/]+)/" replace="<members>\1</members>" /> | |
<replaceregex pattern="FullName/Id: ([^/]+)/([^/]+)" replace="<members>\1</members>" /> | |
<replaceregex pattern="FullName/Id: ([^/]+)/" replace="<members>\1</members>" /> | |
</tokenfilter> | |
<tokenfilter> | |
<filetokenizer /> | |
<scriptfilter language="javascript">with (new JavaImporter(java.net, java.io)) { | |
if ('@{folder}') { | |
self.setToken(self.getToken() + | |
project.getProperty('line.separator') + | |
'<members>@{folder}</members>') | |
;} | |
}</scriptfilter> | |
</tokenfilter> | |
<sortfilter/> | |
</filterchain> | |
<footer filtering="false"><![CDATA[</types>]]></footer> | |
</concat> | |
</sequential> | |
</macrodef> | |
<macrodef name="listFolderForSnapshot"> | |
<attribute name="loginUrl" /> | |
<attribute name="sessionId" /> | |
<attribute name="folderType" /> | |
<attribute name="metadataType" /> | |
<sequential> | |
<echo>Listing all @{folderType}s</echo> | |
<local name="listFolderResult.tmp" /> | |
<tempfile property="listFolderResult.tmp" prefix="@{metadataType}" suffix=".tmp" createfile="true" deleteonexit="true" /> | |
<echo file="${listFolderResult.tmp}" /> | |
<sf:listMetadata serverurl="@{loginUrl}" sessionid="@{sessionId}" metadataType="@{folderType}" resultFilePath="${listFolderResult.tmp}" /> | |
<loadfile srcFile="${listFolderResult.tmp}" property="file" /> | |
<loadfile property=""> | |
<fileset file="${listFolderResult.tmp}" /> | |
<filterchain> | |
<linecontains><contains value="FullName/Id"/></linecontains> | |
<tokenfilter> | |
<replaceregex pattern="FullName/Id: " replace="" /> | |
<replaceregex pattern="/.*" replace="" /> | |
</tokenfilter> | |
<sortfilter/> | |
<scriptfilter language="javascript"> | |
var macro = project.createTask('listMetadataForSnapshot'); | |
macro.setDynamicAttribute('loginurl', '${loginUrl}'); | |
macro.setDynamicAttribute('sessionid', '${sessionId}'); | |
macro.setDynamicAttribute('metadatatype', '@{metadataType}'); | |
macro.setDynamicAttribute('folder', self.getToken()); | |
macro.execute(); //dynamic attributes are lowercase insistent | |
</scriptfilter> | |
<tokenfilter> | |
<replaceregex pattern="FullName/Id: " replace="" /> | |
<replaceregex pattern="/.*" replace="" /> | |
</tokenfilter> | |
</filterchain> | |
</loadfile> | |
</sequential> | |
</macrodef> | |
<!-- reset working directory --> | |
<delete dir="@{outPath}" /> | |
<mkdir dir="@{outPath}" /> | |
<!-- open package definition --> | |
<echo file="@{outPath}/package.xml"><![CDATA[<Package>]]></echo> | |
<!-- iterates over each metadata type --> | |
<loadfile property="" srcFile="${metadataTypes.tmp}"> | |
<filterchain> | |
<!-- exclude folders and standard value sets --> | |
<linecontainsregexp negate="true"> | |
<regexp pattern="StandardValueSet|Dashboard|Document|EmailTemplate|Report" /> | |
</linecontainsregexp> | |
<scriptfilter language="javascript"> | |
var macro = project.createTask('listMetadataForSnapshot'); | |
macro.setDynamicAttribute('loginurl', '${loginUrl}'); | |
macro.setDynamicAttribute('sessionid', '${sessionId}'); | |
macro.setDynamicAttribute('metadatatype', self.getToken()); | |
macro.execute(); //dynamic attributes are lowercase insistent | |
</scriptfilter> | |
</filterchain> | |
</loadfile> | |
<listFolderForSnapshot loginUrl="${loginUrl}" sessionId="${sessionId}" folderType="EmailFolder" metadataType="EmailTemplate" /> | |
<listFolderForSnapshot loginUrl="${loginUrl}" sessionId="${sessionId}" folderType="ReportFolder" metadataType="Report" /> | |
<listFolderForSnapshot loginUrl="${loginUrl}" sessionId="${sessionId}" folderType="DocumentFolder" metadataType="Document" /> | |
<listFolderForSnapshot loginUrl="${loginUrl}" sessionId="${sessionId}" folderType="DashboardFolder" metadataType="Dashboard" /> | |
<!-- shim standard value sets --> | |
<echo append="true" file="@{outPath}/package.xml"><![CDATA[ | |
<types> | |
<name>StandardValueSet</name> | |
<members>AccountContactMultiRoles</members> | |
<members>AccountContactRole</members> | |
<members>AccountOwnership</members> | |
<members>AccountRating</members> | |
<members>AccountType</members> | |
<members>AddressCountryCode</members> | |
<members>AddressStateCode</members> | |
<members>AssetStatus</members> | |
<members>CampaignMemberStatus</members> | |
<members>CampaignStatus</members> | |
<members>CampaignType</members> | |
<members>CaseContactRole</members> | |
<members>CaseOrigin</members> | |
<members>CasePriority</members> | |
<members>CaseReason</members> | |
<members>CaseStatus</members> | |
<members>CaseType</members> | |
<members>ContactRole</members> | |
<members>ContractContactRole</members> | |
<members>ContractStatus</members> | |
<members>EntitlementType</members> | |
<members>EventSubject</members> | |
<members>EventType</members> | |
<members>FiscalYearPeriodName</members> | |
<members>FiscalYearPeriodPrefix</members> | |
<members>FiscalYearQuarterName</members> | |
<members>FiscalYearQuarterPrefix</members> | |
<members>IdeaCategory</members> | |
<members>IdeaMultiCategory</members> | |
<members>IdeaStatus</members> | |
<members>IdeaThemeStatus</members> | |
<members>Industry</members> | |
<members>InvoiceStatus</members> | |
<members>LeadSource</members> | |
<members>LeadStatus</members> | |
<members>OpportunityCompetitor</members> | |
<members>OpportunityStage</members> | |
<members>OpportunityType</members> | |
<members>OrderStatus</members> | |
<members>OrderType</members> | |
<members>PartnerRole</members> | |
<members>Product2Family</members> | |
<members>QuestionOrigin</members> | |
<members>QuickTextCategory</members> | |
<members>QuickTextChannel</members> | |
<members>QuoteStatus</members> | |
<members>RoleInTerritory2</members> | |
<members>SalesTeamRole</members> | |
<members>Salutation</members> | |
<members>ServiceContractApprovalStatus</members> | |
<members>SocialPostClassification</members> | |
<members>SocialPostEngagementLevel</members> | |
<members>SocialPostReviewedStatus</members> | |
<members>SolutionStatus</members> | |
<members>TaskPriority</members> | |
<members>TaskStatus</members> | |
<members>TaskSubject</members> | |
<members>TaskType</members> | |
<members>WorkOrderLineItemStatus</members> | |
<members>WorkOrderPriority</members> | |
<members>WorkOrderStatus</members> | |
</types> | |
]]></echo> | |
<!-- close package definition and retrieve --> | |
<echo append="true" file="@{outPath}/package.xml"><![CDATA[</Package>]]></echo> | |
<sf:retrieve serverUrl="${loginUrl}" sessionId="${sessionId}" unpackaged="@{outPath}/package.xml" retrieveTarget="@{outPath}" /> | |
</sequential> | |
</macrodef> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment