From 9b9535aa7892d86d7337a03e9a0fdee04a83a8a2 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 17 Feb 2026 21:36:15 +0700 Subject: [PATCH] ci: publish Android APK to GitHub releases --- .github/workflows/android-apk-release.yml | 119 ++++++++++++++++++++++ CLAUDE.md | 4 +- 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/android-apk-release.yml diff --git a/.github/workflows/android-apk-release.yml b/.github/workflows/android-apk-release.yml new file mode 100644 index 000000000..ba4fc3a73 --- /dev/null +++ b/.github/workflows/android-apk-release.yml @@ -0,0 +1,119 @@ +name: Android APK Release + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + tag: + description: "Existing tag to build (e.g. v0.1.0)" + required: true + type: string + +concurrency: + group: android-apk-release-${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref }} + cancel-in-progress: false + +env: + RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref_name }} + +jobs: + publish-android-apk: + permissions: + contents: write + packages: read + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref }} + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "22" + cache: "npm" + registry-url: "https://npm.pkg.github.com" + scope: "@boudra" + + - name: Install JS dependencies + run: npm ci + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Expo and EAS + uses: expo/expo-github-action@v8 + with: + eas-version: latest + token: ${{ secrets.EXPO_TOKEN }} + + - name: Build Android APK on EAS + id: eas_build + shell: bash + run: | + set -euo pipefail + cd packages/app + + build_json="$(npx eas build --platform android --profile production-apk --non-interactive --wait --json)" + echo "$build_json" > "$RUNNER_TEMP/eas-build.json" + + build_id="$(jq -r 'if type == "array" then .[0].id // empty else .id // empty end' "$RUNNER_TEMP/eas-build.json")" + if [ -z "$build_id" ]; then + echo "Failed to determine EAS build ID." + cat "$RUNNER_TEMP/eas-build.json" + exit 1 + fi + + echo "build_id=$build_id" >> "$GITHUB_OUTPUT" + + - name: Resolve APK artifact URL + id: artifact + shell: bash + run: | + set -euo pipefail + cd packages/app + + build_view_json="$(npx eas build:view '${{ steps.eas_build.outputs.build_id }}' --json)" + echo "$build_view_json" > "$RUNNER_TEMP/eas-build-view.json" + + artifact_url="$(jq -r '.artifacts.buildUrl // .artifacts.applicationArchiveUrl // empty' "$RUNNER_TEMP/eas-build-view.json")" + if [ -z "$artifact_url" ]; then + echo "Failed to determine APK artifact URL." + cat "$RUNNER_TEMP/eas-build-view.json" + exit 1 + fi + + asset_name="paseo-${RELEASE_TAG}-android.apk" + asset_path="$RUNNER_TEMP/$asset_name" + + curl --fail --location --output "$asset_path" "$artifact_url" + + echo "asset_name=$asset_name" >> "$GITHUB_OUTPUT" + echo "asset_path=$asset_path" >> "$GITHUB_OUTPUT" + + - name: Wait for GitHub release tag + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + set -euo pipefail + for attempt in $(seq 1 90); do + if gh release view "$RELEASE_TAG" --repo "${{ github.repository }}" >/dev/null 2>&1; then + echo "Found release for tag $RELEASE_TAG" + exit 0 + fi + echo "Release for $RELEASE_TAG is not available yet (attempt $attempt/90)." + sleep 20 + done + + echo "Timed out waiting for GitHub release tag $RELEASE_TAG." + exit 1 + + - name: Upload APK to GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload "$RELEASE_TAG" "${{ steps.artifact.outputs.asset_path }}" --clobber --repo "${{ github.repository }}" diff --git a/CLAUDE.md b/CLAUDE.md index 9f59acbc2..3692961f1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -139,6 +139,7 @@ npm run android:production ### Cloud build + submit (EAS Workflows) Tag pushes like `v0.1.0` trigger `packages/app/.eas/workflows/release-mobile.yml` on Expo servers. +Tag pushes like `v0.1.0` also trigger `.github/workflows/android-apk-release.yml` on GitHub Actions to publish an APK asset on the matching GitHub Release. That workflow does: - Build iOS with the `production` profile @@ -182,7 +183,7 @@ npm run release:patch npm run version:all:patch # npm version across all workspaces (creates commit + local tag) npm run release:check npm run release:publish -npm run release:push # pushes HEAD and current version tag (triggers desktop + EAS mobile workflows) +npm run release:push # pushes HEAD and current version tag (triggers desktop + Android APK + EAS mobile workflows) ``` Notes: @@ -196,6 +197,7 @@ Notes: Release completion checklist: - `npm run release:patch` completes successfully. - GitHub `Desktop Release` workflow for the new `v*` tag is green. +- GitHub `Android APK Release` workflow for the same tag is green. - EAS `release-mobile.yml` workflow for the same tag is green (Expo queues can take longer on the free plan). ## Orchestrator Mode