Merancang GitLab CI untuk Proyek Berbasis Android

Aldi Fahrezi
temancatat
Published in
5 min readMar 6, 2018

Bagi Anda yang belum tahu, GitLab CI merupakan seperangkat tools yang dibuat oleh GitLab agar kita bisa merancang pipeline CI/CD (meliputi proses building, testing, packaging, hingga deployment) aplikasi kita yang akan dijalankan secara otomatis oleh GitLab melalui integrasi dengan repositori kode pada GitLab.

Perancangan pipeline tersebut pun tidak sulit! Kita hanya perlu membuat suatu file bernama .gitlab-ci.yml yang berada pada repositori kita dan GitLab CI akan dengan sendirinya menjalankan pipeline sesuai dengan konfigurasi yang kita tuangkan pada file tersebut. Anda dapat membaca di https://docs.gitlab.com/ce/ci/quick_start/README.html untuk mengetahui lebih lanjut.

And the best part is… It’s completely FREE!

Tahapan CI untuk Android

Untuk aplikasi berbasis Android, kita dapat membagi pipeline CI/CD kita menjadi beberapa tahapan atau yang biasa disebut stage seperti berikut

  • Build
    Tahapan ini meliputi proses persiapan environment pipeline yang dibutuhkan beserta tools yang digunakan seperti Android SDK.
    Note: Untuk proyek berbasis Android, di tahapan ini juga perlu untuk dihasilkan apk agar dapat digunakan pada tahapan Test
  • Test
    Di tahapan ini, seluruh test yang sudah kita buat (baik unit test, functional test, maupun UI test) dilakukan seluruhnya.
  • Package (Deployment)
    Pada tahapan ini, kita membungkus dan melakukan deployment aplikasi kita agar siap digunakan oleh userbase kita.

Tentunya, kita dapat mendefinisikan tahapan-tahapan ini pada GitLab CI dengan menambahkan kode berikut pada .gitlab-ci.yml

stages:
- build
- test
- package

Berikutnya, mari kita lihat konfigurasi untuk masing-masing tahapan pada GitLab CI.

Konfigurasi Build Stage

Mengacu pada proyek TemanCatat yang sedang saya kembangkan (bersama teman-teman setim), konfigurasi gitlab-ci untuk tahapan build kami secara kasar berbentuk seperti ini:

build:
stage:
build
script:
# Variables

- export ANDROID_COMPILE_SDK=27
- export ANDROID_SDK_TOOLS=3859397

# Download Android SDK
- wget --quiet --output-document=/tmp/sdk-tools-linux.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip
- unzip /tmp/sdk-tools-linux.zip -d .android

# Set Environment Variables
- export ANDROID_HOME=$PWD/.android
- export PATH=$PATH:$PWD/.android/platform-tools/

# Install platform tools dan Android SDK untuk target kompilasi
- echo y | .android/tools/bin/sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}"
# Pembuatan APK
- chmod +x ./gradlew
- ./gradlew assemble

Beberapa poin penting yang perlu diperhatikan adalah

  • Kita memberikan nama job build dan memasukkan job ini pada tahap build. Pada dasarnya, bisa saja terdapat banyak job yang dilakukan secara paralel dalam suatu tahap
  • Kita mendefinisikan perintah-perintah untuk job tersebut pada script

Setelah job di atas selesai, maka akan masuk ke tahap berikutnya, yaitu test

Konfigurasi Test Stage

test:
stage:
test
artifacts:
paths:
# Tempat artefak Code Coverage
- codeCoverageReport/

before_script:
# Define variables
- export MINIMUM_COVERAGE=0
- export ANDROID_HOME=$PWD/.android
- export PATH=$PATH:$PWD/.android/platform-tools/:$PWD/.android/tools
# Install tools tambahan
- apt-get update
- apt-get install bc

# Edit Permission
- chmod +x ./gradlew

script:
# Linter Test
- test `./gradlew lint | grep "0 issues" | wc -l` = `./gradlew lint | grep "issues" | wc -l`
# Unit Test
- ./gradlew test
# Membuat artefak Code Coverage
- mv app/build/reports/jacoco/test ./codeCoverageReport
# Melakukan komputasi hasil persentase Code Coverage
- MISSED_COUNT=`cat ./codeCoverageReport/test.xml | grep -Po '<counter type="INSTRUCTION"[^>]*>' | tail -n 1 | cut -d '"' -f 4`
- COVERED_COUNT=`cat ./codeCoverageReport/test.xml | grep -Po '<counter type="INSTRUCTION"[^>]*>' | tail -n 1 | cut -d '"' -f 6`
- COVERAGE=`bc -l <<< "100.0 * $COVERED_COUNT / ( $MISSED_COUNT + $COVERED_COUNT )"`
- echo "Coverage result - ($COVERAGE%) covered, Minimum coverage is $MINIMUM_COVERAGE%"
# Pengecekan terhadap batas minimum nilai Code Coverage
- test `bc <<< "$COVERAGE>=$MINIMUM_COVERAGE"` = 1

Dapat dilihat pada kode di atas bahwa cukup banyak yang dilakukan pada tahapan test. Hal ini kembali pada seberapa banyak test yang ingin kita lakukan di CI.

Selain itu, terdapat juga pendefinisian artifacts yang akan menjadi downloadable files pada GitLab CI serta pendefinisian before_script yang akan dijalankan sebelum masuk ke bagian script.

Note: Pada script di atas belum mencakup functional test maupun UI test karena penggunaan emulator yang lamban pada GitLab CI memperlambat seluruh pipeline CI/CD.

Konfigurasi Package Stage

