Files
MapLibreParticleLab/.github/workflows/android-ci.yml

424 lines
15 KiB
YAML

name: android-ci
permissions:
id-token: write # needed for AWS
on:
push:
branches:
- main
- android-*.*.x
tags:
- "android-*"
pull_request:
branches:
- "*"
concurrency:
# cancel jobs on PRs only
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
pre_job:
runs-on: ubuntu-latest
outputs:
should_skip: ${{ github.event_name != 'workflow_dispatch' && steps.changed-files.outputs.android_any_modified != 'true' }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: recursive
persist-credentials: false
- name: Get all Android files that have changed
if: github.event_name != 'workflow_dispatch'
id: changed-files
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
with:
files_yaml_from_source_file: .github/changed-files.yml
android-build:
runs-on: ubuntu-24.04
needs:
- pre_job
if: needs.pre_job.outputs.should_skip != 'true'
strategy:
fail-fast: false
matrix:
renderer: [opengl, vulkan, multiBackend]
defaults:
run:
working-directory: platform/android
env:
BUILDTYPE: Debug
IS_LOCAL_DEVELOPMENT: false
MLN_ANDROID_STL: c++_static
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN_ANDROID }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: recursive
persist-credentials: false
- uses: ./.github/actions/setup-android-ci
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: ".nvmrc"
- name: npm install
run: npm ci --ignore-scripts
working-directory: .
shell: bash
- name: run platform/android/scripts/generate-style-code.mjs
run: node platform/android/scripts/generate-style-code.mjs
working-directory: .
shell: bash
- run: |
python3 -m venv venv
source venv/bin/activate
pip3 install pre-commit
shell: bash
- run: |
source venv/bin/activate
pre-commit run clang-format --all-files
continue-on-error: true # this can mean files are modified, which is not an error
shell: bash
- run: |
source venv/bin/activate
pre-commit run clang-format --all-files
rm -rf venv
shell: bash
- if: env.SENTRY_DSN != ''
run: |
echo "SENTRY_ORG=maplibre" >> "$GITHUB_ENV"
echo "SENTRY_PROJECT=maplibre-android" >> "$GITHUB_ENV"
- uses: ./.github/actions/tree-is-clean
with:
check_untracked: true
- name: Configure sccache
uses: ./.github/actions/configure-sccache-s3
with:
vars: ${{ toJSON(vars) }}
- name: Check code style
if: matrix.renderer == 'opengl'
run: make android-check
- name: Run Android unit tests
run: RENDERER=${{ matrix.renderer }} make run-android-unit-test
- name: Build libmaplibre.so for arm-v8
run: RENDERER=${{ matrix.renderer }} make android-lib-arm-v8
- name: Build API documentation
if: matrix.renderer == 'opengl'
run: ./gradlew dokkaGenerate
- name: Build Examples documentation
if: matrix.renderer == 'opengl'
run: make mkdocs-build
- name: Copy developer config with API key for UI tests
if: github.ref == 'refs/heads/main'
run: |
MAPLIBRE_DEVELOPER_CONFIG_XML='${{ secrets.MAPLIBRE_DEVELOPER_CONFIG_XML }}'
if [ -n "${MAPLIBRE_DEVELOPER_CONFIG_XML}" ]; then
echo "${MAPLIBRE_DEVELOPER_CONFIG_XML}" > MapLibreAndroidTestApp/src/main/res/values/developer-config.xml
else
echo "No secrets.MAPLIBRE_DEVELOPER_CONFIG_XML variable set, not copying..."
fi
- name: Build Benchmark, copy to platform/android
run: |
./gradlew assemble${{ matrix.renderer }}Release assemble${{ matrix.renderer }}ReleaseAndroidTest -PtestBuildType=release -Pmaplibre.abis=arm64-v8a
cp MapLibreAndroidTestApp/build/outputs/apk/${{ matrix.renderer }}/release/MapLibreAndroidTestApp-${{ matrix.renderer }}-release.apk .
cp MapLibreAndroidTestApp/build/outputs/apk/androidTest/${{ matrix.renderer }}/release/MapLibreAndroidTestApp-${{ matrix.renderer }}-release-androidTest.apk .
# https://developer.android.com/guide/practices/page-sizes
- name: Check alignment of .apk
run: |
unzip -o MapLibreAndroidTestApp/build/outputs/apk/${{ matrix.renderer }}/release/MapLibreAndroidTestApp-${{ matrix.renderer }}-release.apk -d /tmp/my_apk_out
scripts/check-alignment.sh /tmp/my_apk_out
- name: Create artifact for benchmark APKs
if: matrix.renderer == 'opengl'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
if-no-files-found: error
name: benchmarkAPKs
path: |
platform/android/MapLibreAndroidTestApp-${{ matrix.renderer }}-release.apk
platform/android/MapLibreAndroidTestApp-${{ matrix.renderer }}-release-androidTest.apk
- if: github.event_name == 'pull_request' && matrix.renderer == 'opengl'
uses: ./.github/actions/save-pr-number
- name: Set renderer env var (OpenGL or Vulkan)
shell: bash
run: |
case "${{ matrix.renderer }}" in
opengl) echo "renderer=OpenGL" >> "$GITHUB_ENV" ;;
vulkan) echo "renderer=Vulkan" >> "$GITHUB_ENV" ;;
multiBackend) echo "renderer=MultiBackend" >> "$GITHUB_ENV" ;;
*) echo "::error ::Unknown renderer '${{ matrix.renderer }}'"; exit 1 ;;
esac
- name: Build Instrumentation Tests (${{ matrix.renderer }}), copy to platform/android
run: |
./gradlew assemble${{ matrix.renderer }}Debug assemble${{ matrix.renderer }}DebugAndroidTest -PtestBuildType=debug -Pmaplibre.abis=arm64-v8a
cp MapLibreAndroidTestApp/build/outputs/apk/${{ matrix.renderer }}/debug/MapLibreAndroidTestApp-${{ matrix.renderer }}-debug.apk InstrumentationTestApp${{ env.renderer }}.apk
cp MapLibreAndroidTestApp/build/outputs/apk/androidTest/${{ matrix.renderer }}/debug/MapLibreAndroidTestApp-${{ matrix.renderer }}-debug-androidTest.apk InstrumentationTests${{ env.renderer }}.apk
- name: Install sentry-cli
if: env.SENTRY_DSN != ''
run: curl -sL https://sentry.io/get-cli/ | sh
- name: Upload debug symbols to sentry
if: env.SENTRY_DSN != ''
run: sentry-cli debug-files upload MapLibreAndroidTestApp
- name: Upload android-ui-test-${{ matrix.renderer }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
if-no-files-found: error
name: android-ui-test-${{ matrix.renderer }}
path: |
platform/android/InstrumentationTestApp${{ env.renderer }}.apk
platform/android/InstrumentationTests${{ env.renderer }}.apk
- name: Show sccache stats
run: sccache --show-stats
android-build-cpp-test:
runs-on: ubuntu-24.04
needs:
- pre_job
if: needs.pre_job.outputs.should_skip != 'true'
defaults:
run:
working-directory: test/android
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: recursive
persist-credentials: false
- uses: ./.github/actions/setup-android-ci
- name: Create data.zip in assets directory
run: zip -r test/android/app/src/main/assets/data.zip -@ < test/android/app/src/main/assets/to_zip.txt
working-directory: .
- name: Configure sccache
uses: ./.github/actions/configure-sccache-s3
with:
vars: ${{ toJSON(vars) }}
- name: Build C++ Unit Tests App
run: |
./gradlew assembleDebug assembleAndroidTest -Pmaplibre.abis=arm64-v8a
cp app/build/outputs/apk/debug/app-debug.apk .
cp app/build/outputs/apk/androidTest/release/app-release-androidTest.apk .
- name: Store C++ Unit Tests .apk files
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: android-cpp-tests
if-no-files-found: error
path: |
./test/android/app-debug.apk
./test/android/app-release-androidTest.apk
android-build-render-test:
strategy:
fail-fast: false
matrix:
flavor: [opengl, vulkan]
runs-on: ubuntu-24.04
needs:
- pre_job
if: needs.pre_job.outputs.should_skip != 'true'
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: recursive
persist-credentials: false
- uses: ./.github/actions/setup-android-ci
- name: Configure sccache
uses: ./.github/actions/configure-sccache-s3
with:
vars: ${{ toJSON(vars) }}
- name: Build and Upload Render Test APKs (${{ matrix.flavor }})
uses: ./.github/actions/android-build-and-upload-render-test
with:
flavor: ${{ matrix.flavor }}
android-build-webgpu-dawn:
runs-on: ubuntu-24.04
needs:
- pre_job
if: needs.pre_job.outputs.should_skip != 'true'
defaults:
run:
working-directory: platform/android
env:
IS_LOCAL_DEVELOPMENT: false
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: recursive
persist-credentials: false
- uses: ./.github/actions/setup-android-ci
- name: Configure sccache
uses: ./.github/actions/configure-sccache-s3
with:
vars: ${{ toJSON(vars) }}
- name: Build WebGPU Dawn library for arm64-v8a
run: ./gradlew :MapLibreAndroid:assembleWebgpuDawnDebug -Pmaplibre.abis=arm64-v8a
- name: Show sccache stats
run: sccache --show-stats
android-build-webgpu-wgpu:
runs-on: ubuntu-24.04
needs:
- pre_job
if: needs.pre_job.outputs.should_skip != 'true'
defaults:
run:
working-directory: platform/android
env:
IS_LOCAL_DEVELOPMENT: false
ANDROID_ARCH: arm64-v8a
RUST_TARGET: aarch64-linux-android
C_COMPILER: aarch64-linux-android26-clang
BINDGEN_TARGET: aarch64-linux-android26
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: recursive
persist-credentials: false
- uses: ./.github/actions/setup-android-ci
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
with:
toolchain: stable
- name: Configure cargo for Android NDK linker
run: |
LATEST_NDK=$(find "$ANDROID_SDK_ROOT/ndk" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n 1)
NDK_BIN="$LATEST_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
mkdir -p ../../vendor/wgpu-native/.cargo
cat > ../../vendor/wgpu-native/.cargo/config.toml << EOF
[target.${{ env.RUST_TARGET }}]
linker = "$NDK_BIN/${{ env.C_COMPILER }}"
EOF
- name: Pre-build wgpu-native for Android
working-directory: vendor/wgpu-native
run: |
# vendor/wgpu-native pins its own rust toolchain; install targets for that active toolchain
ACTIVE_TOOLCHAIN=$(rustup show active-toolchain | awk '{print $1}')
rustup target add ${{ env.RUST_TARGET }} --toolchain "$ACTIVE_TOOLCHAIN"
rustup target list --toolchain "$ACTIVE_TOOLCHAIN" --installed | grep -x '${{ env.RUST_TARGET }}'
LATEST_NDK=$(find "$ANDROID_SDK_ROOT/ndk" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n 1)
NDK_PREBUILT="$LATEST_NDK/toolchains/llvm/prebuilt/linux-x86_64"
RESOURCE_DIR=$("$NDK_PREBUILT/bin/clang" --print-resource-dir)
BINDGEN_EXTRA_CLANG_ARGS=$(echo "${{ env.RUST_TARGET }}" | tr '-' '_')
export BINDGEN_EXTRA_CLANG_ARGS
ENV_VAR="BINDGEN_EXTRA_CLANG_ARGS_$BINDGEN_EXTRA_CLANG_ARGS"
export "${ENV_VAR}=--sysroot=$NDK_PREBUILT/sysroot --target=${{ env.BINDGEN_TARGET }} -isystem $RESOURCE_DIR/include"
cargo build --release --target ${{ env.RUST_TARGET }} --no-default-features --features vulkan,wgsl,spirv,glsl
- name: Configure sccache
uses: ./.github/actions/configure-sccache-s3
with:
vars: ${{ toJSON(vars) }}
- name: Build WebGPU wgpu-native library for Android
run: ./gradlew :MapLibreAndroid:assembleWebgpuWgpuDebug -Pmaplibre.abis=${{ env.ANDROID_ARCH }}
- name: Show sccache stats
run: sccache --show-stats
android-ci-result:
runs-on: ubuntu-latest
permissions:
actions: write
contents: write
if: needs.pre_job.outputs.should_skip != 'true' && always()
needs:
- pre_job
- android-build
- android-build-cpp-test
- android-build-render-test
- android-build-webgpu-dawn
- android-build-webgpu-wgpu
steps:
- name: Set success=true
if: needs.android-build.result == 'success' && needs.android-build-cpp-test.result == 'success' && needs.android-build-render-test.result == 'success' && needs.android-build-webgpu-dawn.result == 'success' && needs.android-build-webgpu-wgpu.result == 'success'
run: echo success=true > "$GITHUB_ENV"
- name: Mark result as failed
if: env.success != 'true'
run: exit 1
# automatically trigger android-release when code is pushed to main
# and the platform/android/VERSION file has changed
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
- name: VERSION file changed
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
id: version-file-android-changed
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
with:
files: platform/android/VERSION
- name: Should make release?
if: env.success && github.ref == 'refs/heads/main' && github.event_name == 'push' && steps.version-file-android-changed.outputs.any_changed == 'true'
run: echo make_release=true >> "$GITHUB_ENV"
- name: Validate and set version
if: env.make_release == 'true'
working-directory: .
run: .github/scripts/validate-version.sh platform/android/VERSION
- name: Create tag if it does not exist
if: env.make_release == 'true'
run: .github/scripts/ensure-tag.sh android-v${{ env.version }} ${{ github.sha }}
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Trigger release
if: env.make_release == 'true'
run: gh workflow run android-release.yml --ref android-v${{ env.version }}
env:
GH_TOKEN: ${{ github.token }}