Arjun Satish
Arjun Satish A technology enthusiast with varied interests

Continuous Integration With Azure DevOps — Part 1

Continuous Integration With Azure DevOps — Part 1

Most of us would be familiar with the term Continuous Integration and that too most of us Android Developer’s would have tried Jenkin’s or any other CI tools in our daily development . I just thought of trying my hand at Azure devOps in one of my test project’s to get the hang of it . And Boy, there were fewer resources to learn more about it apart from the official documentation and I had a hard time figuring it out how to do. This forced me to write about this topic .

Image for post

Photo by Nick Fewings on Unsplash

Blah blah , Now get to the point . :D.

Hope you guy’s have a Microsoft Account in place . My organisation is tied to Microsoft (vendor locked :P )and we have access to most of the Microsoft tools as well.

You might have seen the menu Azure Pipelines in devOp’s page right ? For people who have been wondering what that is .

Azure pipelines is just another cloud service which makes us to build (CI)and test and make it available to other users (CD). Azure pipelines makes use of YAML file (Used as a configuration file) to configure the step’s/Job’s involved . You can go through the YAML schema to get the hang of it . Usually the pipeline is named as “azure-pipelines.yml” and is located at the root of your repo .

A basic azure-pipelines.yml file somewhat looks like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
**trigger:  
  batch:** true  
  **tags:  
    include:** \- v\*  
  **branches:  
    include:** \- releases/\*  
  
**pool:  
  vmImage:** 'Ubuntu-16.04'  
  
**steps:  
**\- **task:** Gradle@2  
  **inputs:  
    workingDirectory:** ''  
    **gradleWrapperFile:** 'gradlew'  
    **publishJUnitResults:** false  
    **tasks:** 'assembleDebug'  
  
_#- task: Gradle@2  
\#  inputs:  
\#    workingDirectory: ''  
\#    gradleWrapperFile: 'gradlew'  
\#    publishJUnitResults: false  
\#    tasks: 'assembleRelease'  
  
_\- **task:** CopyFiles@2  
  **inputs:  
    contents:** '\*\*/\*.apk'  
    **targetFolder:** '$(build.artifactStagingDirectory)'  
  
\- **task:** PublishBuildArtifacts@1  
  **inputs:  
    pathToPublish:** '$(build.artifactStagingDirectory)/app/build/outputs/'  
    **artifactName:** 'apk-files'  
    **artifactType:** 'container'

Don’t worry , I will explain each part of the yml

Trigger

CI trigger’s cause a build to run when a push is made to a certain branch or a when a certain tag is pushed .

1
2
3
4
5
6
**trigger:  
  batch:** true  
  **tags:  
    include:** \- v\*  
  **branches:  
    include:** \- releases/\*

You can either specify a wildcard or the full name of the branch/tag . The particular code makes the CI build run when the tag which starts with the letter v is pushed or when a branch starting with releases gets created (when a commit is pushed to the release branch ). Also instructed the build to get triggered .

Pool

1
2
**pool**:  
  **vmImage**: 'Ubuntu-16.04'

Here you can specify the OS against which need to build the project . You can choose either linux / Mac or windows . Me being a linux guy and supporter of the open source projects, choose ubuntu as my driver.

If you want to run on a mac then you can use specify like this

1
2
pool:  
  vmImage: 'macOS 10.13'

If you don’t want to specify an OS version , then you could use latest version of the OS by specifying like

1
2
**pool**:  
**vmImage**: 'macOS-latest'

Steps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**steps**:  
\- **task**: Gradle@2  
  **inputs**:  
    **workingDirectory**: ''  
    **gradleWrapperFile**: 'gradlew'  
    **publishJUnitResults**: false  
    **tasks**: 'assembleDebug'  
  
_#- task: Gradle@2  
\#  inputs:  
\#    workingDirectory: ''  
\#    gradleWrapperFile: 'gradlew'  
\#    publishJUnitResults: false  
\#    tasks: 'assembleRelease'  
  
_\- **task**: CopyFiles@2  
  **inputs**:  
    **contents**: '\*\*/\*.apk'  
    **targetFolder**: '$(build.artifactStagingDirectory)'  
  
\- **task**: PublishBuildArtifacts@1  
  **inputs**:  
    **pathToPublish**: '$(build.artifactStagingDirectory)/app/build/outputs/'  
    **artifactName**: 'apk-files'  
    **artifactType**: 'container'

This is where all the action takes place . You can run various tasks here . The above code build’s and get’s the debug apk ,copies the apk to a specified folder and publish the artifact

If you want to get the release build , you could also do that .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
steps:  
\- task: Gradle@2  
  inputs:  
    workingDirectory: ''  
    gradleWrapperFile: 'gradlew'  
    gradleOptions: '-Xmx3072m'  
    publishJUnitResults: false  
    testResultsFiles: '\*\*/TEST-\*.xml'  
    tasks: 'assembleRelease'  
  
\- task: DownloadSecureFile@1  
  inputs:  
    secureFile: 'calcubaker.jks'  
  
\- task: AndroidSigning@3  
  inputs:  
    apkFiles: '\*\*/\*.apk'  
    apksignerKeystoreFile: 'calcubaker.jks'  
    apksignerKeystorePassword: '$(keystorePassword)'  
    apksignerKeystoreAlias: '$(keyAlias)'  
    apksignerKeyPassword: '$(keyPassword)'  
    zipalign: false

You could upload the keystore to secure files and get it from there . More info here . (Will cover that in another article)

If you want to connect to google play, you can do with the google play extension. You can connect it to the app center as well . ( May be in part 2 :P )

So all you guy’s need to do is include the azure-pipelines.yml in the root of your project and push to the repo . You will see that the build automatically getting triggered on your commit ( My configuration run’s on release branch or whenever there is a tag)

Rating: