fix(ios): update stale cacert.pem pinned checksum #5098
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: | |
| push: | |
| branches: | |
| - master | |
| - 'Stable*' | |
| tags: | |
| - 'v*' | |
| paths-ignore: | |
| - 'docs/**' | |
| pull_request: | |
| merge_group: | |
| workflow_dispatch: | |
| inputs: | |
| build_type: | |
| description: 'Build type' | |
| required: false | |
| default: 'Release' | |
| type: choice | |
| options: | |
| - Release | |
| - Debug | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} | |
| permissions: | |
| contents: read | |
| actions: read | |
| jobs: | |
| changes: | |
| uses: ./.github/workflows/_detect-changes.yml | |
| with: | |
| platform: android | |
| # The windows leg is the PR long pole by a decent amount; android_matrix.py drops it | |
| # for pull requests and keeps it for push / merge queue / dispatch. | |
| build-matrix: | |
| needs: changes | |
| if: needs.changes.outputs.should_build == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 1 | |
| outputs: | |
| include: ${{ steps.build.outputs.include }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| sparse-checkout: | | |
| .github/scripts/android_matrix.py | |
| .github/scripts/ci_bootstrap.py | |
| tools/_bootstrap.py | |
| tools/common/__init__.py | |
| tools/common/file_traversal.py | |
| tools/common/gh_actions.py | |
| sparse-checkout-cone-mode: false | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| - name: Build matrix | |
| id: build | |
| env: | |
| IS_PR: ${{ github.event_name == 'pull_request' && '1' || '0' }} | |
| run: python3 .github/scripts/android_matrix.py | |
| build: | |
| name: Android (${{ matrix.host }}) | |
| needs: [changes, build-matrix] | |
| if: needs.changes.outputs.should_build == 'true' | |
| # RunsOn runners only when the leg defines one, on mavlink, and not from a fork. | |
| runs-on: ${{ github.repository_owner == 'mavlink' && matrix.runson_runner != '' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && format('runs-on={0}/runner={1}', github.run_id, matrix.runson_runner) || matrix.fallback_runner }} | |
| timeout-minutes: 120 | |
| # id-token/attestations scoped here: only the "Attest and Upload" step needs them. | |
| permissions: | |
| contents: read | |
| actions: read | |
| id-token: write | |
| attestations: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: ${{ fromJSON(needs.build-matrix.outputs.include) }} | |
| defaults: | |
| run: | |
| shell: ${{ matrix.shell }} | |
| env: | |
| BUILD_TYPE: ${{ inputs.build_type || 'Release' }} | |
| PACKAGE: QGroundControl | |
| QT_ANDROID_KEYSTORE_PATH: ${{ github.workspace }}/deploy/android/android_release.keystore | |
| QT_ANDROID_KEYSTORE_ALIAS: QGCAndroidKeyStore | |
| QT_ANDROID_KEYSTORE_STORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| QT_ANDROID_KEYSTORE_KEY_PASS: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| QT_ANDROID_ABIS: >- | |
| ${{ matrix.emulator && 'x86_64' | |
| || (matrix.primary && github.event_name != 'pull_request' && github.event_name != 'pull_request_target') && 'arm64-v8a;armeabi-v7a' | |
| || 'arm64-v8a' }} | |
| HAS_PLAYSTORE_SECRET: ${{ secrets.GOOGLE_SERVICE_ACCOUNT != '' }} | |
| steps: | |
| - name: Enable RunsOn magic cache | |
| if: github.repository_owner == 'mavlink' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && matrix.host != 'mac' | |
| uses: runs-on/action@v2 | |
| with: | |
| metrics: cpu,network,memory,disk,io | |
| show_costs: summary | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@v2 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout repo | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: ${{ github.event_name == 'pull_request' && 1 || 0 }} | |
| persist-credentials: false | |
| # RunsOn images ship no Android SDK and don't preset ANDROID_SDK_ROOT (unlike | |
| # GitHub-hosted images), so setup-android@v4 has no install target. Point it | |
| # at a writable path. macOS stays GitHub-hosted with its preinstalled SDK. | |
| - name: Set Android SDK location | |
| if: matrix.host != 'mac' | |
| shell: bash | |
| run: | | |
| echo "ANDROID_SDK_ROOT=${RUNNER_TEMP}/android-sdk" >> "$GITHUB_ENV" | |
| echo "ANDROID_HOME=${RUNNER_TEMP}/android-sdk" >> "$GITHUB_ENV" | |
| - name: Build Setup (Android) | |
| id: setup | |
| uses: ./.github/actions/build-setup | |
| with: | |
| mode: android | |
| qt-host: ${{ matrix.qt_host || matrix.host }} | |
| qt-arch: ${{ matrix.arch }} | |
| aqt-source: ${{ matrix.aqt_source || '' }} | |
| abis: ${{ env.QT_ANDROID_ABIS }} | |
| build-type: ${{ env.BUILD_TYPE }} | |
| # matrix.host is unique per leg; linux and linux-emulator otherwise | |
| # resolve to identical cache inputs and would race on the moccache | |
| # save key. | |
| cache-key-suffix: ${{ matrix.host }} | |
| cpm-modules: ${{ runner.temp }}/build/cpm_modules | |
| - name: Install host build dependencies | |
| if: runner.os == 'Linux' | |
| uses: ./.github/actions/install-dependencies | |
| - name: Create Debug Keystore | |
| if: ${{ env.QT_ANDROID_KEYSTORE_STORE_PASS == '' || !matrix.primary }} | |
| shell: bash | |
| run: | | |
| keytool -genkey -v \ | |
| -keystore "${RUNNER_TEMP}/debug.keystore" \ | |
| -storepass android -alias androiddebugkey -keypass android \ | |
| -keyalg RSA -keysize 2048 -validity 10000 \ | |
| -dname "CN=Android Debug,O=Android,C=US" | |
| { | |
| echo "QT_ANDROID_KEYSTORE_PATH=${RUNNER_TEMP}/debug.keystore" | |
| echo "QT_ANDROID_KEYSTORE_ALIAS=androiddebugkey" | |
| echo "QT_ANDROID_KEYSTORE_STORE_PASS=android" | |
| echo "QT_ANDROID_KEYSTORE_KEY_PASS=android" | |
| } >> "$GITHUB_ENV" | |
| - name: Configure | |
| uses: ./.github/actions/cmake-configure | |
| with: | |
| build-dir: ${{ runner.temp }}/build | |
| build-type: ${{ env.BUILD_TYPE }} | |
| use-qt-cmake: 'false' | |
| extra-args: >- | |
| -DCMAKE_WARN_DEPRECATED=FALSE | |
| -DCMAKE_TOOLCHAIN_FILE=${{ steps.setup.outputs.target_qt_root_dir }}/lib/cmake/Qt6/qt.toolchain.cmake | |
| -DCMAKE_PREFIX_PATH=${{ steps.setup.outputs.target_qt_root_dir }} | |
| -DQT_ANDROID_ABIS=${{ env.QT_ANDROID_ABIS }} | |
| -DQT_HOST_PATH=${{ steps.setup.outputs.host_qt_root_dir }} | |
| -DQT_ANDROID_SIGN_APK=ON | |
| - name: Build | |
| id: build | |
| continue-on-error: ${{ matrix.emulator }} | |
| timeout-minutes: 75 | |
| # Disable Gradle daemon on CI — Windows runners hang for 30+ min after BUILD SUCCESSFUL waiting for daemon shutdown. | |
| env: | |
| GRADLE_OPTS: -Dorg.gradle.daemon=false | |
| uses: ./.github/actions/cmake-build | |
| with: | |
| build-dir: ${{ runner.temp }}/build | |
| build-type: ${{ env.BUILD_TYPE }} | |
| parallel-jobs: ${{ matrix.emulator && '2' || '' }} | |
| output-file: qgc-build.log | |
| - name: Retry Build (emulator JSON truncation recovery) | |
| id: build-retry | |
| if: ${{ matrix.emulator && steps.build.outcome == 'failure' }} | |
| shell: bash | |
| run: | | |
| python3 "${GITHUB_WORKSPACE}/.github/scripts/android_build_retry.py" \ | |
| --build-dir "${{ runner.temp }}/build" \ | |
| --build-type "${BUILD_TYPE}" | |
| # `failure()` is required: build's continue-on-error makes outcome alone insufficient. | |
| - name: Annotate emulator build retry failure | |
| if: ${{ failure() && matrix.emulator && steps.build.outcome == 'failure' && steps.build-retry.outcome == 'failure' }} | |
| run: echo "::error::Android emulator build failed (initial + retry). See logs for the truncation root cause." | |
| - name: Upload build log on failure | |
| if: ${{ failure() && steps.build.outcome == 'failure' }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: android-${{ matrix.host }}-build-log | |
| path: | | |
| ${{ runner.temp }}/build/qgc-build.log | |
| ${{ runner.temp }}/build/qgc-build-retry.log | |
| ${{ runner.temp }}/build/CMakeFiles/CMakeOutput.log | |
| ${{ runner.temp }}/build/CMakeFiles/CMakeError.log | |
| ${{ runner.temp }}/build/.ninja_log | |
| ${{ runner.temp }}/build/android-QGroundControl-deployment-settings.json | |
| if-no-files-found: ignore | |
| retention-days: 7 | |
| - name: Android Lint | |
| if: ${{ matrix.host == 'linux' }} | |
| shell: bash | |
| working-directory: ${{ runner.temp }}/build/android-build | |
| run: | | |
| if [[ ! -x "./gradlew" ]]; then | |
| echo "::error::Gradle wrapper not found in ${PWD}" | |
| ls -la | |
| exit 1 | |
| fi | |
| ./gradlew lintRelease --no-daemon | |
| - name: Prepare Artifact | |
| shell: bash | |
| run: | | |
| TEMP_DIR="${RUNNER_TEMP//\\//}" # Convert backslashes for Windows | |
| APK_DIR="${TEMP_DIR}/build/android-build" | |
| if ! ls "${APK_DIR}"/*.apk 1>/dev/null 2>&1; then | |
| echo "::error::No APK files found in ${APK_DIR}" | |
| ls -la "${APK_DIR}" 2>/dev/null || echo "Build directory does not exist" | |
| exit 1 | |
| fi | |
| cp "${APK_DIR}"/*.apk "${TEMP_DIR}/build/${{ env.PACKAGE }}.apk" | |
| - name: Emulator Boot Test | |
| if: ${{ matrix.emulator }} | |
| uses: ./.github/actions/android-emulator-test | |
| with: | |
| apk-path: ${{ runner.temp }}/build/${{ env.PACKAGE }}.apk | |
| package: org.mavlink.qgroundcontrol | |
| android-platform: ${{ steps.setup.outputs.android_platform }} | |
| qt-version: ${{ steps.setup.outputs.qt_version }} | |
| ndk-version: ${{ steps.setup.outputs.android_ndk_full_version }} | |
| diagnostics-name: ${{ matrix.host }} | |
| - name: Attest and Upload | |
| if: ${{ !matrix.emulator }} | |
| uses: ./.github/actions/attest-and-upload | |
| with: | |
| artifact-name: ${{ env.PACKAGE }}.apk | |
| package-name: ${{ format('{0}-{1}', env.PACKAGE, matrix.host) }} | |
| subject-name: ${{ env.PACKAGE }}-${{ matrix.host }} | |
| aws-role-arn: ${{ secrets.AWS_ROLE_ARN }} | |
| aws-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| aws-distribution-id: ${{ secrets.AWS_DISTRIBUTION_ID }} | |
| upload-aws: ${{ matrix.primary }} | |
| # Shell conditional, not a `&& x || y` GHA ternary whose `||` arm misfires | |
| # if the truthy arm ever evaluates falsy. tag -> production; master -> beta. | |
| - name: Compute Play Store rollout | |
| id: playstore_rollout | |
| if: ${{ !matrix.emulator && matrix.primary && env.HAS_PLAYSTORE_SECRET == 'true' && (github.ref_type == 'tag' || github.ref == 'refs/heads/master') }} | |
| env: | |
| REF_TYPE: ${{ github.ref_type }} | |
| run: | | |
| if [ "${REF_TYPE}" = "tag" ]; then | |
| { echo "track=production"; echo "status=inProgress"; echo "user_fraction=0.2"; } >> "${GITHUB_OUTPUT}" | |
| else | |
| { echo "track=beta"; echo "status=completed"; echo "user_fraction="; } >> "${GITHUB_OUTPUT}" | |
| fi | |
| - name: Deploy to Play Store | |
| if: ${{ !matrix.emulator && matrix.primary && env.HAS_PLAYSTORE_SECRET == 'true' && (github.ref_type == 'tag' || github.ref == 'refs/heads/master') }} | |
| uses: ./.github/actions/playstore | |
| with: | |
| artifact: ${{ runner.temp }}/build/${{ env.PACKAGE }}.apk | |
| service_account_json: ${{ secrets.GOOGLE_SERVICE_ACCOUNT }} | |
| track: ${{ steps.playstore_rollout.outputs.track }} | |
| status: ${{ steps.playstore_rollout.outputs.status }} | |
| user_fraction: ${{ steps.playstore_rollout.outputs.user_fraction }} | |
| whats_new_directory: ${{ github.workspace }}/deploy/android/whatsnew |