Skip to content

Android Release

Android Release #541

name: Android Release
on:
workflow_dispatch:
inputs:
target_sha:
description: Git SHA to release. Leave empty to release the selected workflow ref.
required: false
type: string
permissions:
contents: read
id-token: write
jobs:
preflight:
name: Resolve Android release target
runs-on: ubuntu-24.04
outputs:
target_sha: ${{ steps.resolve.outputs.target_sha }}
android_version_code: ${{ steps.release-metadata.outputs.android_version_code }}
android_version_name: ${{ steps.release-metadata.outputs.android_version_name }}
android_target_short_sha: ${{ steps.release-metadata.outputs.android_target_short_sha }}
android_release_id: ${{ steps.release-metadata.outputs.android_release_id }}
android_play_release_name: ${{ steps.release-metadata.outputs.android_play_release_name }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ inputs.target_sha || github.sha }}
fetch-depth: 0
- name: Resolve release target
id: resolve
env:
INPUT_TARGET_SHA: ${{ inputs.target_sha }}
WORKFLOW_TARGET_SHA: ${{ github.sha }}
run: |
set -euo pipefail
target_sha="${INPUT_TARGET_SHA}"
if [[ -z "${target_sha}" ]]; then
target_sha="${WORKFLOW_TARGET_SHA}"
fi
target_sha="$(git rev-parse "${target_sha}")"
{
echo "target_sha=${target_sha}"
} >> "${GITHUB_OUTPUT}"
- name: Resolve Android release metadata
id: release-metadata
env:
TARGET_SHA: ${{ steps.resolve.outputs.target_sha }}
GITHUB_RUN_ID: ${{ github.run_id }}
GITHUB_RUN_ATTEMPT: ${{ github.run_attempt }}
run: |
set -euo pipefail
base_epoch_seconds=1767225600
current_epoch_seconds="$(date -u +%s)"
version_code=$(( current_epoch_seconds - base_epoch_seconds ))
version_name="$(sed -nE 's/^[[:space:]]*versionName[[:space:]]*=[[:space:]]*"([^"]+)".*$/\1/p' apps/android/app/build.gradle.kts | head -n 1)"
target_short_sha="$(printf '%s' "${TARGET_SHA}" | cut -c1-8)"
release_id="vc${version_code}-r${GITHUB_RUN_ID}a${GITHUB_RUN_ATTEMPT}-s${target_short_sha}"
play_release_name="main-draft-${release_id}"
if [[ "${version_code}" -le 0 ]]; then
echo "Resolved Android version code must be positive. Got: ${version_code}." >&2
exit 1
fi
if [[ "${version_code}" -gt 2100000000 ]]; then
echo "Resolved Android version code exceeds Google Play limit. Got: ${version_code}." >&2
exit 1
fi
if [[ -z "${version_name}" ]]; then
echo "Could not resolve Android versionName from apps/android/app/build.gradle.kts." >&2
exit 1
fi
if [[ "${#target_short_sha}" -ne 8 ]]; then
echo "Resolved target SHA prefix must be 8 characters. Got: ${target_short_sha}." >&2
exit 1
fi
{
echo "android_version_code=${version_code}"
echo "android_version_name=${version_name}"
echo "android_target_short_sha=${target_short_sha}"
echo "android_release_id=${release_id}"
echo "android_play_release_name=${play_release_name}"
} >> "${GITHUB_OUTPUT}"
- name: Summarize preflight
run: |
{
echo "## Android release preflight"
echo ""
echo "- Target SHA: \`${{ steps.resolve.outputs.target_sha }}\`"
echo "- Version code: \`${{ steps.release-metadata.outputs.android_version_code }}\`"
echo "- Version name: \`${{ steps.release-metadata.outputs.android_version_name }}\`"
echo "- Release ID: \`${{ steps.release-metadata.outputs.android_release_id }}\`"
echo "- Play release name: \`${{ steps.release-metadata.outputs.android_play_release_name }}\`"
echo "- Upload draft to Play: \`true\`"
echo "- Run Firebase Test Lab: \`true\`"
echo "- Play publish mode: \`draft production release uploaded by CI; final publish happens later in Play Console\`"
} >> "${GITHUB_STEP_SUMMARY}"
android_ci:
name: Android CI
needs:
- preflight
concurrency:
group: android-release-ci-main
cancel-in-progress: true
uses: ./.github/workflows/android-ci-reusable.yml
with:
target_ref: ${{ needs.preflight.outputs.target_sha }}
android_version_code: ${{ needs.preflight.outputs.android_version_code }}
secrets: inherit
firebase_test_lab_submission:
name: Firebase Test Lab app instrumentation
needs:
- preflight
- android_ci
if: ${{ needs.android_ci.result == 'success' }}
runs-on: ubuntu-24.04
timeout-minutes: 40
permissions:
contents: read
id-token: write
outputs:
submission_state: ${{ steps.collect.outputs.submission_state }}
matrix_id: ${{ steps.collect.outputs.matrix_id }}
results_path: ${{ steps.collect.outputs.results_path }}
device_descriptor: ${{ steps.collect.outputs.device_descriptor }}
steps:
- name: Validate Firebase Test Lab configuration
id: validate-config
env:
GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
GCP_SERVICE_ACCOUNT_EMAIL: ${{ vars.GCP_SERVICE_ACCOUNT_EMAIL }}
ANDROID_FTL_DEVICE_MODEL: ${{ vars.ANDROID_FTL_DEVICE_MODEL }}
ANDROID_FTL_DEVICE_VERSION: ${{ vars.ANDROID_FTL_DEVICE_VERSION }}
ANDROID_FTL_RESULTS_BUCKET: ${{ vars.ANDROID_FTL_RESULTS_BUCKET }}
ANDROID_FTL_RESULTS_DIR: ${{ vars.ANDROID_FTL_RESULTS_DIR }}
INPUT_RELEASE_ID: ${{ needs.preflight.outputs.android_release_id }}
run: |
set -euo pipefail
missing_values=()
for variable_name in \
GCP_PROJECT_ID \
GCP_WORKLOAD_IDENTITY_PROVIDER \
GCP_SERVICE_ACCOUNT_EMAIL \
ANDROID_FTL_DEVICE_MODEL \
ANDROID_FTL_DEVICE_VERSION \
ANDROID_FTL_RESULTS_BUCKET \
ANDROID_FTL_RESULTS_DIR; do
if [[ -z "${!variable_name}" ]]; then
missing_values+=("${variable_name}")
fi
done
results_dir=""
results_path=""
device_descriptor=""
if [[ -n "${ANDROID_FTL_RESULTS_DIR}" ]]; then
results_dir="${ANDROID_FTL_RESULTS_DIR%/}/${INPUT_RELEASE_ID}"
fi
if [[ -n "${ANDROID_FTL_RESULTS_BUCKET}" ]] && [[ -n "${results_dir}" ]]; then
results_path="${ANDROID_FTL_RESULTS_BUCKET%/}/${results_dir}"
fi
if [[ -n "${ANDROID_FTL_DEVICE_MODEL}" ]] && [[ -n "${ANDROID_FTL_DEVICE_VERSION}" ]]; then
device_descriptor="model=${ANDROID_FTL_DEVICE_MODEL},version=${ANDROID_FTL_DEVICE_VERSION},locale=en,orientation=portrait"
fi
if [[ "${#missing_values[@]}" -gt 0 ]]; then
printf 'Missing required GitHub Actions variables for Android app instrumentation: %s\n' "${missing_values[*]}" >&2
echo "Configure them with bash scripts/android/setup-github-android.sh or in the GitHub repository settings." >&2
echo "submission_state=configuration_invalid" >> "${GITHUB_OUTPUT}"
else
echo "submission_state=ready" >> "${GITHUB_OUTPUT}"
fi
{
echo "results_dir=${results_dir}"
echo "results_path=${results_path}"
echo "device_descriptor=${device_descriptor}"
} >> "${GITHUB_OUTPUT}"
- uses: actions/checkout@v7
if: ${{ steps.validate-config.outputs.submission_state == 'ready' }}
with:
ref: ${{ needs.preflight.outputs.target_sha }}
- uses: google-github-actions/auth@v3
id: auth
if: ${{ steps.validate-config.outputs.submission_state == 'ready' }}
continue-on-error: true
with:
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_SERVICE_ACCOUNT_EMAIL }}
project_id: ${{ vars.GCP_PROJECT_ID }}
- uses: google-github-actions/setup-gcloud@v3
id: setup-gcloud
if: ${{ steps.validate-config.outputs.submission_state == 'ready' && steps.auth.outcome == 'success' }}
continue-on-error: true
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
- name: Download debug APKs
id: download-debug-apks
if: ${{ steps.validate-config.outputs.submission_state == 'ready' && steps.auth.outcome == 'success' && steps.setup-gcloud.outcome == 'success' }}
continue-on-error: true
uses: actions/download-artifact@v8
with:
name: android-debug-apks
path: /tmp/android-debug-apks
- name: Resolve debug APK paths
id: resolve-debug-apks
if: ${{ steps.validate-config.outputs.submission_state == 'ready' && steps.auth.outcome == 'success' && steps.setup-gcloud.outcome == 'success' && steps.download-debug-apks.outcome == 'success' }}
continue-on-error: true
run: |
app_apk_path="$(find /tmp/android-debug-apks -type f -name 'app-debug.apk' | head -n 1)"
test_apk_path="$(find /tmp/android-debug-apks -type f -name 'app-debug-androidTest.apk' | head -n 1)"
if [[ -z "${app_apk_path}" ]]; then
echo "App APK not found in downloaded artifact." >&2
find /tmp/android-debug-apks -maxdepth 5 -type f >&2
exit 1
fi
if [[ -z "${test_apk_path}" ]]; then
echo "Android test APK not found in downloaded artifact." >&2
find /tmp/android-debug-apks -maxdepth 5 -type f >&2
exit 1
fi
printf 'APP_APK_PATH=%s\n' "${app_apk_path}" >> "${GITHUB_ENV}"
printf 'TEST_APK_PATH=%s\n' "${test_apk_path}" >> "${GITHUB_ENV}"
- name: Submit app instrumentation tests to Firebase Test Lab
id: submit
if: ${{ steps.validate-config.outputs.submission_state == 'ready' && steps.auth.outcome == 'success' && steps.setup-gcloud.outcome == 'success' && steps.download-debug-apks.outcome == 'success' && steps.resolve-debug-apks.outcome == 'success' }}
env:
GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
ANDROID_FTL_DEVICE_MODEL: ${{ vars.ANDROID_FTL_DEVICE_MODEL }}
ANDROID_FTL_DEVICE_VERSION: ${{ vars.ANDROID_FTL_DEVICE_VERSION }}
ANDROID_FTL_RESULTS_BUCKET: ${{ vars.ANDROID_FTL_RESULTS_BUCKET }}
RESULTS_DIR: ${{ steps.validate-config.outputs.results_dir }}
RELEASE_ID: ${{ needs.preflight.outputs.android_release_id }}
run: |
set -euo pipefail
command_output_file="${RUNNER_TEMP}/firebase-test-lab-submit.log"
set +e
bash scripts/android/run-android-firebase-test-lab.sh \
--project-id "${GCP_PROJECT_ID}" \
--device-model "${ANDROID_FTL_DEVICE_MODEL}" \
--device-version "${ANDROID_FTL_DEVICE_VERSION}" \
--app-path "${APP_APK_PATH}" \
--test-path "${TEST_APK_PATH}" \
--timeout "30m" \
--test-targets "package com.flashcardsopensourceapp.app" \
--results-bucket "${ANDROID_FTL_RESULTS_BUCKET}" \
--results-dir "${RESULTS_DIR}" \
--async \
> "${command_output_file}" 2>&1
command_exit_code=$?
set -e
cat "${command_output_file}"
matrix_id="$(grep -o 'matrix-[[:alnum:]]\+' "${command_output_file}" | head -n 1 || true)"
if [[ "${command_exit_code}" -eq 0 ]] && [[ -n "${matrix_id}" ]]; then
submission_state="submitted"
else
submission_state="submission_failed"
echo "Firebase Test Lab submission failed. Exit code: ${command_exit_code}. Release ID: ${RELEASE_ID}." >&2
fi
{
echo "submission_state=${submission_state}"
echo "matrix_id=${matrix_id}"
} >> "${GITHUB_OUTPUT}"
- name: Collect Firebase Test Lab outcome
if: always()
id: collect
env:
VALIDATION_STATE: ${{ steps.validate-config.outputs.submission_state }}
AUTH_STEP_OUTCOME: ${{ steps.auth.outcome }}
GCLOUD_STEP_OUTCOME: ${{ steps.setup-gcloud.outcome }}
DOWNLOAD_STEP_OUTCOME: ${{ steps.download-debug-apks.outcome }}
RESOLVE_STEP_OUTCOME: ${{ steps.resolve-debug-apks.outcome }}
SUBMIT_STATE: ${{ steps.submit.outputs.submission_state }}
SUBMIT_MATRIX_ID: ${{ steps.submit.outputs.matrix_id }}
RESULTS_PATH: ${{ steps.validate-config.outputs.results_path }}
DEVICE_DESCRIPTOR: ${{ steps.validate-config.outputs.device_descriptor }}
run: |
set -euo pipefail
submission_state="${VALIDATION_STATE}"
matrix_id="${SUBMIT_MATRIX_ID}"
if [[ "${VALIDATION_STATE}" == "ready" ]]; then
if [[ "${AUTH_STEP_OUTCOME}" != "success" ]]; then
submission_state="auth_failed"
elif [[ "${GCLOUD_STEP_OUTCOME}" != "success" ]]; then
submission_state="setup_failed"
elif [[ "${DOWNLOAD_STEP_OUTCOME}" != "success" ]]; then
submission_state="artifact_download_failed"
elif [[ "${RESOLVE_STEP_OUTCOME}" != "success" ]]; then
submission_state="artifact_resolution_failed"
elif [[ -n "${SUBMIT_STATE}" ]]; then
submission_state="${SUBMIT_STATE}"
else
submission_state="submission_failed"
fi
fi
{
echo "submission_state=${submission_state}"
echo "matrix_id=${matrix_id}"
echo "results_path=${RESULTS_PATH}"
echo "device_descriptor=${DEVICE_DESCRIPTOR}"
} >> "${GITHUB_OUTPUT}"
- name: Summarize Firebase Test Lab submission
if: always()
env:
SUBMISSION_STATE: ${{ steps.collect.outputs.submission_state }}
MATRIX_ID: ${{ steps.collect.outputs.matrix_id }}
RESULTS_PATH: ${{ steps.collect.outputs.results_path }}
DEVICE_DESCRIPTOR: ${{ steps.collect.outputs.device_descriptor }}
RELEASE_ID: ${{ needs.preflight.outputs.android_release_id }}
run: |
{
echo "## Firebase Test Lab submission"
echo ""
echo "- Submission state: \`${SUBMISSION_STATE}\`"
echo "- Release ID: \`${RELEASE_ID}\`"
echo "- Target SHA: \`${{ needs.preflight.outputs.target_sha }}\`"
echo "- Matrix ID: \`${MATRIX_ID:-n/a}\`"
echo "- Results path: \`${RESULTS_PATH:-n/a}\`"
echo "- Device: \`${DEVICE_DESCRIPTOR:-n/a}\`"
} >> "${GITHUB_STEP_SUMMARY}"
- name: Require Firebase Test Lab submission
if: always()
env:
SUBMISSION_STATE: ${{ steps.collect.outputs.submission_state }}
run: |
set -euo pipefail
if [[ "${SUBMISSION_STATE}" != "submitted" ]]; then
echo "Firebase Test Lab submission is required for Android Release. Submission state: ${SUBMISSION_STATE:-unknown}." >&2
exit 1
fi
publish_android:
name: Upload Android bundle to Google Play production draft release
needs:
- preflight
- android_ci
- firebase_test_lab_submission
if: ${{ needs.android_ci.result == 'success' && needs.firebase_test_lab_submission.result == 'success' }}
runs-on: ubuntu-24.04
timeout-minutes: 45
concurrency:
group: android-release-publish-main
cancel-in-progress: false
env:
ANDROID_VERSION_CODE: ${{ needs.preflight.outputs.android_version_code }}
ANDROID_VERSION_NAME: ${{ needs.preflight.outputs.android_version_name }}
ANDROID_RELEASE_ID: ${{ needs.preflight.outputs.android_release_id }}
ANDROID_PLAY_RELEASE_NAME: ${{ needs.preflight.outputs.android_play_release_name }}
ANDROID_SENTRY_DSN: ${{ vars.ANDROID_SENTRY_DSN }}
ANDROID_SENTRY_TRACES_SAMPLE_RATE: ${{ vars.ANDROID_SENTRY_TRACES_SAMPLE_RATE || '0' }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_ANDROID_PROJECT: ${{ vars.SENTRY_ANDROID_PROJECT }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.preflight.outputs.target_sha }}
- name: Validate Google Play configuration
env:
GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
GCP_PLAY_SERVICE_ACCOUNT_EMAIL: ${{ vars.GCP_PLAY_SERVICE_ACCOUNT_EMAIL }}
ANDROID_PLAY_PACKAGE_NAME: ${{ vars.ANDROID_PLAY_PACKAGE_NAME }}
run: |
missing_values=()
for variable_name in \
GCP_PROJECT_ID \
GCP_WORKLOAD_IDENTITY_PROVIDER \
GCP_PLAY_SERVICE_ACCOUNT_EMAIL \
ANDROID_PLAY_PACKAGE_NAME; do
if [[ -z "${!variable_name}" ]]; then
missing_values+=("${variable_name}")
fi
done
if [[ "${#missing_values[@]}" -gt 0 ]]; then
printf 'Missing required GitHub Actions variables: %s\n' "${missing_values[*]}" >&2
echo "Configure them in the GitHub repository settings or with bash scripts/android/setup-github-android.sh." >&2
exit 1
fi
- name: Validate Android Sentry configuration
env:
ANDROID_SENTRY_DSN: ${{ vars.ANDROID_SENTRY_DSN }}
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
SENTRY_ANDROID_PROJECT: ${{ vars.SENTRY_ANDROID_PROJECT }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: |
missing_values=()
for variable_name in \
ANDROID_SENTRY_DSN \
SENTRY_ORG \
SENTRY_ANDROID_PROJECT \
SENTRY_AUTH_TOKEN; do
if [[ -z "${!variable_name}" ]]; then
missing_values+=("${variable_name}")
fi
done
if [[ "${#missing_values[@]}" -gt 0 ]]; then
printf 'Missing required Android Sentry release values: %s\n' "${missing_values[*]}" >&2
echo "Configure repository variables/secrets or run bash scripts/android/setup-github-android.sh." >&2
exit 1
fi
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
- uses: gradle/actions/setup-gradle@v6.3.0
- uses: google-github-actions/auth@v3
id: auth
with:
create_credentials_file: true
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_PLAY_SERVICE_ACCOUNT_EMAIL }}
project_id: ${{ vars.GCP_PROJECT_ID }}
- name: Install Android SDK packages
env:
ANDROID_SDK_ROOT: /usr/local/lib/android/sdk
run: |
yes | "${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager" --licenses >/dev/null
"${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager" \
"platform-tools" \
"platforms;android-37.0" \
"build-tools;37.0.0"
- name: Validate Android signing secrets
env:
ANDROID_UPLOAD_KEYSTORE_BASE64: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_BASE64 }}
ANDROID_UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_PASSWORD }}
ANDROID_UPLOAD_KEY_ALIAS: ${{ secrets.ANDROID_UPLOAD_KEY_ALIAS }}
ANDROID_UPLOAD_KEY_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEY_PASSWORD }}
run: |
missing_secrets=()
for secret_name in \
ANDROID_UPLOAD_KEYSTORE_BASE64 \
ANDROID_UPLOAD_KEYSTORE_PASSWORD \
ANDROID_UPLOAD_KEY_ALIAS \
ANDROID_UPLOAD_KEY_PASSWORD; do
if [[ -z "${!secret_name}" ]]; then
missing_secrets+=("${secret_name}")
fi
done
if [[ "${#missing_secrets[@]}" -gt 0 ]]; then
printf 'Missing required GitHub Actions secrets: %s\n' "${missing_secrets[*]}" >&2
echo "Configure them in the GitHub repository settings or with bash scripts/android/setup-github-android.sh." >&2
exit 1
fi
- name: Prepare Android upload keystore
env:
ANDROID_UPLOAD_KEYSTORE_BASE64: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_BASE64 }}
run: |
keystore_path="${RUNNER_TEMP}/android-upload-key.jks"
printf '%s' "${ANDROID_UPLOAD_KEYSTORE_BASE64}" | base64 --decode > "${keystore_path}"
if [[ ! -s "${keystore_path}" ]]; then
echo "Decoded Android upload keystore is empty." >&2
exit 1
fi
printf 'ANDROID_KEYSTORE_PATH=%s\n' "${keystore_path}" >> "${GITHUB_ENV}"
- name: Build signed Android App Bundle
env:
ANDROID_UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_PASSWORD }}
ANDROID_UPLOAD_KEY_ALIAS: ${{ secrets.ANDROID_UPLOAD_KEY_ALIAS }}
ANDROID_UPLOAD_KEY_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEY_PASSWORD }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
run: |
bash scripts/android/run-android-release.sh \
--version-code "${ANDROID_VERSION_CODE}" \
--keystore-path "${ANDROID_KEYSTORE_PATH}" \
--keystore-password "${ANDROID_UPLOAD_KEYSTORE_PASSWORD}" \
--key-alias "${ANDROID_UPLOAD_KEY_ALIAS}" \
--key-password "${ANDROID_UPLOAD_KEY_PASSWORD}"
- name: Upload signed Android App Bundle artifact
uses: actions/upload-artifact@v7
with:
name: android-release-bundle
if-no-files-found: error
path: apps/android/app/build/outputs/bundle/release/app-release.aab
- name: Upload bundle to Google Play production track as draft release
uses: r0adkll/upload-google-play@v1.1.5
with:
serviceAccountJson: ${{ steps.auth.outputs.credentials_file_path }}
packageName: ${{ vars.ANDROID_PLAY_PACKAGE_NAME }}
releaseFiles: apps/android/app/build/outputs/bundle/release/app-release.aab
tracks: production
status: draft
releaseName: ${{ env.ANDROID_PLAY_RELEASE_NAME }}
- name: Summarize Play draft upload
run: |
{
echo "## Android Play draft upload"
echo ""
echo "- Release ID: \`${ANDROID_RELEASE_ID}\`"
echo "- Production track release name: \`${ANDROID_PLAY_RELEASE_NAME}\`"
echo "- Sentry release: \`com.flashcardsopensourceapp.app@${ANDROID_VERSION_NAME}+${ANDROID_VERSION_CODE}\`"
echo "- Version code: \`${ANDROID_VERSION_CODE}\`"
echo "- Version name: \`${ANDROID_VERSION_NAME}\`"
echo "- Target SHA: \`${{ needs.preflight.outputs.target_sha }}\`"
echo "- GitHub run: \`${{ github.run_id }}\` attempt \`${{ github.run_attempt }}\`"
echo "- GitHub run URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
echo "- Upload state: \`draft\`"
echo "- Firebase Test Lab: \`required submission in this Android Release run\`"
echo "- Next step: review Play App strings translations in Play Console, then publish the release manually."
} >> "${GITHUB_STEP_SUMMARY}"
release_summary:
name: Android release summary
if: ${{ always() }}
needs:
- preflight
- android_ci
- firebase_test_lab_submission
- publish_android
runs-on: ubuntu-24.04
steps:
- name: Summarize Android release outcome
run: |
{
echo "## Android release summary"
echo ""
echo "- Target SHA: \`${{ needs.preflight.outputs.target_sha }}\`"
echo "- Version code: \`${{ needs.preflight.outputs.android_version_code || 'n/a' }}\`"
echo "- Release ID: \`${{ needs.preflight.outputs.android_release_id || 'n/a' }}\`"
echo "- Play release name: \`${{ needs.preflight.outputs.android_play_release_name || 'n/a' }}\`"
echo "- Android CI result: \`${{ needs.android_ci.result }}\`"
echo "- Firebase Test Lab submission result: \`${{ needs.firebase_test_lab_submission.result }}\`"
echo "- Firebase Test Lab requested: \`true\`"
echo "- Play draft upload requested: \`true\`"
echo "- Android Play draft upload result: \`${{ needs.publish_android.result }}\`"
echo "- Firebase Test Lab submission: \`${{ needs.firebase_test_lab_submission.outputs.submission_state || 'n/a' }}\`"
echo "- Firebase Test Lab matrix ID: \`${{ needs.firebase_test_lab_submission.outputs.matrix_id || 'n/a' }}\`"
echo "- Firebase Test Lab results path: \`${{ needs.firebase_test_lab_submission.outputs.results_path || 'n/a' }}\`"
echo "- Firebase Test Lab device: \`${{ needs.firebase_test_lab_submission.outputs.device_descriptor || 'n/a' }}\`"
echo "- Play publish mode: \`CI uploads a production-track draft only; Play Console publication remains manual\`"
echo "- Run details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
} >> "${GITHUB_STEP_SUMMARY}"