End-to-end CI/CD pipeline Setup with Azure DevOps for Mobile App: Common Pipeline—Part 5

Sandeep Rajbhar
3 min readJul 17, 2023

--

Please follow these steps to set up a common pipeline for both iOS and Android, along with the sonar cloud quality gate.

Prerequisite

You must have already gone through PART 1, PART 2, PART 3, and PART 4 of this series. Along with Sonar Cloud with GitHub.

Create a common Pipeline:

Since we already know how to create a pipeline and release it in Part 4, Here we will just look at a new common YAML file.

# Starter pipeline

# Start with a minimal pipeline that you can customize to build and deploy your code.

# Add steps that build, run tests, deploy, and more:

# https://aka.ms/yaml

trigger:

- master

pool:

vmImage: macOS-11

jobs:

- job: TestViaJob # name of the job (A-Z, a-z, 0–9, and underscore)

timeoutInMinutes: 300

steps:

- checkout: self

persistCredentials: true

clean: true

- task: NodeTool@0

displayName: ‘Install Node’

inputs:

versionSpec: ‘v16.6.2’ # you can use your desired version here

- script: yarn install

displayName: Install Dependencies

- task: SonarSource.sonarcloud.14d9cde6-c1da-4d55-aa01–2965cd301255.SonarCloudPrepare@1

displayName: ‘Prepare analysis on SonarCloud’

inputs:

SonarCloud: SonarClodPOCServiceCon

organization: ‘*************’

scannerMode: CLI

configMode: manual

cliProjectKey: ‘*************’

cliProjectName: PM.SonarCloudPOC

extraProperties: |

sonar.exclusions=**/android/**/*.* , **/ios/**/*.* , **/node_modules/**/*.* , **/__tests__/*.tsx , **/coverage/**/*.js,**/setupTests.ts,**/babel.config.js, **/metro.config.js,

sonar.coverage.exclusions = **/android/**/*.* , **/ios/**/*.* , **/node_modules/**/*.*

sonar.javascript.file.suffixes= .jsx , .js

sonar.typescript.file.suffixes= .tsx , .ts

sonar.java.binaries=-

sonar.c.file.suffixes=-

sonar.cpp.file.suffixes=-

sonar.objc.file.suffixes=-

sonar.html.file.suffixes=-

sonar.css.file.suffixes=-

sonar.java.file.suffixes=-

sonar.sources=.

sonar.language=js , jsx, ts , tsx

sonar.tests=./__tests__

sonar.javascript.lcov.reportPaths=./coverage/lcov.info

sonar.testExecutionReportPaths=./test-report.xml

sonar.sourceEncoding=UTF-8

enabled: true

- task: SonarSource.sonarcloud.ce096e50–6155–4de8–8800–4221aaeed4a1.SonarCloudAnalyze@1

displayName: ‘Run Code Analysis’

enabled: true

- task: SonarSource.sonarcloud.38b27399-a642–40af-bb7d-9971f69712e8.SonarCloudPublish@1

displayName: ‘Publish Quality Gate Result’

enabled: true

- task: SimondeLang.sonarcloud-buildbreaker.sonar-buildbreaker.sonarcloud-buildbreaker@2

displayName: ‘Break build on quality gate failure’

inputs:

SonarCloud: SonarClodPOCServiceCon

organization: ‘*************’

enabled: true

- task: Gradle@2

displayName: ‘gradlew build’

inputs:

gradleWrapperFile: android/gradlew

workingDirectory: android

publishJUnitResults: false

- task: AndroidSigning@3

displayName: ‘Signing and aligning APK file(s) **/*.apk’

inputs:

apksignerKeystoreFile: ‘*************’

apksignerKeystorePassword: sonar123

apksignerKeystoreAlias: sonar0

apksignerKeyPassword: sonar123

zipalign: false

- task: CopyFiles@2

displayName: ‘Copy Files to: $(build.artifactstagingdirectory)’

inputs:

SourceFolder: ‘$(system.defaultworkingdirectory)’

Contents: ‘**/*.apk’

