Last active
December 29, 2022 17:11
-
-
Save afawcett/5843110 to your computer and use it in GitHub Desktop.
Defines some macros around sf:deploy to install and uninstall packages.
This file contains 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
<!-- TODO: Review Ant v1.8 local properties --> | |
<project xmlns:sf="antlib:com.salesforce"> | |
<!-- Download from Salesforce Tools page under Setup --> | |
<typedef | |
uri="antlib:com.salesforce" | |
resource="com/salesforce/antlib.xml" | |
classpath="${basedir}/lib/ant-salesforce.jar"/> | |
<!-- Download from http://sourceforge.net/projects/ant-contrib/files/ant-contrib/1.0b3/ --> | |
<taskdef | |
resource="net/sf/antcontrib/antlib.xml" | |
classpath="${basedir}/lib/ant-contrib-1.0b3.jar" | |
/> | |
<!-- Download from https://code.google.com/p/missing-link/ --> | |
<taskdef | |
name="http" | |
classname="org.missinglink.ant.task.http.HttpClientTask" | |
classpath="${basedir}/lib/ml-ant-http-1.1.3.jar"/> | |
<!-- Download from http://www.oopsconsultancy.com/software/xmltask/ --> | |
<taskdef | |
name="xmltask" | |
classname="com.oopsconsultancy.xmltask.ant.XmlTask" | |
classpath="${basedir}/lib/xmltask.jar"/> | |
<macrodef name="installPackage" description="Installs the given managed package"> | |
<attribute name="namespace" description="Namespace of managed package to install."/> | |
<attribute name="version" description="Version of managed package to install."/> | |
<attribute name="packagePassword" description="Password used to install the pacakge. Optional." default=""/> | |
<attribute name="username" description="Salesforce user name."/> | |
<attribute name="password" description="Salesforce password."/> | |
<sequential> | |
<!-- Generate optional <password> element? --> | |
<if><equals arg1="@{packagePassword}" arg2=""/> | |
<then><property name="passwordElement" value=""/></then> | |
<else><property name="passwordElement" value="<password>@{packagePassword}</password>"/></else> | |
</if> | |
<!-- Generate working folder and metadata files representing the package to install --> | |
<delete dir="${basedir}/installdeploy"/> | |
<mkdir dir="${basedir}/installdeploy"/> | |
<mkdir dir="${basedir}/installdeploy"/> | |
<mkdir dir="${basedir}/installdeploy/installedPackages"/> | |
<echo file="${basedir}/installdeploy/package.xml"><![CDATA[<Package xmlns="http://soap.sforce.com/2006/04/metadata"><types><members>@{namespace}</members><name>InstalledPackage</name></types><version>28.0</version></Package>]]></echo> | |
<echo file="${basedir}/installdeploy/installedPackages/@{namespace}.installedPackage"><![CDATA[<InstalledPackage xmlns="http://soap.sforce.com/2006/04/metadata"><versionNumber>@{version}</versionNumber>${passwordElement}</InstalledPackage>]]></echo> | |
<sf:deploy deployRoot="${basedir}/installdeploy" username="@{username}" password="@{password}"/> | |
</sequential> | |
</macrodef> | |
<macrodef name="uninstallPackage" description="Uninstalls the given managed package"> | |
<attribute name="namespace" description="Namespace of managed package to install."/> | |
<attribute name="username" description="Salesforce user name."/> | |
<attribute name="password" description="Salesforce password."/> | |
<sequential> | |
<!-- Generate working folder and metadata files representing the package to uninstall --> | |
<delete dir="${basedir}/installdeploy"/> | |
<mkdir dir="${basedir}/installdeploy"/> | |
<mkdir dir="${basedir}/installdeploy"/> | |
<mkdir dir="${basedir}/installdeploy/installedPackages"/> | |
<echo file="${basedir}/installdeploy/package.xml"><![CDATA[<Package xmlns="http://soap.sforce.com/2006/04/metadata"><version>28.0</version></Package>]]></echo> | |
<echo file="${basedir}/installdeploy/destructiveChanges.xml"><![CDATA[<Package xmlns="http://soap.sforce.com/2006/04/metadata"><types><members>@{namespace}</members><name>InstalledPackage</name></types><version>28.0</version></Package>]]></echo> | |
<echo file="${basedir}/installdeploy/installedPackages/@{namespace}.installedPackage"><![CDATA[<InstalledPackage xmlns="http://soap.sforce.com/2006/04/metadata"><versionNumber>@{version}</versionNumber></InstalledPackage>]]></echo> | |
<sf:deploy deployRoot="${basedir}/installdeploy" username="@{username}" password="@{password}"/> | |
</sequential> | |
</macrodef> | |
<!-- Deploys the given file as a static resource via the sf:deploy Ant task (Metadata API) --> | |
<macrodef name="staticResource"> | |
<attribute name="username" description="Salesforce user name."/> | |
<attribute name="password" description="Salesforce password."/> | |
<attribute name="developername" description="Developer name for the Static Resource."/> | |
<attribute name="file" description="Source file for the static resource."/> | |
<attribute name="contenttype" description="Content type of the Static Resource."/> | |
<sequential> | |
<!-- Generate working folder and metadata files representing the package to uninstall --> | |
<delete dir="${basedir}/staticresourcedeploy"/> | |
<mkdir dir="${basedir}/staticresourcedeploy"/> | |
<mkdir dir="${basedir}/staticresourcedeploy"/> | |
<mkdir dir="${basedir}/staticresourcedeploy/staticresources"/> | |
<echo file="${basedir}/staticresourcedeploy/package.xml"><![CDATA[<Package xmlns="http://soap.sforce.com/2006/04/metadata"><types><members>*</members><name>StaticResource</name></types><version>29.0</version></Package>]]></echo> | |
<copy file="@{file}" tofile="${basedir}/staticresourcedeploy/staticresources/@{developername}.resource"/> | |
<echo file="${basedir}/staticresourcedeploy/staticresources/@{developername}.resource-meta.xml"><![CDATA[<StaticResource xmlns="http://soap.sforce.com/2006/04/metadata"><cacheControl>Private</cacheControl><contentType>@{contentType}</contentType></StaticResource>]]></echo> | |
<sf:deploy deployRoot="${basedir}/staticresourcedeploy" username="@{username}" password="@{password}"/> | |
</sequential> | |
</macrodef> | |
<!-- Provides access to the Salesforce Tooling REST API ExecuteAnnoynmous resource --> | |
<macrodef name="executeApex" description="Provides access to the Salesforce Tooling REST API ExecuteAnnoynmous resource"> | |
<attribute name="username" description="Salesforce user name."/> | |
<attribute name="password" description="Salesforce password."/> | |
<attribute name="resultprefix" description="Property name prefix used for properties containing response data" default="executeAnonymousResponse"/> | |
<attribute name="failonerror" description="If the execute fails then fail the Ant script" default="true"/> | |
<text name="apexcode"/> | |
<sequential> | |
<!-- Login --> | |
<login username="@{username}" password="@{password}" serverurl="serverUrl" sessionId="sessionId"/> | |
<!-- Execute Apex via Tooling API /executeAnonymous resource --> | |
<http url="https://na11.salesforce.com/services/data/v29.0/tooling/executeAnonymous" method="GET" entityProperty="executeAnonymousResponse" statusProperty="loginResponseStatus"> | |
<headers> | |
<header name="Authorization" value="Bearer ${sessionId}"/> | |
</headers> | |
<query> | |
<parameter name="anonymousBody" value="@{apexcode}"/> | |
</query> | |
</http> | |
<!-- Parse JSON response and set properites --> | |
<script language="javascript"> | |
var response = eval('('+project.getProperty('executeAnonymousResponse')+')'); | |
for(field in response) | |
project.setProperty('@{resultprefix}.' + field, response[field]); | |
</script> | |
<!-- Fail on error?--> | |
<if> | |
<and> | |
<equals arg1="@{failonerror}" arg2="true"/> | |
<equals arg1="${@{resultprefix}.success}" arg2="false"/> | |
</and> | |
<then> | |
<if> | |
<equals arg1="${@{resultprefix}.compiled}" arg2="false"/> | |
<then> | |
<fail message="${@{resultprefix}.line}:${@{resultprefix}.column} ${@{resultprefix}.compileProblem}"/> | |
</then> | |
<else> | |
<fail message="${@{resultprefix}.exceptionMessage} ${@{resultprefix}.exceptionStackTrace}"/> | |
</else> | |
</if> | |
</then> | |
</if> | |
</sequential> | |
</macrodef> | |
<!-- Provides access to the Salesforce Tooling REST API StaticResource resource --> | |
<macrodef name="staticResource.toolingapi" description="Provides access to the Salesforce Tooling REST API StaticResource resource"> | |
<attribute name="username" description="Salesforce user name."/> | |
<attribute name="password" description="Salesforce password."/> | |
<attribute name="developername" description="Developer name for the Static Resource."/> | |
<attribute name="body" description="Base64 encoded data for the Static Resource."/> | |
<attribute name="contenttype" description="Content type of the Static Resource."/> | |
<sequential> | |
<!-- Login --> | |
<login username="@{username}" password="@{password}" serverurl="serverUrl" sessionId="sessionId"/> | |
<!-- Create the StaticResource (later versions of this macro can support other operations) --> | |
<http url="https://na11.salesforce.com/services/data/v29.0/tooling/sobjects/StaticResource/" printresponse="true" printrequest="true" expected="201" method="POST" entityProperty="executeAnonymousResponse" statusProperty="loginResponseStatus"> | |
<headers> | |
<header name="Content-Type" value="application/json"/> | |
<header name="Authorization" value="Bearer ${sessionId}"/> | |
</headers> | |
<entity> | |
{ | |
"Name": "@{developerName}", | |
"Body": "@{body}", | |
"ContentType" : "@{contentType}" | |
} | |
</entity> | |
</http> | |
</sequential> | |
</macrodef> | |
<!-- Login into Salesforce and return the session Id and serverUrl --> | |
<macrodef name="login"> | |
<attribute name="username" description="Salesforce user name."/> | |
<attribute name="password" description="Salesforce password."/> | |
<attribute name="serverurl" description="Server Url property."/> | |
<attribute name="sessionId" description="Session Id property."/> | |
<sequential> | |
<!-- Obtain Session Id via Login SOAP service --> | |
<http url="https://login.salesforce.com/services/Soap/c/29.0" method="POST" failonunexpected="false" entityProperty="loginResponse" statusProperty="loginResponseStatus"> | |
<headers> | |
<header name="Content-Type" value="text/xml"/> | |
<header name="SOAPAction" value="login"/> | |
</headers> | |
<entity> | |
<![CDATA[ | |
<env:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'> | |
<env:Body> | |
<sf:login xmlns:sf='urn:enterprise.soap.sforce.com'> | |
<sf:username>@{username}</sf:username> | |
<sf:password>@{password}</sf:password> | |
</sf:login> | |
</env:Body> | |
</env:Envelope> | |
]]> | |
</entity> | |
</http> | |
<!-- Parse response --> | |
<xmltask destbuffer="loginResponseBuffer"> | |
<insert path="/">${loginResponse}</insert> | |
</xmltask> | |
<if> | |
<!-- Success? --> | |
<equals arg1="${loginResponseStatus}" arg2="200"/> | |
<then> | |
<!-- Parse sessionId and serverUrl --> | |
<xmltask sourcebuffer="loginResponseBuffer" failWithoutMatch="true"> | |
<copy path="/*[local-name()='Envelope']/*[local-name()='Body']/:loginResponse/:result/:sessionId/text()" property="@{sessionId}"/> | |
<copy path="/*[local-name()='Envelope']/*[local-name()='Body']/:loginResponse/:result/:serverUrl/text()" property="@{serverUrl}"/> | |
</xmltask> | |
</then> | |
<else> | |
<!-- Parse login error message and fail build --> | |
<xmltask sourcebuffer="loginResponseBuffer" failWithoutMatch="true"> | |
<copy path="/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='Fault']/*[local-name()='faultstring']/text()" property="faultString"/> | |
</xmltask> | |
<fail message="${faultString}"/> | |
</else> | |
</if> | |
</sequential> | |
</macrodef> | |
<!-- Base64 encode a files data --> | |
<macrodef name="base64encode"> | |
<attribute name="file" description="File to base 64 encode."/> | |
<attribute name="base64" description="Property to store the base 64 encoded data."/> | |
<sequential> | |
<loadfile property="filedata" srcFile="@{file}"/> | |
<script language="javascript"> | |
importClass(javax.xml.bind.DatatypeConverter); | |
project.setProperty('@{base64}', | |
DatatypeConverter.printBase64Binary( | |
new java.lang.String(project.getProperty('filedata')).getBytes("UTF-8"))); | |
</script> | |
</sequential> | |
</macrodef> | |
<!-- Provides access to the Salesforce REST API for a SOQL query --> | |
<macrodef name="runQuery" description="Run database query"> | |
<attribute name="sessionId" description="Salesforce user name."/> | |
<attribute name="serverUrl" description="Salesforce url."/> | |
<attribute name="query" description="Salesforce password."/> | |
<attribute name="queryResult" description="Query result property name"/> | |
<sequential> | |
<!-- Extract host/instance name from the serverUrl returned from the login response --> | |
<propertyregex property="host" | |
input="${serverUrl}" | |
regexp="^((http[s]?|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$" | |
select="\3" | |
casesensitive="false" /> | |
<!-- Execute Apex via REST API /query resource --> | |
<http url="https://${host}/services/data/v29.0/query" method="GET" entityProperty="queryResultResponse" statusProperty="loginResponseStatus" printrequestheaders="false" printresponseheaders="false"> | |
<headers> | |
<header name="Authorization" value="Bearer ${sessionId}"/> | |
</headers> | |
<query> | |
<parameter name="q" value="@{query}"/> | |
</query> | |
</http> | |
<property name="@{queryResult}" value="${queryResultResponse}"/> | |
</sequential> | |
</macrodef> | |
</project> |
Ye sessionId does work in sf:deploy. However if providing a session id. 'serverurl' attribute should be a specific app server instance (e.g. na1, na2) and can't be login.salesforce.com or test.salesforce.com, it needs to be na14.salesforce.com or so.
Thats really interesting, i didn't know sf:deploy supported sessionId cool!
Though i don't see any reference in the Ant migration tool docs?
I tried it and I'm using it too, it works like a charm :)
<sf:deploy serverurl="${sf.destinationserverurl}" sessionId="${sf.destinationsessionId}" maxPoll="${sf.maxPoll}" deployRoot="exported_foldername" rollbackOnError="true"/>
Hello! Thanks for this script.
i am using this script for deploying dependency tree before start working. however I am not able to define that the dependent package should be deployed for everyone, instead of only single user.
how would i do that?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is it possible to use sessionid only for deployment ???