Continuous Integration — GitLab — iOS — Part 2
By: Rakesh Chander
Tags: Sonar, iOS, Sonarqube, Continuous Integration, Swiftlint

We have covered SetUp of CI in gitlab along with Build & Test jobs in my medium story “Continuous Integration — GitLab — iOS — Part 1”. Go through this for all preliminary details.

In this story we’ll cover up Lint & SONAR (Static Code Analysis) integration in CI pipelines.

Its always best practices to lint code before taking up Merge Requests. Linting can also be automated via GitLab Pipeline and Reviewer / Developer both are always sure that code pushed is not having any lint issues.

In general, we use SwiftLint in iOS Projects for linting. SwiftLint YML file is added to project root and rules are defined as per project needs. Developers start getting warnings / errors from SwiftLint in their local machines itself which they can fix on the go. But they can still push code, here comes the CI part which will make sure that all lint issues are fixed, otherwise pipeline will start failing.

SwiftLint has added more beauty to this in such a way that we can define customised location from where swiftlint.yml to be picked for CI — making sure that no rules are being changed by developers locally in the project. At gitlab runner machine we can place yml file and specify that location in gitlab yml for job execution.

Reviewers can keep on adding more rules as and whne required at runner machine only, to automate their review rules — frankly speaking, I have offloaded most of my review checks to SwiftLint by adding rules. You can check SwiftLint - Advanced story for such rules.

LINT — Run SwiftLint

We should check for lint issues even before the build validation to make sure no lint level mistakes are there to compromise with Best Practices.

I reommend creating a separate pre_build.sh file, which you can use for any pre-build activity required. Place this file in runner machine at some defined location. Refer below for SwiftLint scripts in pre_build.sh -

export PATH=/usr/local/bin:$PATH LINT=$(which swiftlint) if [[ -e "${LINT}" ]]; then echo "SwiftLint Start..." echo $(pwd) else echo "SwiftLint does not exist, download from https://github.com/realm/SwiftLint" exit 1 fi RESULT=$($LINT lint --quiet --strict --config $HOME/Documents/Pre-Build/.swiftlint.yml) if [ "$RESULT" == '' ]; then printf "SwiftLint Finished.

" else printf "SwiftLint Failed. Please check below:

" while read -r line; do FILEPATH=$(echo $line | cut -d : -f 1) L=$(echo $line | cut -d : -f 2) C=$(echo $line | cut -d : -f 3) TYPE=$(echo $line | cut -d : -f 4 | cut -c 2-) MESSAGE=$(echo $line | cut -d : -f 5 | cut -c 2-) DESCRIPTION=$(echo $line | cut -d : -f 6 | cut -c 2-) printf "

$TYPE

" printf " $FILEPATH:$L:$C

" printf " $MESSAGE - $DESCRIPTION

" done <<< "$RESULT" echo "PIPELINE ABORTED. Please fix them and push again." exit 1 fi

To automate this, we will edit existing “build_core_all” job itself

Just before xcodebuild command we will add script to execute pre_build.sh

Refer below snippet —

stages:

- test

- build build_core_all:

stage: build

script:

- rm -rf Pods

- rm -rf Podfile.lock

- pod install

- bash $HOME/Documents/Pre-Build/pre_build.sh

- xcodebuild -workspace <WORKSPACE_NAME>.xcworkspace -scheme <SCHEME_NAME> clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED=NO -destination generic/platform=iOS

except:

- tags

test_all:

stage: test

script:

- rm -rf Pods

- rm -rf Podfile.lock

- pod install

- xcodebuild -workspace <WORKSPACE_NAME>.xcworkspace -scheme <SCHEME_NAME> clean test -destination 'platform=iOS Simulator,name=iPhone 11,OS=14.0' -enableCodeCoverage YES

except:

- tags

- master

SONAR Analysis — Validate SONAR status

We should have SONAR analysis and validation as part of CI to make sure we are not adding any Techincal Debt & CodeCoverage etc are as per expected level and compliant with organisation level rules.

We will add a new stage named “sonar” and corresponding job which executes only on develop branch.

Download SONAR-Scanner at your runner machine and place at defined location.

Create file “sonar_validation.sh” at project root and add below commands to that. Update “SONAR_SERVER_DOMAIN” in below file with your server url.

#!/bin/bash file="./sonar-project.properties" if [ -f "$file" ] then echo "$file found." projectKey=`sed '/^\#/d' $file | grep 'sonar.projectKey' | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'` projectKey=${projectKey/":"/"%3A"} #echo project key is = $projectKey else echo "$file not found." fi URL=http://<SONAR_SERVER_DOMAIN>/sonar/api/qualitygates/project_status?projectKey=$projectKey #echo "url being hit is $URL" RESPONSE=$(curl -X GET $URL) PROJECTSTATUS=$( jq -r '.projectStatus|.status' <<< "${RESPONSE}" ) echo $PROJECTSTATUS if [ "$PROJECTSTATUS" = "OK" ]; then echo "This means that the quality gate has passed" else echo "This means that quality gate has failed" exit 1 fi

Now, once you have added “sonar-project.properties” & “xcode-coverage-mapper.sh” files at your project root, update your gitlab.yml as per below -

stages:

- test

- build

- sonar build_core_all:

stage: build

script:

- rm -rf Pods

- rm -rf Podfile.lock

- pod install

- bash $HOME/Documents/Pre-Build/pre_build.sh

- xcodebuild -workspace <WORKSPACE_NAME>.xcworkspace -scheme <SCHEME_NAME> clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED=NO -destination generic/platform=iOS

except:

- tags test_all:

stage: test

script:

- rm -rf Pods

- rm -rf Podfile.lock

- pod install

- xcodebuild -workspace <WORKSPACE_NAME>.xcworkspace -scheme <SCHEME_NAME> clean test -destination 'platform=iOS Simulator,name=iPhone 11,OS=14.0' -enableCodeCoverage YES

except:

- tags

- master test_sonar:

stage: sonar

script:

- rm -rf Pods

- rm -rf Podfile.lock

- pod install

- xcodebuild -workspace <WORKSPACE_NAME>.xcworkspace -scheme <SCHEME_NAME> clean test -destination 'platform=iOS Simulator,name=iPhone 11,OS=14.0' -enableCodeCoverage YES -derivedDataPath Build/

- bash xcode-coverage-mapper.sh Build/Logs/Test/*.xcresult/ > sonarqube-generic-coverage.xml

- bash $HOME/Documents/Sonar/sonar*/bin/sonar-scanner

- bash sonar_validation.sh

only:

- develop

Thats It!! Now REST ASSURED

Whenever Code is getting pushed and getting merged till develop, CI is making sure that