-
Katharina Seiz authoredKatharina Seiz authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
config.yml 22.17 KiB
version: 2.1
orbs:
android: circleci/android@0.2.1
sonarcloud: sonarsource/sonarcloud@1.0.2
#######################
# Commands section
# For code reuse.
#######################
commands:
install-ndk: android/install-ndk
restore-android-build-cache: android/restore-build-cache
save-android-build-cache: android/save-build-cache
scan-sonar: sonarcloud/scan
restore-gradle-cache:
description: "Restore gradle caches"
steps:
- restore_cache:
key: gradle-v1-{{ arch }}-{{ checksum "build.gradle" }}-{{ checksum "Corona-Warn-App/build.gradle" }}-{{ checksum "Server-Protocol-Buffer/build.gradle" }}
save-gradle-cache:
description: "Save gradle caches"
steps:
- save_cache:
paths:
- ~/.gradle
key: gradle-v1-{{ arch }}-{{ checksum "build.gradle" }}-{{ checksum "Corona-Warn-App/build.gradle" }}-{{ checksum "Server-Protocol-Buffer/build.gradle" }}
restore-android-build-cache-macos:
description: "Restore Android build caches on macOS"
steps:
- restore_cache:
key: android-buildcache-v1-{{ arch }}
save-android-build-cache-macos:
description: "Save Android build caches on macOS"
steps:
- save_cache:
paths:
- ~/.android/build-cache
- ~/.android/cache
key: android-buildcache-v1-{{ arch }}-{{ epoch }}
run-gradle-cmd:
description: "Running gradle command with environment options"
parameters:
desc:
type: string
default: "Running gradle command"
cmd:
type: string
steps:
- run:
name: << parameters.desc >>
command: >
./gradlew -PdisablePreDex
<< parameters.cmd >>
no_output_timeout: 30m
environment:
JVM_OPTS: -Xmx4096m
GRADLE_OPTS: >
-Xmx1536m -XX:+HeapDumpOnOutOfMemoryError
-Dorg.gradle.caching=true
-Dorg.gradle.configureondemand=true
-Dkotlin.compiler.execution.strategy=in-process
-Dkotlin.incremental=false
run-gradle-cmd-test-splitting:
description: "Running gradle command with environment options and test splitting"
parameters:
desc:
type: string
default: "Running gradle command"
cmd:
type: string
steps:
- run:
name: Test splitting output
command: circleci tests glob "**/test*/**/*.kt" | circleci tests split | xargs -n 1 echo
- run:
name: << parameters.desc >>
command: >
./gradlew -PdisablePreDex
<< parameters.cmd >>
-i -PtestFilter="`circleci tests glob "**/test*/**/*.kt" | circleci tests split`"
environment:
JVM_OPTS: -Xmx4096m
GRADLE_OPTS: >
-Xmx1536m -XX:+HeapDumpOnOutOfMemoryError
-Dorg.gradle.caching=true
-Dorg.gradle.configureondemand=true
-Dkotlin.compiler.execution.strategy=in-process
-Dkotlin.incremental=false
skip-for-external-pull-requests:
description: "Skip for external pull requests due to missing access to secrets."
steps:
- run:
name: Early return if this build is from a forked PR
command: |
if [ -n "$CIRCLE_PR_NUMBER" ]; then
echo "Nothing to do for forked PRs, so marking this step successful"
circleci step halt
fi
setup-android-macos:
description: "Setup Android environment on macOS executor"
steps:
- restore_cache:
key: android-sdk-v1-{{ arch }}-{{ checksum ".circleci/install-android-sdk.sh" }}
- run:
name: Set ANDROID_SDK_ROOT environment variable
command: echo 'export ANDROID_SDK_ROOT=$HOME/android-sdk' >> $BASH_ENV
- run:
name: Install Android SDK
command: |
sh .circleci/install-android-sdk.sh
echo 'export PATH=$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$PATH' >> $BASH_ENV
echo 'export PATH=$ANDROID_SDK_ROOT/cmdline-tools/latest:$PATH' >> $BASH_ENV
echo 'export PATH=$ANDROID_SDK_ROOT/platform-tools:$PATH' >> $BASH_ENV
echo 'export PATH=$ANDROID_SDK_ROOT/emulator:$PATH' >> $BASH_ENV
echo 'export PATH=$ANDROID_SDK_ROOT/build-tools/29.0.3:$PATH' >> $BASH_ENV
source $BASH_ENV
sdkmanager --list
- save_cache:
key: android-sdk-v1-{{ arch }}-{{ checksum ".circleci/install-android-sdk.sh" }}
paths:
- /Users/distiller/android-sdk
run-emulator-for-api:
parameters:
apilevel:
type: integer
description: "Setup and start emulator for API<< parameters.apilevel >>"
steps:
- run:
name: Create emulator AVD
command: >
echo "no" | avdmanager --verbose create avd --force
--name "emulator_API<< parameters.apilevel >>"
--package "system-images;android-<< parameters.apilevel >>;google_apis;x86_64"
- run:
name: Configure emulator settings
command: |
cd $HOME/.android/avd/emulator_API<< parameters.apilevel >>.avd
sed -i '' -e 's/hw.lcd.density=[0-9]*/hw.lcd.density=560/g' config.ini
sed -i '' -e 's/hw.lcd.height=[0-9]*/hw.lcd.height=2880/g' config.ini
sed -i '' -e 's/hw.lcd.width=[0-9]*/hw.lcd.width=1440/g' config.ini
sed -i '' -e 's/hw.ramSize=[0-9]*/hw.ramSize=1536/g' config.ini
- run:
name: Check host state
command: |
emulator -accel-check
emulator -version
- run:
name: Start emulator AVD
command: >
emulator @emulator_API<< parameters.apilevel >>
-no-window
-no-audio
-no-boot-anim
-memory 2048
-nojni
background: true
no_output_timeout: 60m
- run:
name: Wait for emulator
command: |
adb wait-for-device shell 'while [[ -z $(getprop dev.bootcomplete) ]]; do sleep 1; done;'
adb devices
sleep 5
- run:
name: Disable animations
command: |
adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0
kill-all-emulators:
description: "Kill all emulators"
steps:
- run:
name: Kill all emulators
command: |
adb devices | grep emulator | cut -f1 | while read line; do adb -s $line emu kill; done
sleep 2
adb kill-server
sleep 2
compress-path:
parameters:
input:
type: string
output:
type: string
description: "Compress << parameters.input >> to << parameters.output >>"
steps:
- run:
name: Compress files
command: >
zip -r
<< parameters.output >>
<< parameters.input >>
setup-google-cloud:
description: "Setup Google Cloud access."
steps:
- run:
name: Store Google Service Account
command: echo $GCLOUD_SERVICE_KEY_BASE64 | base64 -di > ${HOME}/gcloud-service-key.json
- run:
name: Authorize gcloud and set config defaults
command: |
sudo gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json
sudo gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
#######################
# Jobs section
# Tasks that get executed
#######################
jobs:
detekt:
executor: android/android
resource_class: large
working_directory: ~/project
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: Detekt check
cmd: ":Corona-Warn-App:detekt"
- store_artifacts:
path: Corona-Warn-App/build/reports
destination: reports
quick_build_device_release_no_tests:
executor: android/android
resource_class: xlarge
working_directory: ~/project
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: Quick Build
cmd: "assembleDeviceRelease"
- save-gradle-cache
- save-android-build-cache
- store_artifacts:
path: Corona-Warn-App/build/reports
destination: reports
quick_build_device_for_testers_release_no_tests:
executor: android/android
resource_class: xlarge
working_directory: ~/project
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: Quick Build
cmd: ":Corona-Warn-App:assembleDeviceForTestersRelease"
- save-gradle-cache
- save-android-build-cache
- store_artifacts:
path: Corona-Warn-App/build/reports
destination: reports
unit_tests_device_release:
executor: android/android
resource_class: xlarge
working_directory: ~/project
parallelism: 3
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd-test-splitting:
desc: Unit tests
cmd: ":Corona-Warn-App:testDeviceReleaseUnitTest -i"
- save-gradle-cache
- save-android-build-cache
- store_test_results:
path: Corona-Warn-App/build/test-results
- persist_to_workspace:
root: /home/circleci
paths:
- ./project
- compress-path:
input: ./Corona-Warn-App/build/reports
output: /tmp/unit_tests_device_release.zip
- store_artifacts:
path: /tmp/unit_tests_device_release.zip
destination: zips/unit_tests_device_release.zip
unit_tests_device_for_testers_release:
executor: android/android
resource_class: xlarge
working_directory: ~/project
parallelism: 3
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd-test-splitting:
desc: Unit tests with splitting
cmd: ":Corona-Warn-App:testDeviceForTestersReleaseUnitTest"
- save-gradle-cache
- save-android-build-cache
- store_test_results:
path: Corona-Warn-App/build/test-results
- compress-path:
input: ./Corona-Warn-App/build/reports
output: /tmp/unit_tests_device_for_testers_release.zip
- store_artifacts:
path: /tmp/unit_tests_device_for_testers_release.zip
destination: zips/unit_tests_device_for_testers_release.zip
lint_device_release_check:
executor: android/android
resource_class: xlarge
working_directory: ~/project
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: Lint check deviceRelease
cmd: ":Corona-Warn-App:lintDeviceRelease -i"
- store_artifacts:
path: Corona-Warn-App/build/reports
destination: reports
lint_device_for_testers_release_check:
executor: android/android
resource_class: xlarge
working_directory: ~/project
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: Lint check deviceForTestersRelease
cmd: ":Corona-Warn-App:lintDeviceForTestersRelease -i"
- store_artifacts:
path: Corona-Warn-App/build/reports
destination: reports
ktlint_check:
executor: android/android
resource_class: medium
working_directory: ~/project
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: Ktlint check
cmd: ":Corona-Warn-App:ktlintCheck"
- store_artifacts:
path: Corona-Warn-App/build/reports
destination: reports
run_sonar:
executor: android/android
resource_class: xlarge
working_directory: ~/project
steps:
- skip-for-external-pull-requests
- attach_workspace:
at: /home/circleci
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: JaCoCo report
cmd: ":Corona-Warn-App:jacocoTestReportDeviceRelease -i"
- scan-sonar
quick_build_device_for_testers_signed:
executor: android/android
resource_class: xlarge
working_directory: ~/project
steps:
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run:
name: Download Keystore
command: |
curl --header "Authorization: token $keystore_download_token" --header "Accept: application/vnd.github.v3.raw" --remote-name --location "$keystore_download_url$keystore_download_filename"
- run:
name: Download Environment Properties
command: |
curl --header "Authorization: token $keystore_download_token" --header "Accept: application/vnd.github.v3.raw" --remote-name --location "$environments_download_url$env_prop_download_filename"
- run:
name: Decrypt Keystore
command: openssl enc -aes-256-cbc -d -pbkdf2 -iter 100000 -in $keystore_download_filename -out $keystore_filename -k $keystore_encrypt_key
- run:
name: Prepare commit hash
command: |
commit_hash=$(echo $CIRCLE_SHA1 | cut -c1-5)
echo $commit_hash
echo "" >> "./gradle.properties"
echo "commit_hash=$commit_hash" >> "./gradle.properties"
- run:
name: Prepare keystore properties for Signing
command: |
echo "" >> "./keystore.properties"
echo "deviceForTestersRelease.storePath=../$keystore_filename" >> "./keystore.properties"
echo "deviceForTestersRelease.storePassword=$keystore_password" >> "./keystore.properties"
echo "deviceForTestersRelease.keyAlias=$key_alias" >> "./keystore.properties"
echo "deviceForTestersRelease.keyPassword=$key_password" >> "./keystore.properties"
- run-gradle-cmd:
desc: Quick Build
cmd: ":Corona-Warn-App:assembleDeviceForTestersRelease"
- save-gradle-cache
- save-android-build-cache
- store_artifacts:
path: Corona-Warn-App/build/outputs/apk
destination: apk
- store_artifacts:
path: Corona-Warn-App/build/reports
destination: reports
- run:
name: Send to T-System
command: |
fileName=$(find Corona-Warn-App/build/outputs/apk/deviceForTesters/release -name '*Corona-Warn-App*.apk')
curl --location --request POST $tsystems_upload_url \
--header "Authorization: Bearer $tsystems_upload_bearer" \
--form "file=@${fileName}" \
instrumentation_tests_device:
resource_class: xlarge
docker:
- image: circleci/android:api-28
steps:
- skip-for-external-pull-requests
- setup-google-cloud
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: Build app APK
cmd: ":Corona-Warn-App:assembleDeviceForTestersDebug"
- run-gradle-cmd:
desc: Build instrumentation test APK
cmd: ":Corona-Warn-App:assembleDeviceForTestersDebugAndroidTest"
- run:
name: Setup Testlab environment
command: |
echo "export BUCKETDIR=\"`date "+%Y-%m-%d-%H:%M:%S:%3N"`-${RANDOM}\"" >> $BASH_ENV
source $BASH_ENV
echo "$BUCKETDIR is setup."
- run:
name: Test with Firebase Test Lab
command: |
echo "Using bucketdir $BUCKETDIR"
sudo gcloud firebase test android run \
--type instrumentation \
--app Corona-Warn-App/build/outputs/apk/deviceForTesters/debug/*.apk \
--test Corona-Warn-App/build/outputs/apk/androidTest/deviceForTesters/debug/*.apk \
--results-dir ${BUCKETDIR} \
--results-bucket ${GOOGLE_PROJECT_ID}-circleci-android \
--environment-variables clearPackageData=true \
--test-targets "notAnnotation testhelpers.Screenshot" \
--timeout 20m \
--device-ids flame \
--os-version-ids 29 \
--locales de_DE \
--orientations portrait \
--no-record-video
no_output_timeout: 30m
- run:
name: Create directory to store test results
command: mkdir firebase-results
when: always
- run:
name: Install gsutil dependency and copy test results data
command: |
sudo pip install -U crcmod
sudo gsutil -m cp -R -U gs://${GOOGLE_PROJECT_ID}-circleci-android/${BUCKETDIR}/flame* firebase-results
when: always
- store_test_results:
path: ./firebase-results/flame-29-de_DE-portrait
- compress-path:
input: ./firebase-results/flame-29-de_DE-portrait/*.xml
output: /tmp/instrumentation_tests_device.zip
- store_artifacts:
path: /tmp/instrumentation_tests_device.zip
destination: zips/instrumentation_tests_device.zip
# Keep it until Firebase Test Lab proves reliability
device_screenshots:
macos:
xcode: "12.3.0"
resource_class: large
steps:
- checkout
- restore_cache:
key: gem-cache-v1-{{ arch }}-{{ checksum "Gemfile.lock" }}
- run: bundle check || bundle install --path vendor/bundle
- save_cache:
key: gem-cache-v1-{{ arch }}-{{ checksum "Gemfile.lock" }}
paths:
- vendor/bundle
- setup-android-macos
- restore-gradle-cache
- restore-android-build-cache-macos
- run-gradle-cmd:
desc: Build APKs for screenshots
cmd: >
:Corona-Warn-App:assembleDebug
:Corona-Warn-App:assembleAndroidTest
- save-gradle-cache
- save-android-build-cache-macos
- run-emulator-for-api:
apilevel: 29
- run:
name: Run fastlane screengrab
command: |
for i in {1..5}; do bundle exec fastlane screengrab && break || sleep 15; done
no_output_timeout: 30m
- kill-all-emulators
- store_artifacts:
path: fastlane/metadata/android
destination: screenshots
- compress-path:
input: ./fastlane/metadata/android
output: /tmp/device_screenshots.zip
- store_artifacts:
path: /tmp/device_screenshots.zip
destination: zips/device_screenshots.zip
firebase_screenshots:
resource_class: xlarge
docker:
- image: circleci/android:api-28
steps:
- skip-for-external-pull-requests
- setup-google-cloud
- checkout
- restore-gradle-cache
- restore-android-build-cache
- run-gradle-cmd:
desc: Build APKs for screenshots
cmd: >
:Corona-Warn-App:assembleDebug
:Corona-Warn-App:assembleAndroidTest
- run:
name: Setup Testlab environment
command: |
echo "export BUCKETDIR=\"`date "+%Y-%m-%d-%H:%M:%S:%3N"`-${RANDOM}\"" >> $BASH_ENV
source $BASH_ENV
echo "$BUCKETDIR is setup."
- run:
name: Test with Firebase Test Lab
command: |
echo "Using bucketdir $BUCKETDIR"
sudo gcloud firebase test android run \
--type instrumentation \
--app Corona-Warn-App/build/outputs/apk/deviceForTesters/debug/*.apk \
--test Corona-Warn-App/build/outputs/apk/androidTest/deviceForTesters/debug/*.apk \
--results-dir ${BUCKETDIR} \
--results-bucket ${GOOGLE_PROJECT_ID}-circleci-android \
--environment-variables clearPackageData=true \
--test-targets "annotation testhelpers.Screenshot" \
--timeout 20m \
--device-ids flame \
--os-version-ids 29 \
--locales de_DE,en_US \
--orientations portrait \
--no-record-video
no_output_timeout: 30m
- run:
name: Create directory to store test results
command: mkdir firebase-screenshots
when: always
- run:
name: Install gsutil dependency and copy test results data
command: |
sudo pip install -U crcmod
sudo gsutil -m cp -R -U gs://${GOOGLE_PROJECT_ID}-circleci-android/${BUCKETDIR}/flame* firebase-screenshots
sudo chown -R circleci:circleci firebase-screenshots
when: always
- store_test_results:
path: ./firebase-screenshots
- run:
name: Clean up pulled bucket
command: |
rm -rf firebase-screenshots/*/artifacts/sdcard
rm -rf firebase-screenshots/*/test_cases
rm -f firebase-screenshots/*/instrumentation.results
rm -f firebase-screenshots/*/logcat
rm -f firebase-screenshots/*/test_result_1.xml
mkdir /tmp/screenshots
- compress-path:
input: ./firebase-screenshots
output: /tmp/screenshots/CWA-Android-Screenshots-${CIRCLE_SHA1}.zip
- store_artifacts:
path: /tmp/screenshots
destination: zips/
#######################
# Workflow section
# Job execution orders
#######################
workflows:
version: 2
check_buildtype_device:
jobs:
- detekt
- lint_device_release_check
- ktlint_check
- quick_build_device_release_no_tests
- unit_tests_device_release
- run_sonar:
requires:
- unit_tests_device_release
- instrumentation_tests_device:
requires:
- ktlint_check
- detekt
check_buildtype_device_for_testers:
jobs:
- detekt
- lint_device_for_testers_release_check
- ktlint_check
- quick_build_device_for_testers_release_no_tests
- unit_tests_device_for_testers_release
signed_build:
jobs:
- quick_build_device_for_testers_signed:
filters:
tags:
only:
- /^v.*/
branches:
ignore: /.*/
- firebase_screenshots:
filters:
tags:
only:
- /^v.*/
branches:
ignore: /.*/