7

When deploying with ant you have the option to specify which tests to run, e.g.

<target name="deploy">
<sf:deploy username="${sf.username}"
           password="${sf.password}"
           serverurl="${sf.serverurl}"
           deployRoot="${dir}"
           testLevel="RunSpecifiedTests"
           maxPoll="300">
   <runTest>Test1</runTest>
   <runTest>Test2</runTest>
</sf:deploy>

We use a shared build script with the team and I'm trying to figure out how to pass a list of tests to run during the deployment from either a file or a parameter. Ideally we could do ant deploy -Dtests=Test1,Test2

I'm a very novice ant users, and I'm really struggling to figure out how to accomplish this.

I'd thought this might work and then I could hook up the list value to a command line parameter, but it complains that sf:deploy doesn't support a nested for element.

<target name="mydeploy">
  <sf:deploy username="${sf.username}"
             password="${sf.password}"
             serverurl="${sf.serverurl}"
             deployRoot="${dir}"
             testLevel="RunSpecifiedTests"
             maxPoll="300">
      <for list="Test1,Test2" param="test">
        <sequential>
            <runTest>"@{test}"</runTest>
        </sequential>
      </for>
  </sf:deploy>
</target> 

Is there anyway to build the list of <runTest> elements dynamically based on a command line input or file so that I don't need to edit my build.xml script everytime I want to do a deploy with a subset of tests?

Perhaps I should just be abandoning ant in favor of something like grunt?

11

Was able to do this using ant's scripting capability. Now you can do ant deploy -Ddir=src -Dtests=Class1,Class2,Class3

<target name="deploy">
  <script language="javascript"><![CDATA[
    var deployTask = project.createTask('antlib:com.salesforce:deploy');
    deployTask.setUsername(project.getProperty("sf.username"));
    deployTask.setPassword(project.getProperty("sf.password"));
    deployTask.setServerURL(project.getProperty("sf.serverurl"));
    deployTask.setDeployRoot(project.getProperty("dir"));
    deployTask.setTestLevel(project.getProperty("testLevel"));
    deployTask.setMaxPoll("300");
    var tests = project.getProperty('tests');
    if (tests) {
      deployTask.setTestLevel('RunSpecifiedTests');
      tests = tests.split(',');
      for (var i = 0; i < tests.length; i++) {
        var runTest = java.lang.Class.forName(
          "com.salesforce.ant.DeployTask$CodeNameElement"
        ).newInstance();
        runTest.addText(tests[i]);
        deployTask.addRunTest(runTest);
      }
    }
    deployTask.perform();
  ]]></script>
</target>
1
  • 2
    That's great. Even I was also looking for something like this. +1 – Rohit Mourya Mar 17 '17 at 5:33
1

I don't have enough reputation to comment, but I wanted to say Ralph Callaway's solution worked perfectly for me. I expanded it slightly to cover a few more of the Salesforce Migration Tool's parameters. I thought I'd share that here, and also give props to Ralph:

<target name="deployDynamic">
    <script language="javascript"><![CDATA[
        var deployTask = project.createTask('antlib:com.salesforce:deploy');
        deployTask.setUsername(project.getProperty("sf.username"));
        deployTask.setPassword(project.getProperty("sf.password"));
        deployTask.setServerURL(project.getProperty("sf.serverurl"));
        deployTask.setDeployRoot(project.getProperty("directory"));
        deployTask.setTestLevel(project.getProperty("testLevel"));
        deployTask.setSinglePackage(project.getProperty("singlePackage"));
        deployTask.setIgnoreWarnings(project.getProperty("ignoreWarnings"));
        deployTask.setAutoUpdatePackage(project.getProperty("autoUpdatePackage"));
        deployTask.setAllowMissingFiles(project.getProperty("allowMissingFiles"));
        deployTask.setCheckonly(project.getProperty("checkOnly"));
        deployTask.setMaxPoll("10000");
        var tests = project.getProperty('tests');
        if (tests) {
            deployTask.setTestLevel('RunSpecifiedTests');
            tests = tests.split(',');
            var CodeNameElement = deployTask.getClass().getClassLoader().loadClass("com.salesforce.ant.DeployTask$CodeNameElement");

            for (var i = 0; i < tests.length; i++) {
                var runTest = CodeNameElement.newInstance();
                runTest.addText(tests[i]);
                deployTask.addRunTest(runTest);
            }
        }
        deployTask.perform();
    ]]></script>
</target>
3
  • 1
    this counts as answer imo, although in this sort of case you might consider improving the original answer by editing it, even with very low rep you can edit questions, the edits just have to get reviewed. – Ralph Callaway Nov 17 '18 at 1:33
  • Update: this was working great on a self-hosted Jenkins instance. We are now moving to Github with self-hosted task runners in EC2. For some reason now, Ant/Salesforce plugin is acting differently, and using the "deployDynamic" task defined in my answer here, I am now getting: BUILD FAILED /home/ec2-user/actions-runner/_work/chg-fox-monolith/chg-fox-monolith/jenkinsFiles/build.xml:68: java.lang.RuntimeException: java.lang.ClassNotFoundException: com.salesforce.ant.DeployTask$CodeNameElement at ... etc... Any ideas ? @RalphCallaway – Kevin Gwynn Oct 16 '20 at 18:41
  • I finally figured out that issue. I think it was an Oracle JDK vs OpenJDK issue. I essentially had to change java.lang.Class.forName("com.salesforce.ant.DeployTask$CodeNameElement") to deployTask.getClass().getClassLoader().loadClass("com.salesforce.ant.DeployTask$CodeNameElement"). I'm going to update my code in the answer to reflect. – Kevin Gwynn Oct 16 '20 at 22:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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