Maximizing Efficiency: Speeding Up Your Android Pipeline with Parallel Jobs in Azure DevOps

Kamran Shahid
5 min readMar 6, 2023

--

If you’re an Android developer using MS Azure DevOps for your app development, you’re likely already familiar with YAML files. But did you know running jobs in parallel can help you optimize your app development process? In this article, we’ll explore how to configure YAML files in MS Azure DevOps to run jobs in parallel for your Android pipeline.

What are parallel jobs?

Parallel jobs are a way of running multiple jobs concurrently, rather than sequentially. This can significantly reduce build times and increase efficiency, allowing you to deliver high-quality apps faster. Although it’s not currently possible to run tasks in parallel (Azure DevOps), we can run jobs concurrently to save time. However, there is a feature request to enable parallel task running, which may become available in the future.

How can parallel jobs benefit Android development?

Running parallel jobs can be particularly helpful for Android developers when you want to save time by creating multiple builds, perform unit tests, code analysis in parallel. For example, without parallel jobs, a single build could take up to 20 minutes, and three builds add up to an hour. By running parallel jobs, you can dramatically reduce this time and make the development process more efficient.

Scenario:

Suppose we have a ride-hailing app like Uber with three build flavors for driver, customer, and admin. In this scenario, we could have the following YAML configuration:

name: 'Android-CD-Pipeline-$(date:yyyyMMdd)'

