Hello!With the advent of Github Actions, he took the initiative and integrated the simple (but quite effective) CI / CD into our small, but already 2 years old, live Flowwow project .What for?
Perhaps there are some developers who do not make mistakes, but here I am not one of them, so occasionally, but such small bursts of crash happen and you have to urgently release a new version with editing or rollback to the previous version. But those hours-days in which users stumble upon app crashes do not remain without traces both among customers and in the mood of a responsible developer.How to minimize fakapy on production, I will tell below.Why do I personally have such fakap?- Insecure code snippet
- They brought in some library and it crashes situationally
- Updated some library (usually analytics) to an unstable version
With 1 point, code review, Unit tests, static code analysis, UI tests, manual testing will help us.With 2-3 points - only UI tests and manual testing.It remains only to automate this. At this stage, the choice fell on the then just appeared Github Actions , the benefit and the project code is on Github. I must say right away, for a free github account, there are 2,000 free action minutes per month.Where to start?
It is full of ready-made examples for various languages โโand frameworks. This thing is configured through the YAML configuration file , which is located in the project repository.
Minimal example for Android:name: Android CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Gradle
run: ./gradlew assembleDebug
Description: for every push, a task is launched on any branch on the github virtual machine with ubuntu OS. Task steps: checkout our code, configure jdk, run gradle tasks for assembly.In case of unsuccessful passage of a step, we will see such a picture
there you can see the logs.Itโs convenient that with Pull Request weโll immediately be shown that our test sequence has flopped.
And if you have github integration with Slack, then itโs also
Now point by point
1. Unit testsYou wrote Unit tests using junit, mockito, etc.Now your tests are included in the test sequence by adding the appropriate gradle task.- name: Run some unit tests
run: ./gradlew testStageDebugUnitTest
2. Static code analysisYou can use simple linters ( detekt - for kotlin, pmd - for java).Or a more complicated option is sonarqube .In the case of simple linters (for example, we have both java and kotlin):task("checkAll") {
group "Verify"
description "Runs all static checks on the build"
dependsOn "pmd", "detekt"
}
- name: Run some unit tests
run: ./gradlew checkAll
in case of sonarqube - more about tuning - here- uses: actions/checkout@v1
- name: SonarCloud Scan
run: ./gradlew jacocoUnitTestReport sonarqube -Dsonar.login=${{ secrets.SONAR_TOKEN }} --stacktrace
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Link to SonarCloud Report
run: echo "https://sonarcloud.io/dashboard?id=.."
3. UI testsWriting a UI test is a figment of your imagination, my approach is one โSmokeโ test that imitates the standard actions of the user in the application - log in, select a product, place an order, track the order. You can use UIAutomator, Espresso, Kaspresso.There are also 2 options for launching here - an emulator on a github virtual machine or cloud services such as the Firebase Test Lab.To use the emulator inside github, there are ready-made implementations: one and two .In the case of the Firebase Test Lab, you must work with the Google Cloud Platform through the gcloud CLI- name: prepare gcloud
uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
with:
version: latest
service_account_email: ${{ secrets.SA_EMAIL }}
service_account_key: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
- name: gcloud Set up project
run: |
gcloud config set project ${{ secrets.PROJECT_ID }}
- name: Assemble apks for smoke test
run: ./gradlew Smoke
- name: Run tests in test lab
run: |
gcloud firebase test android run \
--app app/build/outputs/apk/production/debug/app.apk \
--test app/build/outputs/apk/androidTest/production/debug/appTest.apk \
--device model=Nexus6P,version=25,orientation=portrait,locale=en_US \
--device model=athene,version=23,orientation=portrait,locale=en_US \
--device model=sailfish,version=26,orientation=portrait,locale=en_US
For this to work, you need to create a project in Firebase, create a service account with admin rights in Google Cloud Console, and upload the received json key to base64 in github secrets for authorization in gcloud .The general config in my case looked like this. The task is triggered by the PR event in mastername: Android CI
on:
pull_request:
branches:
- 'master'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Run static checks
run: ./gradlew checkAll
- name: Run some unit tests
run: ./gradlew testStageDebugUnitTest
- name: prepare gcloud
uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
with:
version: latest
service_account_email: ${{ secrets.SA_EMAIL }}
service_account_key: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
- name: gcloud Set up project
run: |
gcloud config set project ${{ secrets.PROJECT_ID }}
- name: Assemble apks for smoke test
run: ./gradlew Smoke
- name: Run tests in test lab
run: |
gcloud firebase test android run \
--app app/build/outputs/apk/production/debug/app.apk \
--test app/build/outputs/apk/androidTest/production/debug/appTest.apk \
--device model=Nexus6P,version=25,orientation=portrait,locale=en_US \
--device model=athene,version=23,orientation=portrait,locale=en_US \
--device model=sailfish,version=26,orientation=portrait,locale=en_US
It seems simple. Efficiency depends on the written tests and the selected code analysis rules. You can write several independent tasks (job) to run them in parallel. In my case, everything goes sequentially. The verification process takes about 15 minutes on our project (virtual machine github 2-core CPU, 7 GB RAM, 14 GB of SSD), but itโs not really critical, as long as you "code it" with your eyes, the results of these tests also arrive.UI tests help out the most - it happens that during their passage the analytics crashes after updating the library and you just understand that you should not update it.Through gcloud, you can also deliver builds to Firebase App Distribution, release to Google Play, etc.Many useful examples can be seen here and here .I hope this article is useful to someone. Good luck and less crashes on production!