Execute an Apex class using Ant build script

We are in the process of setting up automatic build using Ant. We want to do some start up activities like read an xml file which is stored as a static resource and verify it with a custom object data to make sure some settings are valid. We want the build to fail if there is a mismatch on any of the data. So to do this, i am trying to create an ant task where i can create a target which would do the following?
a. upload static resources which are xml files from a folder.
b. execute an apex class which would compare the xml file with a custom object data and if there is a mismatch fail the target build.
Do you guys know how to have an ant target which would execute an apex class or even a visual force page and spit an error please?
Thanks
Buyan

Answer

Inspired by mattandneil‘s answer, my preference for platform neutral Ant scripts and wanting to see if I could get the Tooling API working from Ant, I’ve worked up this solution. Its taken quite a while actually, but I’ve enjoyed it and it has shown some great possibilities for calling Salesforce REST API’s from Ant. Anyway, first the data we want to assert exists in the target org, contained in assertdata.xml.

<accounts>
    <name>Burlington Textiles Corp of America</name>
    <name>Dickenson plc</name>
    <name>Edge Communications</name>
</accounts>

The following is a demo Ant script to upload that as a StaticResource and Run some Apex to check it against the database, in this case the Account object. The script makes use of the Ant macro functionality to hide the complex bits away. I’ve uploaded the ant-salesforce.xml macro file here, it has additional Ant library download requirements to support the HTTP callouts see comments within.

<project name="demo" default="assertOrgData" basedir="." xmlns:sf="antlib:com.salesforce">

    <property file="${basedir}/build.properties"/>

    <target name="assertOrgData">
    
        <!-- Import macros -->
        <import file="${basedir}/lib/ant-salesforce.xml"/>

        <!-- Deploy the Static Resource -->
        <staticResource
            username="${sf.username}"
            password="${sf.password}"
            developername="assertdata"
            file="${basedir}/assertdata.xml"
            contenttype="application/xml"/>

        <!-- Execute the following Apex code -->
        <executeApex
            username="${sf.username}"
            password="${sf.password}">
            <![CDATA[

                Dom.Document doc = new Dom.Document();
                doc.load(new PageReference('/resource/assertdata').getContent().toString());
                List<String> accountNames = new List<String>();
                for(Dom.XMLNode accountNode : doc.getRootElement().getChildElements())
                    accountNames.add(accountNode.getText());
                List<Account> accountRecords = [select Id from Account where Name in :accountNames];            
                System.assertEquals(accountNames.size(), accountRecords.size());

            ]]>
        </executeApex>      

    </target>

</build>

NOTE: To fail the build throw an exception or as in the case above use the System.assert functions (which actually work outside of a test context) from the Apex code (which can call other Apex code in the org as well). I used the assert approach in this demo as they felt more appropriate given the nature of the code. However you can just as easily throw an exception, that will also stop the build.

The build output for a failure will be something like this…

BUILD FAILED
/ant-salesforce-demo/build.xml:19: The following error occurred while executing this line:
/ant-salesforce-demo/lib/ant-salesforce.xml:125: System.AssertException: Assertion Failed: Expected: 3, Actual: 2 AnonymousBlock: line 9, column 1

TOOLING API USAGE: The execute apex macro uses the recently released execute Apex feature of the Tooling API. You will also find in the macro file an example of uploading the StaticResource via the Tooling API in the macro called staticResource.toolingapi, which turned out to be much much faster! However behaviour wise it would not overwrite the file if it was already deployed. So I moved it aside and wrote an Metadata API (sf:deploy) based one instead for now.

Attribution
Source : Link , Question Author : Buyan Thyagarajan , Answer Author : Matt and Neil

Leave a Comment