TargetFolder: ‘$(build.artifactstagingdirectory)’

condition: succeededOrFailed()

- task: PublishBuildArtifacts@1

displayName: ‘Publish Artifact: drop’

inputs:

PathtoPublish: ‘$(build.artifactstagingdirectory)’

condition: succeededOrFailed()

- task: CocoaPods@0

displayName: ‘Install CocoaPods’

inputs:

workingDirectory: ‘ios’

- task: InstallAppleCertificate@2

displayName: ‘Install an Apple certificate’

inputs:

certSecureFile: ‘iosAzureDevOPSCICD_distribution.p12’

certPwd: ‘$(P12password)’

- task: InstallAppleProvisioningProfile@1

displayName: ‘Install an Apple provisioning profile’

inputs:

provProfileSecureFile: AzueDevOpsCICDTest.mobileprovision

- task: Xcode@5

displayName: ‘Xcode build’

inputs:

actions: ‘build’

configuration: ‘$(Configuration)’

xcWorkspacePath: ‘ios/QualityGateTest.xcworkspace’

scheme: ‘QualityGateTest’

packageApp: true

signingOption: ‘manual’

signingIdentity: ‘$(APPLE_CERTIFICATE_SIGNING_IDENTITY)’

provisioningProfileUuid: ‘$(APPLE_PROV_PROFILE_UUID)’

destinationPlatformOption: ‘iOS’

destinationSimulators: ‘iPhone 12’

- task: CopyFiles@2

displayName: ‘Copy Files to: $(build.artifactstagingdirectory)’

inputs:

SourceFolder: ‘$(system.defaultworkingdirectory)’

Contents: ‘**/*.ipa’

TargetFolder: ‘$(build.artifactstagingdirectory)’

condition: succeededOrFailed()

- task: PublishBuildArtifacts@1

displayName: ‘Publish Artifact: drop’

inputs:

PathtoPublish: ‘$(build.artifactStagingDirectory)’

condition: succeededOrFailed()

There are a few new lines added for the common YAML file highlighted in bold; let’s see them one by one.

1) Jobs: Jobs are added at the top level of the YAML file to increase a pipeline timeout from the default of 60 minutes.

2) Node tool: The new Mac machine provided by the Azure pipeline did not have a default node. So we are installing it from the pipeline, it will install the node module regardless of whether it is present or not.

3) Yarn install: Installing a node module in a VM via pipeline

4) Install Cocoa pods: Installing pods in a VM via pipeline

Note:

a) The node installation is a very important step. If the node is not installed on the VM, it will not create an Artifact and will give some error like the one mentioned below for iOS and Android.

https://developercommunity.visualstudio.com/t/Android---main-module-field-for-%E2%80%9Creact/1494126?space=22&entry=problem&viewtype=all

https://developercommunity.visualstudio.com/t/IOS---Running-script-CP-User-Generate/1494122?space=22&entry=problem&viewtype=all

b) Jobs were added to the pipeline to tackle the timeout issue, but we need to be careful about indentation while changing the pipeline.

Enjoy !!!!!.

This is a standard way to create a CICD for a multi-environment mobile app in native, React Native, or Flutter.

However, I have worked at the advanced level of CICD and using in our application, as mentioned below

  1. Creating a dynamic single pipeline for all the environments (SIT, UAT, and PROD) without creating three different pipelines.
  2. Using WebHook to automatically send the Release Notes to the Microsoft Teams channel.
  3. Using Azure's Microsoft Graph API to upload ADHoc IPA and APK for testers to use for testing in the browser stack or other platform.
  4. Upload the IPA and APK automatically to the browser stack and run the test.
  5. Generate the test result.

Connect with me on my email ID, SandeepRajbhar1985@gmail.com for more detail on the above topic and to discuss how advanced we can go and what else we can do to make CICD better along with Automation.

--

--

Sandeep Rajbhar
Sandeep Rajbhar

Written by Sandeep Rajbhar

Solution Architect at Royal Cyber.

No responses yet