Following the topic of Continuous Integration (CI) that I started here, in this post we are going to see how we can build our app, and run unit tests remotely with a pipeline in Azure.
If you want to go straight to the Continuous Deployment (CD) part, check this other post.
In Azure, pipelines are built using .yml files, where part of the setup is configured and the steps of the pipeline are defined.
Pipeline Code
In Azure, and in most of the CI/CD services you can find, we need to indicate what is going to trigger the pipeline, where do we want to execute it in terms of operating system and what are going to be the steps for the pipeline to follow.
We are going to see each section individually and then finish with a complete example.
Trigger
With triggers, there is a lot of customization that you can achieve.
You can for example run builds on a schedule like so, thanks to Cron. In this example, the pipeline is going to be triggered at 10 PM every day with the contents of develop
.
schedules:
- cron: '0 22 * * *'
displayName: 'Nightly build'
branches:
include:
- develop
YAMLFor most of us, what you would probably want is to run the pipeline when you merge a pull request to the develop
branch or when you want to release a new version to production after a merge to main/master.
For that, we just need the following line at the top of our file. In this case, we want to run the pipeline every time a change is made in the develop
branch.
trigger:
- develop
YAMLPool
The pool is what is going to tell Azure where do you want to execute your pipeline. For Android, we could use the Linux based machines, but if you are building an iOS app, then you would have to choose a macOS option.
pool:
vmImage: 'ubuntu-latest'
YAMLSteps
For Android, here is where we run the Gradle tasks or the bash scripts that our pipeline is going to execute sequentially.
The first thing to do is checkout the Git repository. As the pipeline is inside the repo, we can just do it like so. You can read more about the options of this command here.
steps:
- checkout: self
persistCredentials: true
clean: true
YAMLAfter that, we can start running Gradle tasks. In the following example, I’m building all the variants of the Android app and then running unit tests on each of them.
- task: Gradle@2
displayName: 'Build app and run unit tests'
inputs:
gradleWrapperFile: 'gradlew'
options: '--stacktrace'
tasks: 'clean assemble testPreDebug testProRelease'
publishJUnitResults: true
javaHomeOption: 'JDKVersion'
sonarQubeRunAnalysis: false
sqGradlePluginVersionChoice: 'build'
YAMLEach step is going to be shown when the pipeline is executed, the displayName
variable is going to define the name of the step to be shown.
Afterward, in the inputs
variable is where we execute Gradle like we would do locally. You can do it using normal bash script but instead of using the task Gradle@2
, you would use the CmdLine@2
task, and then in the inputs field, you could run a script like so.
# For a bash script
- task: CmdLine@2
displayName: 'Run a script'
inputs:
script: |
# Some bash commands separated by a line jump
# For single line bash commands
- task: Bash@3
displayName: 'Run bash command'
inputs:
targetType: 'inline'
script: |
# A bash command
YAMLVariables
To keep your keys or other data secret and use it when you run a pipeline, you can store them in variables. This can be done in the Azure web when you are editing a pipeline, it’s pretty straightforward.
Then to use them, you just need to use this syntax $(VARIABLE_NAME)
.
Complete sample pipeline
The following sample runs on changes in the develop
branch on a Linux machine and executes these steps.
- Checkout the repo
- Set the username to whom the commit will belong
- Checkout branch and fetch any changes
- Set the Java JDK to use
- Write the
local.properties
file with pipeline variables. - Assemble the app and run unit tests
# Android
# Build your Android project with Gradle.
# Add steps that test, sign, and distribute the APK, save build artifacts, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/android
trigger:
- develop
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: self
persistCredentials: true
clean: true
- script: |
git config --global user.name "MyUsername"
git config --global user.email "myuser@email.com"
git config --global push.followTags true
- task: CmdLine@2
displayName: 'Checkout branch'
inputs:
script: |
export branchName=$(echo $(Build.SourceBranch) | cut -c12-)
git fetch
git checkout $branchName
git reset --hard origin/$branchName
- task: Bash@3
displayName: 'Use JDK11 by default'
inputs:
targetType: 'inline'
script: |
echo "##vso[task.setvariable variable=JAVA_HOME]$JAVA_HOME_11_X64"
- task: Bash@3
displayName: 'Config local.properties'
inputs:
targetType: 'inline'
script: |
echo KEY=$(KEY) > ./local.properties
- task: Gradle@2
displayName: 'Build app and run unit tests'
inputs:
gradleWrapperFile: 'gradlew'
options: '--stacktrace'
tasks: 'clean assemble testPreDebug testProRelease'
publishJUnitResults: true
javaHomeOption: 'JDKVersion'
sonarQubeRunAnalysis: false
sqGradlePluginVersionChoice: 'build'
YAMLAfter digging into the code, there’s some preparation that needs to be done before running the pipeline, which is giving permissions to the users to access the repository where our Android project is hosted.
Users Permissions
For this pipeline, we need permissions to read the repository, so that we read the Git branch that we want to test.
In order to give this permission to the user that is going to be running the pipeline, we need to go to our pipeline, and in then in the three dots there is a Manage Security option, where we must change the read permission to allow.
To see which user is going to be running the pipeline, you can go to your pipeline settings, where you are going to see a Variables tab. There is a variable called system.collectionId
, which you can then use to search for the user in the Manage Security section that we talked about before, so that you know who to give the permissions to.
Featured image by An Tran on Unsplash
If you want to read more content like this and support me, don’t forget to check the rest of the bolg or subscribe here to get an email every time I publish new content.