We are trying to implement our CI/CD with Azure DevOps (Pipelines) but we are facing a couple errors.
Basically we were trying to created just one build.xml and one build.properties files and dynamically change the values within these files based on the variables declared for each Pipeline.
Below are the files we are currently using:
build-sb.xml
<project name="Sample usage of Salesforce Ant tasks" default="deployCodeCheckOnly" basedir="." xmlns:sf="antlib:com.salesforce">
<property file="build-sb.properties"/>
<property environment="env"/>
<!-- Setting default value for username, password and session id properties to empty string
so unset values are treated as empty. Without this, ant expressions such as ${sf.username}
will be treated literally.
-->
<condition property="sf.username" value="${sf.username}"> <not> <isset property="sf.username"/> </not> </condition>
<condition property="sf.password" value="${sf.password}"> <not> <isset property="sf.password"/> </not> </condition>
<taskdef resource="com/salesforce/antlib.xml" uri="antlib:com.salesforce">
<classpath>
<pathelement location="ant-salesforce.jar" />
</classpath>
</taskdef>
<!-- Shows check only; never actually saves to the server -->
<target name="deployCodeCheckOnly">
<sf:deploy username="${sf.username}" password="${sf.password}" serverurl="${sf.serverurl}" maxPoll="${sf.maxPoll}" pollWaitMillis="10000" deployRoot="../src" checkOnly="true"/>
</target>
</project>
build-sb.properties
# build.properties
#
# Specify the login credentials for the desired Salesforce organization
sf.username = usernamehere
sf.password = passwordhere
#sf.sessionId = <Insert your Salesforce session id here. Use this or username/password above. Cannot use both>
#sf.pkgName = <Insert comma separated package names to be retrieved>
#sf.zipFile = <Insert path of the zipfile to be retrieved>
#sf.metadataType = <Insert metadata type name for which listMetadata or bulkRetrieve operations are to be performed>
# Use 'https://login.salesforce.com' for production or developer edition (the default if not specified).
# Use 'https://test.salesforce.com for sandbox.
sf.serverurl = https://test.salesforce.com
sf.maxPoll = 2000
# If your network requires an HTTP proxy, see http://ant.apache.org/manual/proxy.html for configuration.
#
These are the variables defined for the Pipeline. The value for the password is pwd + token:
And here is our Ant Build script:
# Ant
# Build your Java projects and run tests with Apache Ant.
# Add steps that save build artifacts and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/java
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Ant@1
inputs:
workingDirectory: ''
buildFile: 'build/build-sb.xml'
options: -verbose -Dsalesforce.loginurl=$SF.LOGINURL -Dsalesforce.password=$SF.PASSWORD -Dsalesforce.testLevel=$SF.TESTLEVEL -Dsalesforce.username=$SF.USERNAME
javaHomeOption: 'JDKVersion'
jdkVersionOption: '1.8'
jdkArchitectureOption: 'x64'
publishJUnitResults: false
testResultsFiles: '**/TEST-*.xml'
The problem happens if we don't explicitly enter the username/password and url in the build-sb.properties. We would like to dynamically populate these values based on the values declared for each Pipeline.
Here is what we get back from the logs if we don't enter these values:
##[section]Starting: Ant
==============================================================================
Task : Ant
Description : Build with Apache Ant
Version : 1.155.0
Author : Microsoft Corporation
Help : https://docs.microsoft.com/azure/devops/pipelines/tasks/build/ant
==============================================================================
[command]/usr/bin/ant -version
Apache Ant(TM) version 1.9.6 compiled on July 20 2018
[command]/usr/bin/ant -buildfile /home/vsts/work/1/s/build/build-sb.xml -verbose -Dsalesforce.loginurl=$SF.LOGINURL -Dsalesforce.password=$SF.PASSWORD -Dsalesforce.testLevel=$SF.TESTLEVEL -Dsalesforce.username=$SF.USERNAME
Apache Ant(TM) version 1.9.6 compiled on July 20 2018
Buildfile: /home/vsts/work/1/s/build/build-sb.xml
Detected Java version: 1.8 in: /usr/lib/jvm/zulu-8-azure-amd64/jre
Detected OS: Linux
parsing buildfile /home/vsts/work/1/s/build/build-sb.xml with URI = file:/home/vsts/work/1/s/build/build-sb.xml
Project base dir set to: /home/vsts/work/1/s/build
parsing buildfile jar:file:/usr/share/ant/lib/ant.jar!/org/apache/tools/ant/antlib.xml with URI = jar:file:/usr/share/ant/lib/ant.jar!/org/apache/tools/ant/antlib.xml from a zip file
[property] Loading /home/vsts/work/1/s/build/build-sb.properties
[property] Loading Environment env.
parsing buildfile jar:file:/home/vsts/work/1/s/build/ant-salesforce.jar!/com/salesforce/antlib.xml with URI = jar:file:/home/vsts/work/1/s/build/ant-salesforce.jar!/com/salesforce/antlib.xml from a zip file
Build sequence for target(s) `deployCodeCheckOnly' is [deployCodeCheckOnly]
Complete build sequence is [deployCodeCheckOnly, ]
deployCodeCheckOnly:
[antlib:com.salesforce] Could not load definitions from resource com/salesforce/antlib.xml. It could not be found.
BUILD FAILED
/home/vsts/work/1/s/build/build-sb.xml:21: Attribute 'username' cannot be an empty string
at com.salesforce.ant.SFDCAntTask.validateAttribute(SFDCAntTask.java:130)
at com.salesforce.ant.SFDCAntTask.validateAttributes(SFDCAntTask.java:38)
at com.salesforce.ant.SFDCMDAPIAntTask.validateAttributes(SFDCMDAPIAntTask.java:41)
at com.salesforce.ant.DeployTask.execute(DeployTask.java:57)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:293)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.Target.execute(Target.java:435)
at org.apache.tools.ant.Target.performTasks(Target.java:456)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1405)
at org.apache.tools.ant.Project.executeTarget(Project.java:1376)
at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
at org.apache.tools.ant.Project.executeTargets(Project.java:1260)
at org.apache.tools.ant.Main.runBuild(Main.java:853)
at org.apache.tools.ant.Main.startAnt(Main.java:235)
at org.apache.tools.ant.launch.Launcher.run(Launcher.java:285)
at org.apache.tools.ant.launch.Launcher.main(Launcher.java:112)
Total time: 1 second
The process '/usr/bin/ant' failed with exit code 1
##[error]Error: The process '/usr/bin/ant' failed with exit code 1
##[section]Finishing: Ant
Here is the documentation about the Pipeline Variables:
To reference a variable in YAML, prefix it with a dollar sign and enclose it in parentheses. For example: $(variable-name)
To use a variable in a script, use environment variable syntax. Replace . and space with _, capitalize the letters, and then use your platform's syntax for referencing an environment variable. Examples:
Batch script: %VARIABLE-NAME%
PowerShell script: $env:VARIABLE-NAME
Bash script: $VARIABLE-NAME
We have tried every possible way of referencing these variables within build-sb.properties without success.
$SF.USERNAME, $SF_USERNAME, $(sf_username), $(sf.username), etc.....
Any ideas?
Also, even when it works, we always get this message in the log:
deployCodeCheckOnly:
[antlib:com.salesforce] Could not load definitions from resource com/salesforce/antlib.xml. It could not be found.
[sf:deploy] Note: use ant -verbose to get more information on the failure
This is really driving us crazy...
Thanks.