CI: separate fastlane and build code...WIP #260
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build | |
on: | |
push: | |
branches: [ master ] | |
tags: | |
- v* | |
pull_request: | |
branches: [ master ] | |
env: | |
NDK_VERSION: '25.2.9519653' | |
NODE_VERSION: '16' | |
JAVA_VERSION: '17' | |
jobs: | |
build-rust: | |
name: Build aw-server-rust | |
runs-on: ubicloud-standard-8 | |
steps: | |
- uses: actions/checkout@v3 | |
with: | |
submodules: 'recursive' | |
- name: Set RELEASE | |
run: | | |
echo "RELEASE=${{ startsWith(github.ref_name, 'v') }}" >> $GITHUB_ENV | |
- name: Cache JNI libs | |
uses: actions/cache@v3 | |
id: cache-jniLibs | |
env: | |
cache-name: jniLibs | |
with: | |
path: mobile/src/main/jniLibs/ | |
key: ${{ env.cache-name }}-release-${{ env.RELEASE }}-ndk-${{ env.NDK_VERSION }}-${{ hashFiles('.git/modules/aw-server-rust/HEAD') }} | |
- name: Display structure of downloaded files | |
if: steps.cache-jniLibs.outputs.cache-hit == 'true' | |
run: | | |
pushd mobile/src/main/jniLibs && ls -R && popd | |
# Android SDK & NDK | |
- name: Set up Android SDK | |
if: steps.cache-jniLibs.outputs.cache-hit != 'true' | |
uses: android-actions/setup-android@v2 | |
- name: Set up Android NDK | |
if: steps.cache-jniLibs.outputs.cache-hit != 'true' | |
run: | | |
sdkmanager "ndk;${{ env.NDK_VERSION }}" | |
ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/${{ env.NDK_VERSION }}" | |
ls $ANDROID_NDK_HOME | |
echo "ANDROID_NDK_HOME=$ANDROID_NDK_HOME" >> $GITHUB_ENV | |
# Rust | |
- name: Set up Rust | |
id: toolchain | |
uses: dtolnay/rust-toolchain@stable | |
if: steps.cache-jniLibs.outputs.cache-hit != 'true' | |
- name: Set up Rust toolchain for Android NDK | |
if: steps.cache-jniLibs.outputs.cache-hit != 'true' | |
run: | | |
./aw-server-rust/install-ndk.sh | |
- name: Cache cargo build | |
uses: actions/cache@v3 | |
if: steps.cache-jniLibs.outputs.cache-hit != 'true' | |
env: | |
cache-name: cargo-build-target | |
with: | |
path: aw-server-rust/target | |
# key needs to contain cachekey due to https://github.com/ActivityWatch/aw-server-rust/issues/180 | |
key: ${{ env.cache-name }}-${{ runner.os }}-release-${{ env.RELEASE }}-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }} | |
restore-keys: | | |
${{ env.cache-name }}-${{ runner.os }}-release-${{ env.RELEASE }}-${{ steps.toolchain.outputs.cachekey }}- | |
- name: Build aw-server-rust | |
if: steps.cache-jniLibs.outputs.cache-hit != 'true' | |
run: | | |
make aw-server-rust | |
- name: Check that jniLibs present | |
run: | | |
test -e mobile/src/main/jniLibs/x86_64/libaw_server.so | |
# This needs to be a seperate job since fastlane update_version, | |
# fails if run concurrently (such as in build apk/aab matrix), | |
# thus we need to run it once and and reuse the results. | |
# https://github.com/fastlane/fastlane/issues/13689#issuecomment-439217502 | |
get-versionCode: | |
name: Get latest versionCode | |
runs-on: ubuntu-latest | |
outputs: | |
versionCode: ${{ steps.versionCode.outputs.versionCode }} | |
steps: | |
- uses: actions/checkout@v2 | |
with: | |
submodules: 'recursive' | |
# Ruby & Fastlane | |
# version set by .ruby-version | |
- name: Set up Ruby and install fastlane | |
uses: ruby/setup-ruby@v1 | |
with: | |
bundler-cache: true | |
# Needed for `fastlane update_version` | |
- uses: adnsio/[email protected] | |
- name: Load Fastlane secrets | |
env: | |
KEY_FASTLANE_API: ${{ secrets.KEY_FASTLANE_API }} | |
run: | | |
printf "$KEY_FASTLANE_API" > fastlane/api-8546008605074111507-287154-450dc77b365f.json.key | |
cat fastlane/api-8546008605074111507-287154-450dc77b365f.json.age \ | |
| age -d -i fastlane/api-8546008605074111507-287154-450dc77b365f.json.key \ | |
-o fastlane/api-8546008605074111507-287154-450dc77b365f.json | |
rm fastlane/api-8546008605074111507-287154-450dc77b365f.json.key | |
# Retry this, in case there are concurrent jobs, which may lead to the error: | |
# "Google Api Error: Invalid request - This Edit has been deleted." | |
- name: Update versionCode | |
uses: Wandalen/wretry.action@master | |
with: | |
command: bundle exec fastlane update_version | |
attempt_limit: 3 | |
attempt_delay: 20000 | |
- name: Output versionCode | |
id: versionCode | |
run: | | |
cat mobile/build.gradle | grep versionCode | sed 's/.*\s\([0-9]*\)$/versionCode=\1/' >> "$GITHUB_OUTPUT" | |
build-apk: | |
name: Build ${{ matrix.type }} | |
runs-on: ubicloud-standard-4 | |
needs: [build-rust, get-versionCode] | |
strategy: | |
fail-fast: true | |
matrix: | |
type: ['apk', 'aab'] | |
steps: | |
- uses: actions/checkout@v2 | |
with: | |
submodules: 'recursive' | |
- uses: ActivityWatch/check-version-format-action@v2 | |
id: version | |
with: | |
prefix: 'v' | |
- name: Echo version | |
run: | | |
echo "${{ steps.version.outputs.full }} (stable: ${{ steps.version.outputs.is_stable }})" | |
- name: Set RELEASE | |
run: | | |
# Build in release mode if on a tag/release (longer build times) | |
echo "RELEASE=${{ startsWith(github.ref_name, 'v') }}" >> $GITHUB_ENV | |
- name: Set up JDK | |
uses: actions/setup-java@v1 | |
with: | |
java-version: ${{ env.JAVA_VERSION }} | |
# Android SDK & NDK | |
- name: Set up Android SDK | |
uses: android-actions/setup-android@v2 | |
- name: Set up Android NDK | |
run: | | |
sdkmanager "ndk;${{ env.NDK_VERSION }}" | |
ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/${{ env.NDK_VERSION }}" | |
ls $ANDROID_NDK_HOME | |
echo "ANDROID_NDK_HOME=$ANDROID_NDK_HOME" >> $GITHUB_ENV | |
# Restores jniLibs from cache | |
# `actions/cache/restore` only restores, without saving back in a post-hook | |
- uses: actions/cache/restore@v3 | |
id: cache-jniLibs | |
env: | |
cache-name: jniLibs | |
with: | |
path: mobile/src/main/jniLibs/ | |
key: ${{ env.cache-name }}-release-${{ env.RELEASE }}-ndk-${{ env.NDK_VERSION }}-${{ hashFiles('.git/modules/aw-server-rust/HEAD') }} | |
fail-on-cache-miss: true | |
- name: Check that jniLibs present | |
run: | | |
test -e mobile/src/main/jniLibs/x86_64/libaw_server.so | |
- name: Set versionName | |
if: startsWith(github.ref, 'refs/tags/v') # only on runs triggered from tag | |
run: | | |
# Sets versionName, tail used to skip "v" at start of tag name | |
SHORT_VERSION=$(echo "${{ github.ref_name }}" | tail -c +2 -) | |
sed -i "s/versionName \".*\"/versionName \"$SHORT_VERSION\"/g" \ | |
mobile/build.gradle | |
- name: Set versionCode | |
run: | | |
# Sets versionCode | |
sed -i "s/versionCode .*/versionCode ${{needs.get-versionCode.outputs.versionCode}}/" \ | |
mobile/build.gradle | |
- uses: adnsio/[email protected] | |
- name: Load Android secrets | |
if: env.KEY_ANDROID_JKS != null | |
env: | |
KEY_ANDROID_JKS: ${{ secrets.KEY_ANDROID_JKS }} | |
run: | | |
printf "$KEY_ANDROID_JKS" > android.jks.key | |
cat android.jks.age | age -d -i android.jks.key -o android.jks | |
rm android.jks.key | |
- name: Assemble | |
env: | |
JKS_STOREPASS: ${{ secrets.KEY_ANDROID_JKS_STOREPASS }} | |
JKS_KEYPASS: ${{ secrets.KEY_ANDROID_JKS_KEYPASS }} | |
run: | | |
make dist/aw-android.${{ matrix.type }} | |
- name: Upload | |
uses: actions/upload-artifact@v3 | |
with: | |
name: aw-android | |
path: dist/aw-android*.${{ matrix.type }} | |
test: | |
name: Test | |
runs-on: ubuntu-20.04 | |
needs: [build-rust] | |
env: | |
SUPPLY_TRACK: production # used by fastlane to determine track to publish to | |
steps: | |
- uses: actions/checkout@v2 | |
with: | |
submodules: 'recursive' | |
- name: Set RELEASE | |
run: | | |
echo "RELEASE=${{ startsWith(github.ref_name, 'v') }}" >> $GITHUB_ENV | |
- name: Set up JDK | |
uses: actions/setup-java@v1 | |
with: | |
java-version: ${{ env.JAVA_VERSION }} | |
# Android SDK & NDK | |
- name: Set up Android SDK | |
uses: android-actions/setup-android@v2 | |
- name: Set up Android NDK | |
run: | | |
sdkmanager "ndk;${{ env.NDK_VERSION }}" | |
ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/${{ env.NDK_VERSION }}" | |
ls $ANDROID_NDK_HOME | |
echo "ANDROID_NDK_HOME=$ANDROID_NDK_HOME" >> $GITHUB_ENV | |
# Restores jniLibs from cache | |
# `actions/cache/restore` only restores, without saving back in a post-hook | |
- uses: actions/cache/restore@v3 | |
id: cache-jniLibs | |
env: | |
cache-name: jniLibs | |
with: | |
path: mobile/src/main/jniLibs/ | |
key: ${{ env.cache-name }}-release-${{ env.RELEASE }}-ndk-${{ env.NDK_VERSION }}-${{ hashFiles('.git/modules/aw-server-rust/HEAD') }} | |
fail-on-cache-miss: true | |
- name: Check that jniLibs present | |
run: | | |
test -e mobile/src/main/jniLibs/x86_64/libaw_server.so | |
# Test | |
- name: Test | |
run: | | |
make test | |
test-e2e: | |
name: Test E2E | |
needs: [build-rust] | |
#if: false # disabled | |
#runs-on: "macos-12" # macOS-latest | |
runs-on: ubicloud-standard-8 | |
env: | |
MATRIX_E_SDK: ${{ matrix.android_emu_version }} | |
MATRIX_AVD: ${{ matrix.android_avd }} | |
strategy: | |
fail-fast: false | |
max-parallel: 1 | |
matrix: | |
android_avd: [Pixel_API_27_AOSP] | |
include: | |
- android_avd: Pixel_API_27_AOSP | |
android_emu_version: 27 | |
# # # Cannot run > 27-emuLevel -_- https://github.com/actions/runner-images/issues/6527 | |
# - android_avd: Pixel_API_32_AOSP | |
# android_emu_version: 32 | |
steps: | |
- uses: actions/checkout@v2 | |
with: | |
submodules: 'recursive' | |
- name: Set RELEASE | |
run: | | |
echo "RELEASE=${{ startsWith(github.ref_name, 'v') }}" >> $GITHUB_ENV | |
# Restores jniLibs from cache | |
# `actions/cache/restore` only restores, without saving back in a post-hook | |
- uses: actions/cache/restore@v3 | |
id: cache-jniLibs | |
env: | |
cache-name: jniLibs | |
with: | |
path: mobile/src/main/jniLibs/ | |
key: ${{ env.cache-name }}-release-${{ env.RELEASE }}-ndk-${{ env.NDK_VERSION }}-${{ hashFiles('.git/modules/aw-server-rust/HEAD') }} | |
fail-on-cache-miss: true | |
- name: Display structure of downloaded files | |
run: | | |
pushd mobile/src/main/jniLibs && ls -R && popd | |
- name: Install intel-haxm | |
if: runner.os == 'macOS' | |
run: brew install intel-haxm | |
# # # Below code is majorly from https://github.com/actions/runner-images/issues/6152#issuecomment-1243718140 | |
- name: Create Android emulator | |
run: | | |
# Install AVD files | |
echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --install 'system-images;android-'$MATRIX_E_SDK';default;x86_64' | |
echo "y" | $ANDROID_HOME/tools/bin/sdkmanager --licenses | |
# Create emulator | |
$ANDROID_HOME/tools/bin/avdmanager create avd -n $MATRIX_AVD -d pixel --package 'system-images;android-'$MATRIX_E_SDK';default;x86_64' | |
$ANDROID_HOME/emulator/emulator -list-avds | |
if false; then | |
emulator_config=~/.android/avd/$MATRIX_AVD.avd/config.ini | |
# The following madness is to support empty OR populated config.ini files, | |
# the state of which is dependant on the version of the emulator used (which we don't control), | |
# so let's be defensive to be safe. | |
# Replace existing config (NOTE we're on MacOS so sed works differently!) | |
sed -i .bak 's/hw.lcd.density=.*/hw.lcd.density=420/' "$emulator_config" | |
sed -i .bak 's/hw.lcd.height=.*/hw.lcd.height=1920/' "$emulator_config" | |
sed -i .bak 's/hw.lcd.width=.*/hw.lcd.width=1080/' "$emulator_config" | |
# Or, add new config | |
if ! grep -q "hw.lcd.density" "$emulator_config"; then | |
echo "hw.lcd.density=420" >> "$emulator_config" | |
fi | |
if ! grep -q "hw.lcd.height" "$emulator_config"; then | |
echo "hw.lcd.height=1920" >> "$emulator_config" | |
fi | |
if ! grep -q "hw.lcd.width" "$emulator_config"; then | |
echo "hw.lcd.width=1080" >> "$emulator_config" | |
fi | |
echo "Emulator settings ($emulator_config)" | |
cat "$emulator_config" | |
fi | |
- name: Start Android emulator | |
timeout-minutes: 30 # ~4min normal - 3x DOSafety | |
env: | |
SUFFIX: ${{ matrix.android_avd }}-eAPI-${{ matrix.android_emu_version }} | |
HOMEBREW_NO_INSTALL_CLEANUP: 1 | |
run: | | |
echo "Starting emulator and waiting for boot to complete...." | |
ls -la $ANDROID_HOME/emulator | |
$ANDROID_HOME/tools/emulator --accel-check # check for hardware acceleration | |
nohup $ANDROID_HOME/tools/emulator -avd $MATRIX_AVD -gpu host -no-audio -no-boot-anim -camera-back none -camera-front none -qemu -m 2048 2>&1 & | |
$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed | tr -d '\r') ]]; do echo "wait..."; sleep 1; done; input keyevent 82' | |
echo "Emulator has finished booting" | |
$ANDROID_HOME/platform-tools/adb devices | |
sleep 30 | |
mkdir -p screenshots | |
screencapture screenshots/screenshot-$SUFFIX.jpg | |
$ANDROID_HOME/platform-tools/adb exec-out screencap -p > screenshots/emulator-$SUFFIX.png | |
# # # Have to re-setup everything since we need to run emulator for faster performance on masOS ? Other os'es emulator will not startup ? | |
# TODO: Optimize the steps taking into consideration all software present by default on macOS runner image | |
# # # Test # # reactiveCircus is giving a black screenshot not working | |
# # # TODO: Take a screenshot of OS to confirm if its Emulator issue or testcode/androidsdk issue - or maybe the emulator is screen off ? | |
# # # https://github.com/ReactiveCircus/android-emulator-runner | |
# - name: Test Cache | |
# uses: reactivecircus/android-emulator-runner@v2 | |
# with: | |
# api-level: ${{ matrix.android_emu_version }} | |
# arch: x86_64 | |
# profile: Nexus 6 | |
# target: google_apis | |
# emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim | |
# script: echo Meoooow ! | |
# - name: Test | |
# id: test | |
# uses: reactivecircus/android-emulator-runner@v2 | |
# with: | |
# api-level: ${{ matrix.android_emu_version }} | |
# arch: x86_64 | |
# profile: Nexus 6 | |
# target: google_apis | |
# emulator-options: -gpu swiftshader_indirect -noaudio -no-boot-anim -no-snapshot-save | |
# # Only running specific Instrumentation tests cause others are failing right now. TODO: Fix others | |
# script: ./gradlew connectedCheck -Pandroid.testInstrumentationRunnerArguments.class=net.activitywatch.android.ScreenshotTest --stacktrace | |
# - name: Install recorder and record session | |
# env: | |
# SUFFIX: ${{ matrix.android_avd }}-eAPI-${{ matrix.android_emu_version }}-${{ matrix.os }} | |
# run: | | |
# brew install ffmpeg | |
# $ANDROID_HOME/tools/emulator -help-all | |
# # -logcat *:v | |
# # $ANDROID_HOME/tools/emulator -port 18725 -verbose -no-audio -gpu swiftshader_indirect -logcat *:v @$MATRIX_AVD & | |
# ffmpeg -f avfoundation -i 0 -t 120 out$SUFFIX.mov & | |
- name: Set up JDK | |
uses: actions/setup-java@v1 | |
with: | |
java-version: ${{ env.JAVA_VERSION }} | |
# Android SDK & NDK | |
- name: Set up Android SDK | |
uses: android-actions/setup-android@v2 | |
- name: Set up Android NDK | |
run: | | |
sdkmanager "ndk;${{ env.NDK_VERSION }}" | |
ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/${{ env.NDK_VERSION }}" | |
ls $ANDROID_NDK_HOME | |
echo "ANDROID_NDK_HOME=$ANDROID_NDK_HOME" >> $GITHUB_ENV | |
- name: Run E2E tests | |
timeout-minutes: 20 | |
id: test | |
run: | | |
make test-e2e | |
- name: Output and save logcat to file | |
if: ${{ success() || steps.test.conclusion == 'failure'}} | |
run: | | |
mkdir -p mobile/build | |
adb logcat -d > mobile/build/logcat.log | |
adb logcat -v color & | |
- name: Screenshot | |
if: ${{ success() || steps.test.conclusion == 'failure'}} | |
env: | |
SUFFIX: ${{ matrix.android_avd }}-eAPI-${{ matrix.android_emu_version }} | |
run: | | |
adb shell monkey -p net.activitywatch.android.debug 1 | |
sleep 10 | |
screencapture screenshots/pscreenshot-$SUFFIX.jpg | |
$ANDROID_HOME/platform-tools/adb exec-out screencap -p > screenshots/pemulator-$SUFFIX.png | |
ls -alh screenshots/ | |
- name: Upload logcat | |
if: ${{ success() || steps.test.conclusion == 'failure'}} | |
uses: actions/upload-artifact@v3 | |
with: | |
name: logcat | |
# mobile\build\outputs\connected_android_test_additional_output\debugAndroidTest\connected\Pixel_XL_API_32(AVD) - 12\ScreenshotTest_saveDeviceScreenBitmap.png | |
path: | | |
mobile/build/logcat.log | |
#mobile/build/reports/* | |
# - name: Upload video | |
# if: ${{ success() || steps.test.conclusion == 'failure'}} | |
# uses: actions/upload-artifact@master | |
# with: | |
# name: video | |
# path: ./*.mov # out.mov | |
- name: Upload screenshots | |
uses: actions/upload-artifact@v3 | |
if: ${{ success() || steps.test.conclusion == 'failure'}} | |
with: | |
name: screenshots | |
path: | | |
screenshots/* | |
**/mobile/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/* | |
#- name: Publish Test Report | |
# # # uses: mikepenz/action-junit-report@v3 | |
# # # # # TODO: Format a little ? or Use some utility to confier GITHUB_STE_SUMMARY.html below into markdown before outputting it into $GITHUB_STEP_SUMMARY? | |
# if: ${{ success() || steps.test.conclusion == 'failure'}} | |
# # # with: | |
# # # report_paths: '**/build/reports/*Tests/**/*.html' # '**/build/test-results/test/TEST-*.xml' | |
# run: | | |
# for file in ./mobile/build/reports/androidTests/connected/*.html; do cat $file >> GITHUB_STEP_SUMMARY.html ; done | |
# # echo '<style>' >> GITHUB_STEP_SUMMARY.html;for file in ./mobile/build/reports/androidTests/connected/**/*.css; do cat $file >> GITHUB_STEP_SUMMARY.html ; done; echo '</style>' >> GITHUB_STEP_SUMMARY.html; | |
# cat GITHUB_STEP_SUMMARY.html >> $GITHUB_STEP_SUMMARY | |
release-fastlane: | |
needs: [build-apk, test] | |
if: startsWith(github.ref, 'refs/tags/v') # only on runs triggered from tag | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v3 | |
- name: Download APK & AAB | |
uses: actions/download-artifact@v3 | |
with: | |
name: aw-android | |
path: dist | |
- name: Display structure of downloaded files | |
working-directory: dist | |
run: ls -R | |
# Ruby & Fastlane | |
# version set by .ruby-version | |
- name: Set up Ruby and install fastlane | |
uses: ruby/setup-ruby@v1 | |
with: | |
bundler-cache: true | |
# detect if version tag is stable/beta | |
- uses: nowsprinting/check-version-format-action@v2 | |
id: version | |
with: | |
prefix: 'v' | |
- name: Set SUPPLY_TRACK | |
run: | | |
# Set SUPPLY_TRACK (used by fastlane) depending on is_stable | |
if [[ "${{ steps.version.outputs.is_stable }}" == "true" ]]; then | |
SUPPLY_TRACK="production" | |
else | |
SUPPLY_TRACK="internal" | |
fi | |
echo "SUPPLY_TRACK=${SUPPLY_TRACK}" >> $GITHUB_ENV | |
- uses: adnsio/[email protected] | |
- name: Load Android secrets | |
env: | |
KEY_FASTLANE_API: ${{ secrets.KEY_FASTLANE_API }} | |
run: | | |
printf "$KEY_FASTLANE_API" > fastlane/api-8546008605074111507-287154-450dc77b365f.json.key | |
cat fastlane/api-8546008605074111507-287154-450dc77b365f.json.age \ | |
| age -d -i fastlane/api-8546008605074111507-287154-450dc77b365f.json.key \ | |
-o fastlane/api-8546008605074111507-287154-450dc77b365f.json | |
rm fastlane/api-8546008605074111507-287154-450dc77b365f.json.key | |
- name: Release with fastlane | |
run: | | |
# bundle exec fastlane supply run --apk dist/*.apk | |
bundle exec fastlane supply run --aab dist/*.aab | |
release-gh: | |
needs: [build-apk, test] | |
if: startsWith(github.ref, 'refs/tags/v') # only on runs triggered from tag | |
runs-on: ubuntu-latest | |
steps: | |
# Will download all artifacts to path | |
- name: Download release APK & AAB | |
uses: actions/download-artifact@v3 | |
with: | |
name: aw-android | |
path: dist | |
- name: Display structure of downloaded files | |
working-directory: dist | |
run: ls -R | |
# detect if version tag is stable/beta | |
- uses: nowsprinting/check-version-format-action@v2 | |
id: version | |
with: | |
prefix: 'v' | |
# create a release | |
- name: Release | |
uses: softprops/action-gh-release@v1 | |
with: | |
draft: true | |
prerelease: ${{ !(steps.version.outputs.is_stable == 'true') }} # must compare to true, since boolean outputs are actually just strings, and "false" is truthy since it's not empty: https://github.com/actions/runner/issues/1483#issuecomment-994986996 | |
files: | | |
dist/*.apk | |
dist/*.aab | |
# body_path: dist/release_notes/release_notes.md | |