package:
stage:
package
artifacts:
expire_in:
48 hours
paths:
- deliverables
script:
# Define Variables
- export APP_NAME=TemanCatat
- export VERSION_NAME=`egrep '^[[:blank:]]+versionName[[:blank:]]' app/build.gradle | awk '{print $2}' | sed s/\"//g`
- export VERSION_CODE=`egrep '^[[:blank:]]+versionCode[[:blank:]]' app/build.gradle | awk '{print $2}'`
# Memasukkan artefak informasi aplikasi
- mkdir -p deliverables
- touch ./deliverables/info.txt
- echo "Build date $(date)" >> ./deliverables/info.txt
- echo "App version name ${VERSION_NAME}" >> ./deliverables/info.txt
- echo "App version code ${VERSION_CODE}" >> ./deliverables/info.txt
- echo "Git branch ${CI_COMMIT_REF_NAME}" >> ./deliverables/info.txt
- echo "Git commit ${CI_COMMIT_SHA}" >> ./deliverables/info.txt
- echo "Gitlab pipeline ${CI_PIPELINE_ID}" >> ./deliverables/info.txt
# Memasukkan artefak apk aplikasi
- mv app/build/outputs/apk/app.apk ./deliverables/$APP_NAME-v$VERSION_NAME-$VERSION_CODE.apk

Pada tahap ini, di proyek kami hanya melakukan pembungkusan aplikasi beserta informasinya tanpa melakukan deployment (karena tidak menggunakan backend maupun push ke playstore).

Conclusion

Jika digabungkan, maka konten .gitlab-ci.yml akhir akan berbentuk seperti ini:

build:
stage:
build
script:
# Variables

- export ANDROID_COMPILE_SDK=27
- export ANDROID_SDK_TOOLS=3859397

# Download Android SDK
- wget --quiet --output-document=/tmp/sdk-tools-linux.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS}.zip
- unzip /tmp/sdk-tools-linux.zip -d .android

# Set Environment Variables
- export ANDROID_HOME=$PWD/.android
- export PATH=$PATH:$PWD/.android/platform-tools/

# Install platform tools dan Android SDK untuk target kompilasi
- echo y | .android/tools/bin/sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}"
# Pembuatan APK
- chmod +x ./gradlew
- ./gradlew assemble
test:
stage:
test
artifacts:
paths:
# Tempat artefak Code Coverage
- codeCoverageReport/

before_script:
# Define variables
- export MINIMUM_COVERAGE=0
- export ANDROID_HOME=$PWD/.android
- export PATH=$PATH:$PWD/.android/platform-tools/:$PWD/.android/tools
# Install tools tambahan
- apt-get update
- apt-get install bc

# Edit Permission
- chmod +x ./gradlew

script:
# Linter Test
- test `./gradlew lint | grep "0 issues" | wc -l` = `./gradlew lint | grep "issues" | wc -l`
# Unit Test
- ./gradlew test
# Membuat artefak Code Coverage
- mv app/build/reports/jacoco/test ./codeCoverageReport
# Melakukan komputasi hasil persentase Code Coverage
- MISSED_COUNT=`cat ./codeCoverageReport/test.xml | grep -Po '<counter type="INSTRUCTION"[^>]*>' | tail -n 1 | cut -d '"' -f 4`
- COVERED_COUNT=`cat ./codeCoverageReport/test.xml | grep -Po '<counter type="INSTRUCTION"[^>]*>' | tail -n 1 | cut -d '"' -f 6`
- COVERAGE=`bc -l <<< "100.0 * $COVERED_COUNT / ( $MISSED_COUNT + $COVERED_COUNT )"`
- echo "Coverage result - ($COVERAGE%) covered, Minimum coverage is $MINIMUM_COVERAGE%"
# Pengecekan terhadap batas minimum nilai Code Coverage
- test `bc <<< "$COVERAGE>=$MINIMUM_COVERAGE"` = 1
package:
stage:
package
artifacts:
expire_in:
48 hours
paths:
- deliverables
script:
# Define Variables
- export APP_NAME=TemanCatat
- export VERSION_NAME=`egrep '^[[:blank:]]+versionName[[:blank:]]' app/build.gradle | awk '{print $2}' | sed s/\"//g`
- export VERSION_CODE=`egrep '^[[:blank:]]+versionCode[[:blank:]]' app/build.gradle | awk '{print $2}'`
# Memasukkan artefak informasi aplikasi
- mkdir -p deliverables
- touch ./deliverables/info.txt
- echo "Build date $(date)" >> ./deliverables/info.txt
- echo "App version name ${VERSION_NAME}" >> ./deliverables/info.txt
- echo "App version code ${VERSION_CODE}" >> ./deliverables/info.txt
- echo "Git branch ${CI_COMMIT_REF_NAME}" >> ./deliverables/info.txt
- echo "Git commit ${CI_COMMIT_SHA}" >> ./deliverables/info.txt
- echo "Gitlab pipeline ${CI_PIPELINE_ID}" >> ./deliverables/info.txt
# Memasukkan artefak apk aplikasi
- mv app/build/outputs/apk/app.apk ./deliverables/$APP_NAME-v$VERSION_NAME-$VERSION_CODE.apk

Pada dasarnya masih banyak hal yang bisa ditambahkan sesuai dengan keinginan masing-masing pada konfigurasi GitLab CI. Dari proyek kami pun, konfigurasi GitLab CI menggunakan multiple job untuk suatu stage untuk membedakan antar beberapa environment aplikasi yang kami miliki (development, staging, production).

So, use GitLab CI for great good!

--

--