Files
Tracearr/.github/workflows/mobile-release.yml
Rephl3x 3015f48118
Some checks failed
CI / Lint & Typecheck (push) Has been cancelled
CI / Test (routes) (push) Has been cancelled
CI / Test (security) (push) Has been cancelled
CI / Test (services) (push) Has been cancelled
CI / Test (unit) (push) Has been cancelled
CI / Test (integration) (push) Has been cancelled
CI / Test Coverage (push) Has been cancelled
CI / Build (push) Has been cancelled
Initial Upload
2025-12-17 12:32:50 +13:00

315 lines
11 KiB
YAML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Mobile Release
on:
workflow_dispatch:
inputs:
tag:
description: 'Tag to deploy (e.g., v1.2.3-beta.1)'
required: true
type: string
concurrency:
group: mobile-release-${{ github.ref }}
cancel-in-progress: false
jobs:
# Check if this is a prerelease (alpha, beta, rc)
check-release-type:
name: Check Release Type
runs-on: ubuntu-latest
outputs:
prerelease: ${{ steps.check.outputs.prerelease }}
previous_tag: ${{ steps.prev_tag.outputs.tag }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.tag }}
- name: Check if prerelease
id: check
run: |
TAG="${{ inputs.tag }}"
if [[ "$TAG" == *-* ]]; then
echo "prerelease=true" >> "$GITHUB_OUTPUT"
echo "This is a prerelease: $TAG"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
echo "This is a stable release: $TAG"
fi
- name: Get previous tag
id: prev_tag
run: |
TAG="${{ inputs.tag }}"
PREV_TAG=$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || echo "")
echo "tag=$PREV_TAG" >> "$GITHUB_OUTPUT"
echo "Previous tag: $PREV_TAG"
# Check if mobile code changed since last tag
check-mobile-changes:
name: Check Mobile Changes
runs-on: ubuntu-latest
needs: [check-release-type]
if: needs.check-release-type.outputs.prerelease == 'true'
outputs:
mobile_changed: ${{ steps.check.outputs.changed }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.tag }}
- name: Check for mobile changes
id: check
run: |
PREV_TAG="${{ needs.check-release-type.outputs.previous_tag }}"
CURRENT_TAG="${{ inputs.tag }}"
if [ -z "$PREV_TAG" ]; then
echo "No previous tag found, assuming mobile changed"
echo "changed=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# Check if any files in apps/mobile or shared packages changed
CHANGES=$(git diff --name-only "$PREV_TAG" "$CURRENT_TAG" -- apps/mobile/ packages/shared/ | wc -l)
if [ "$CHANGES" -gt 0 ]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Mobile changes detected: $CHANGES files"
git diff --name-only "$PREV_TAG" "$CURRENT_TAG" -- apps/mobile/ packages/shared/
else
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No mobile changes since $PREV_TAG"
fi
# Deploy mobile app using fingerprint-based detection
# This action automatically:
# 1. Calculates the native fingerprint
# 2. Checks if a compatible build already exists
# 3. If no build exists → triggers eas build
# 4. If build exists → reuses it
# 5. Pushes OTA update to the channel
deploy:
name: Deploy Mobile
runs-on: ubuntu-latest
needs: [check-release-type, check-mobile-changes]
if: |
needs.check-release-type.outputs.prerelease == 'true' &&
needs.check-mobile-changes.outputs.mobile_changed == 'true'
timeout-minutes: 60
defaults:
run:
working-directory: apps/mobile
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: .
- name: Build shared package
run: pnpm --filter @tracearr/shared build
- name: Setup Expo
uses: expo/expo-github-action@main
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Validate secrets
run: |
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
echo "::error::EXPO_TOKEN secret is not set"
exit 1
fi
- name: Sync version from git tag
run: |
# Extract version from tag (v1.2.3-alpha.4 -> 1.2.3)
VERSION="${{ inputs.tag }}"
VERSION="${VERSION#v}" # Remove 'v' prefix
VERSION="${VERSION%%-*}" # Remove prerelease suffix (-alpha.4, -beta.1, etc.)
echo "Setting app version to: $VERSION"
# Update app.json with the version
jq --arg v "$VERSION" '.expo.version = $v' app.json > tmp.json && mv tmp.json app.json
# Verify the change
ACTUAL=$(jq -r '.expo.version' app.json)
if [ "$ACTUAL" != "$VERSION" ]; then
echo "::error::Version sync failed. Expected $VERSION, got $ACTUAL"
exit 1
fi
echo "Version synced: $ACTUAL"
- name: Decode Google Service Account
run: |
mkdir -p credentials
echo "${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}" | base64 -d > credentials/google-service-account.json
- name: Deploy with fingerprint
uses: expo/expo-github-action/continuous-deploy-fingerprint@main
id: deploy
with:
profile: preview
branch: preview
working-directory: apps/mobile
auto-submit-builds: true
env:
EXPO_APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.EXPO_APPLE_APP_SPECIFIC_PASSWORD }}
GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
- name: Output deployment info
run: |
echo "## Deployment Results" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Fingerprint**: \`${{ steps.deploy.outputs.fingerprint }}\`" >> "$GITHUB_STEP_SUMMARY"
echo "**Build needed**: ${{ steps.deploy.outputs.build-new-build }}" >> "$GITHUB_STEP_SUMMARY"
if [ -n "${{ steps.deploy.outputs.ios-build-id }}" ]; then
echo "**iOS Build ID**: ${{ steps.deploy.outputs.ios-build-id }}" >> "$GITHUB_STEP_SUMMARY"
fi
if [ -n "${{ steps.deploy.outputs.android-build-id }}" ]; then
echo "**Android Build ID**: ${{ steps.deploy.outputs.android-build-id }}" >> "$GITHUB_STEP_SUMMARY"
fi
if [ -n "${{ steps.deploy.outputs.update-id }}" ]; then
echo "**Update ID**: ${{ steps.deploy.outputs.update-id }}" >> "$GITHUB_STEP_SUMMARY"
fi
# Fallback: Manual OTA if fingerprint action has issues
# This job only runs if deploy fails and we want to try OTA anyway
ota-fallback:
name: OTA Fallback
runs-on: ubuntu-latest
needs: [check-release-type, check-mobile-changes, deploy]
if: |
always() &&
needs.deploy.result == 'failure' &&
needs.check-release-type.outputs.prerelease == 'true' &&
needs.check-mobile-changes.outputs.mobile_changed == 'true'
timeout-minutes: 15
defaults:
run:
working-directory: apps/mobile
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: .
- name: Build shared package
run: pnpm --filter @tracearr/shared build
- name: Setup Expo
uses: expo/expo-github-action@main
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Push OTA update with retry
run: |
TAG="${{ inputs.tag }}"
echo "::warning::Deploy failed, attempting OTA fallback for $TAG"
for attempt in 1 2 3; do
echo "Attempt $attempt of 3..."
if eas update \
--channel preview \
--message "Release $TAG (fallback)" \
--non-interactive; then
echo "OTA update successful on attempt $attempt"
exit 0
fi
if [ $attempt -lt 3 ]; then
echo "Attempt $attempt failed, waiting before retry..."
sleep $((30 * attempt))
fi
done
echo "::error::OTA update failed after 3 attempts"
exit 1
# Summary job that reports status
summary:
name: Release Summary
runs-on: ubuntu-latest
needs: [check-release-type, check-mobile-changes, deploy, ota-fallback]
if: always()
steps:
- name: Report status
env:
TAG: ${{ inputs.tag }}
PRERELEASE: ${{ needs.check-release-type.outputs.prerelease }}
MOBILE_CHANGED: ${{ needs.check-mobile-changes.outputs.mobile_changed || 'skipped' }}
DEPLOY_RESULT: ${{ needs.deploy.result }}
FALLBACK_RESULT: ${{ needs.ota-fallback.result }}
run: |
{
echo "## Mobile Release Summary"
echo ""
echo "**Tag**: $TAG"
echo "**Prerelease**: $PRERELEASE"
echo "**Mobile Changed**: $MOBILE_CHANGED"
echo ""
if [[ "$PRERELEASE" != "true" ]]; then
echo " Skipped: Not a prerelease (stable releases don't trigger mobile builds)"
elif [[ "$MOBILE_CHANGED" != "true" ]]; then
echo " Skipped: No mobile code changes detected"
else
echo "### Deployment Status"
echo ""
if [[ "$DEPLOY_RESULT" == "success" ]]; then
echo "✅ **Deploy**: Success"
echo ""
echo "The fingerprint-based deployment completed successfully."
echo "- If native changes were detected, a new build was triggered"
echo "- If only JS changes, an OTA update was pushed"
echo ""
echo "Check the [Expo dashboard](https://expo.dev) for details."
elif [[ "$FALLBACK_RESULT" == "success" ]]; then
echo "⚠️ **Deploy**: Failed (fingerprint action issue)"
echo "✅ **OTA Fallback**: Success"
echo ""
echo "The main deploy failed but OTA fallback succeeded."
echo "Users will receive the JS update on next app launch."
else
echo "❌ **Deploy**: $DEPLOY_RESULT"
echo "❌ **OTA Fallback**: $FALLBACK_RESULT"
echo ""
echo "Both deployment methods failed. Check workflow logs for details."
fi
fi
} >> "$GITHUB_STEP_SUMMARY"