feat: measure TV playback quality #326
This file contains hidden or 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: Android | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| workflow_dispatch: | |
| inputs: | |
| publish_release: | |
| description: Publish a GitHub release | |
| required: true | |
| type: boolean | |
| default: false | |
| tag_name: | |
| description: Release tag, leave empty to use the Gradle version | |
| required: false | |
| default: "" | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: >- | |
| android-${{ github.workflow }}-${{ | |
| github.event_name == 'push' && 'push' || | |
| github.event_name == 'workflow_dispatch' && inputs.publish_release && | |
| github.ref == 'refs/heads/main' && 'release' || | |
| github.ref | |
| }} | |
| cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' || !inputs.publish_release || github.ref != 'refs/heads/main' }} | |
| env: | |
| CI: true | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| JAVA_TOOL_OPTIONS: -Djava.awt.headless=true | |
| GRADLE_OPTS: -Dorg.gradle.workers.max=8 -Dorg.gradle.daemon.idletimeout=900000 | |
| ANDROID_HOME: /opt/android-sdk | |
| ANDROID_SDK_ROOT: /opt/android-sdk | |
| JAVA_HOME: /usr/lib/jvm/java-26-openjdk | |
| GRADLE_USER_HOME: /var/tmp/typetype-android-gradle-user-home | |
| TYPETYPE_SDK_PATH: .ci/TypeType-SDK | |
| jobs: | |
| verify: | |
| if: ${{ github.event_name != 'workflow_dispatch' || !inputs.publish_release || github.ref != 'refs/heads/main' }} | |
| runs-on: [self-hosted, Linux, X64, arko, android] | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7.0.1 | |
| - name: Install Android SDK platform | |
| run: | | |
| platform="$ANDROID_HOME/platforms/android-37.0" | |
| ( | |
| flock 9 | |
| if [ ! -f "$platform/android.jar" ]; then | |
| rm -rf "$platform" | |
| "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" \ | |
| --sdk_root="$ANDROID_HOME" \ | |
| "platforms;android-37.0" | |
| fi | |
| test -f "$platform/android.jar" | |
| ) 9>"$ANDROID_HOME/.platform-install.lock" | |
| - name: Verify Android project | |
| timeout-minutes: 25 | |
| run: | | |
| set -euo pipefail | |
| tasks=( | |
| :baseline-profile:assemble | |
| :player:testDebugUnitTest | |
| :app:testDebugUnitTest | |
| :player:lintDebug | |
| :app:lintDebug | |
| :app:assembleDebug | |
| :app:assembleRelease | |
| ) | |
| if [[ -f "$TYPETYPE_SDK_PATH/settings.gradle.kts" ]]; then | |
| tasks+=( | |
| :tv:testDebugUnitTest | |
| :tv:lintDebug | |
| :tv:assembleDebug | |
| ) | |
| else | |
| echo "::notice::TV verification skipped because the private TypeType-SDK checkout is unavailable." | |
| fi | |
| ./gradlew --build-cache --stacktrace "${tasks[@]}" | |
| - name: Upload debug APK | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: typetype-debug-apk | |
| path: | | |
| app/build/outputs/apk/debug/*.apk | |
| tv/build/outputs/apk/debug/*.apk | |
| if-no-files-found: error | |
| compression-level: 0 | |
| retention-days: 14 | |
| - name: Upload lint report | |
| if: ${{ always() }} | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: lint-report | |
| path: | | |
| app/build/reports/lint-results-debug.html | |
| player/build/reports/lint-results-debug.html | |
| tv/build/reports/lint-results-debug.html | |
| if-no-files-found: ignore | |
| retention-days: 14 | |
| release: | |
| if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'workflow_dispatch' && inputs.publish_release }} | |
| runs-on: [self-hosted, Linux, X64, arko, android] | |
| timeout-minutes: 35 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7.0.1 | |
| - name: Install Android SDK platform | |
| run: | | |
| platform="$ANDROID_HOME/platforms/android-37.0" | |
| ( | |
| flock 9 | |
| if [ ! -f "$platform/android.jar" ]; then | |
| rm -rf "$platform" | |
| "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" \ | |
| --sdk_root="$ANDROID_HOME" \ | |
| "platforms;android-37.0" | |
| fi | |
| test -f "$platform/android.jar" | |
| ) 9>"$ANDROID_HOME/.platform-install.lock" | |
| - name: Prepare release metadata | |
| env: | |
| INPUT_TAG_NAME: ${{ inputs.tag_name }} | |
| run: | | |
| version="$(sed -nE 's/^[[:space:]]*versionName = "([^"]+)"/\1/p' app/build.gradle.kts)" | |
| test -n "$version" | |
| expected_tag="v$version" | |
| release_tag="${INPUT_TAG_NAME:-$expected_tag}" | |
| test "$release_tag" = "$expected_tag" | |
| echo "RELEASE_VERSION=$version" >> "$GITHUB_ENV" | |
| echo "RELEASE_TAG=$release_tag" >> "$GITHUB_ENV" | |
| - name: Prepare signing | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| run: | | |
| test -n "$ANDROID_KEYSTORE_BASE64" | |
| test -n "$ANDROID_KEYSTORE_PASSWORD" | |
| test -n "$ANDROID_KEY_ALIAS" | |
| test -n "$ANDROID_KEY_PASSWORD" | |
| printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 --decode > release.keystore | |
| { | |
| printf 'storeFile=%s\n' "$PWD/release.keystore" | |
| printf 'storePassword=%s\n' "$ANDROID_KEYSTORE_PASSWORD" | |
| printf 'keyAlias=%s\n' "$ANDROID_KEY_ALIAS" | |
| printf 'keyPassword=%s\n' "$ANDROID_KEY_PASSWORD" | |
| } > keystore.properties | |
| - name: Verify Android project and build release | |
| timeout-minutes: 25 | |
| run: | | |
| set -euo pipefail | |
| tasks=( | |
| :baseline-profile:assemble | |
| :player:testDebugUnitTest | |
| :app:testDebugUnitTest | |
| :player:lintDebug | |
| :app:lintDebug | |
| :app:assembleDebug | |
| :app:assembleRelease | |
| ) | |
| if [[ -f "$TYPETYPE_SDK_PATH/settings.gradle.kts" ]]; then | |
| tasks+=( | |
| :tv:testDebugUnitTest | |
| :tv:lintDebug | |
| :tv:assembleDebug | |
| ) | |
| else | |
| echo "::notice::TV verification skipped because the private TypeType-SDK checkout is unavailable." | |
| fi | |
| ./gradlew --build-cache --stacktrace "${tasks[@]}" | |
| - name: Upload lint report | |
| if: ${{ always() }} | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: lint-report | |
| path: | | |
| app/build/reports/lint-results-debug.html | |
| player/build/reports/lint-results-debug.html | |
| tv/build/reports/lint-results-debug.html | |
| if-no-files-found: ignore | |
| retention-days: 14 | |
| - name: Prepare APK artifact | |
| run: | | |
| mkdir -p artifacts | |
| apk="$(find app/build/outputs/apk/release -name '*.apk' | head -n 1)" | |
| test -n "$apk" | |
| build_tools="$(find "$ANDROID_HOME/build-tools" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n 1)" | |
| test -n "$build_tools" | |
| "$build_tools/zipalign" -c -P 16 -v 4 "$apk" | |
| "$build_tools/apksigner" verify --verbose --print-certs "$apk" | |
| apk_version="$("$ANDROID_HOME/cmdline-tools/latest/bin/apkanalyzer" manifest version-name "$apk")" | |
| test "$apk_version" = "$RELEASE_VERSION" | |
| cp "$apk" "artifacts/TypeType-$RELEASE_TAG.apk" | |
| ( | |
| cd artifacts | |
| sha256sum "TypeType-$RELEASE_TAG.apk" \ | |
| > "TypeType-$RELEASE_TAG.apk.sha256" | |
| ) | |
| - name: Upload release APK | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: typetype-release-apk | |
| path: | | |
| artifacts/*.apk | |
| artifacts/*.sha256 | |
| if-no-files-found: error | |
| compression-level: 0 | |
| retention-days: 30 | |
| - name: Publish GitHub release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ env.RELEASE_TAG }} | |
| name: ${{ env.RELEASE_TAG }} | |
| body_path: release-notes/${{ env.RELEASE_TAG }}.md | |
| files: | | |
| artifacts/*.apk | |
| artifacts/*.sha256 | |
| fail_on_unmatched_files: true |