trigger:
branches:
include:
- release/*

jobs:
- job: CreateReleaseNotes
pool:
vmImage: macOS-latest
steps:
- task: Bash@3
displayName: Create Release Notes
inputs:
targetType: filePath
filePath: $(Build.SourcesDirectory)/releasenotes.sh
condition: succeeded()

- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(Build.SourcesDirectory)/app/build/outputs/apk/release
artifactName: android-artifacts

- job: Build
pool:
vmImage: macOS-latest
steps:
- task: JavaToolInstaller@0
displayName: Acquire Java 11
inputs:
versionSpec: '11'
jdkArchitectureOption: x64
jdkSourceOption: PreInstalled

- task: Gradle@2
displayName: Assemble Builds
inputs:
workingDirectory: $(Build.SourcesDirectory)/app
gradleWrapperFile: $(Build.SourcesDirectory)/gradlew
gradleOptions: '-Xmx3072m'
publishJUnitResults: false
tasks: >-
clean assembleDriverEnvBuild assembleCustomerEnvBuild
assembleAdminEnvBuild

- task: PublishBuildArtifacts@1
displayName: Publish Builds
inputs:
pathtoPublish: $(Build.SourcesDirectory)/app/build/outputs/apk/release
artifactName: android-artifacts

dependsOn: CreateReleaseNotes
condition: succeeded()

The name field sets the name of the pipeline, including the current date.

The trigger section specifies that the pipeline should run when changes are made to branches that match the pattern "release/*".

The YAML code defines two jobs:

  • The CreateReleaseNotes job runs on a macOS virtual machine and creates release notes using a Bash script. If the job succeeds, it publishes the build artifacts (APK files) to Azure DevOps.
  • The Build job runs on a macOS virtual machine, installs Java 11, runs a Gradle build to assemble the driver, customer, and admin build flavors, and publishes the build artifacts (APK files) to Azure DevOps. This job depends on the completion of the CreateReleaseNotes job and will only run if the CreateReleaseNotes job succeeds.

Overall, this pipeline builds and publishes the driver, customer, and admin build flavors for an Android app whenever changes are made to a “release/*” branch. Additionally, the pipeline creates release notes using a Bash script and publishes the build artifacts to Azure DevOps.

Please note that this is a basic example to illustrate the concept of using parallel jobs in a YAML pipeline. In real-world scenarios, the build and deployment process may involve more steps, such as testing and code analysis.

Parallel Job Implementation:

We’re currently running three different gradle build tasks sequentially in the “Assemble Builds” task: assembleDriverEnvBuild, assembleCustomerEnvBuild, and assembleAdminEnvBuild.

Here’s an example of how you can configure it to run jobs in parallel:

name: 'Android-CD-Pipeline-$(date:yyyyMMdd)'

trigger:
branches:
include:
- release/*

jobs:
- job: CreateReleaseNotes
pool:
vmImage: macOS-latest
steps:
- task: Bash@3
displayName: Create Release Notes
inputs:
targetType: filePath
filePath: $(Build.SourcesDirectory)/releasenotes.sh
condition: succeeded()

- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(Build.SourcesDirectory)/app/build/outputs/apk/release
artifactName: android-artifacts

- job: Build_Driver
pool:
vmImage: macOS-latest
steps:
- task: JavaToolInstaller@0
displayName: Acquire Java 11
inputs:
versionSpec: '11'
jdkArchitectureOption: x64
jdkSourceOption: PreInstalled

- task: Gradle@2
displayName: Assemble Driver Build
inputs:
workingDirectory: $(Build.SourcesDirectory)/app
gradleWrapperFile: $(Build.SourcesDirectory)/gradlew
gradleOptions: '-Xmx3072m'
publishJUnitResults: false
tasks: clean assembleDriverEnvBuild

- task: PublishBuildArtifacts@1
displayName: Publish Builds
inputs:
pathtoPublish: $(Build.SourcesDirectory)/app/build/outputs/apk/release
artifactName: android-artifacts

dependsOn: CreateReleaseNotes
condition: succeeded()

- job: Build_Customer
pool:
vmImage: macOS-latest
steps:
- task: JavaToolInstaller@0
displayName: Acquire Java 11
inputs:
versionSpec: '11'
jdkArchitectureOption: x64
jdkSourceOption: PreInstalled

- task: Gradle@2
displayName: Assemble Customer Build
inputs:
workingDirectory: $(Build.SourcesDirectory)/app
gradleWrapperFile: $(Build.SourcesDirectory)/gradlew
gradleOptions: '-Xmx3072m'
publishJUnitResults: false
tasks: clean assembleCustomerEnvBuild

- task: PublishBuildArtifacts@1
displayName: Publish Builds
inputs:
pathtoPublish: $(Build.SourcesDirectory)/app/build/outputs/apk/release
artifactName: android-artifacts

dependsOn: CreateReleaseNotes
condition: succeeded()

- job: Build_Admin
pool:
vmImage: macOS-latest
steps:
- task: JavaToolInstaller@0
displayName: Acquire Java 11
inputs:
versionSpec: '11'
jdkArchitectureOption: x64
jdkSourceOption: PreInstalled

- task: Gradle@2
displayName: Assemble Admin Build
inputs:
workingDirectory: $(Build.SourcesDirectory)/app
gradleWrapperFile: $(Build.SourcesDirectory)/gradlew
gradleOptions: '-Xmx3072m'
publishJUnitResults: false
tasks: clean assembleAdminEnvBuild

- task: PublishBuildArtifacts@1
displayName: Publish Builds
inputs:
pathtoPublish: $(Build.SourcesDirectory)/app/build/outputs/apk/release
artifactName: android-artifacts

dependsOn: CreateReleaseNotes
condition: succeeded()

The updated code now includes three separate jobs (Build_Driver, Build_Customer and Build_Admin), one for each of the three different build flavors (driver, customer, and admin). Since each of these jobs is independent of the others and they all depend on the same job (CreateReleaseNotes), they can run in parallel.

The jobs have been named according to the build flavor they are responsible for, and each job includes the necessary steps to acquire Java 11 and run the appropriate Gradle task to assemble the build. After each build is assembled, the final step is to publish the resulting artifacts.

Each job will run concurrently, allowing for faster overall build times compared to running all of the builds sequentially in a single job. However, it’s important to note that the actual time it takes to complete each build will depend on factors such as the size and complexity of the project, the virtual machine’s processing power, and other environmental factors.

In conclusion, parallel jobs in Azure DevOps offer an excellent solution for teams looking to maximize efficiency and speed up their Android pipeline. By setting up and configuring parallel jobs, teams can significantly reduce testing and deployment time, resulting in faster build times, better use of resources, and improved overall efficiency.

To learn more about concurrent jobs in Azure DevOps, visit the official documentation available at https://learn.microsoft.com/en-us/azure/devops/pipelines/licensing/concurrent-jobs?view=azure-devops&tabs=ms-hosted.

Stay tuned to my tech journey by following me on Medium. And if you want to join forces and conquer the tech world together, let’s connect on LinkedIn!

--

--

Kamran Shahid
Kamran Shahid

Written by Kamran Shahid

Experienced Android developer building quality, scalable, and user-friendly apps. Sharing my insights on mobile development.

No responses yet