Skip to content

Merge branch 'main' of https://github.com/codebuilderinc/codebuilder-app #88

Merge branch 'main' of https://github.com/codebuilderinc/codebuilder-app

Merge branch 'main' of https://github.com/codebuilderinc/codebuilder-app #88

name: 🚠EAS Android Build & Smart Release

Check failure on line 1 in .github/workflows/eas-android-build.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/eas-android-build.yml

Invalid workflow file

You have an error in your yaml syntax
on:
push:
branches:
- main
workflow_dispatch:
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build-android:
name: 🔠Build Android - Version Manager
runs-on: ubuntu-latest
outputs:
build_id: ${{ steps.build.outputs.BUILD_ID }}
app_version: ${{ steps.version-control.outputs.app_version }}
build_number: ${{ steps.version-control.outputs.build_number }}
build_date: ${{ steps.version-control.outputs.build_date }}
is_production: ${{ steps.version-control.outputs.is_production }}
steps:
# Repository Setup
- name: "📠Checkout (Full History)"
uses: actions/checkout@v4
with:
fetch-depth: 0
# Environment Configuration
- name: "📠Setup Node.js 20.x"
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: "🔠Install pnpm"
run: |
npm install -g pnpm
pnpm --version
- name: "🧠Install dependencies (ci)"
run: pnpm install --frozen-lockfile
# Version Management
- name: "🔠Update Production Version"
if: github.ref == 'refs/heads/main'
run: node scripts/bumpVersion.js
- name: "🔠Configure Git for Automation"
if: github.ref == 'refs/heads/main'
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "[email protected]"
- name: "💠Commit Version Update"
if: github.ref == 'refs/heads/main'
run: |
git add version.json
git commit -m "chore: Auto-increment version [skip ci]"
git push
# Version Tagging
- name: "ðŸï¸ Set CI/CD Versions"
id: version-control
run: |
# Use version from version.json (requires jq)
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
APP_VERSION=$(jq -r '.version' version.json)
IS_PRODUCTION="true"
else
APP_VERSION="1.0.0-prerelease.${{ github.run_number }}"
IS_PRODUCTION="false"
fi
# Generate build identifiers
BUILD_NUMBER="${{ github.run_id }}"
BUILD_DATE=$(date +'%Y%m%d-%H%M%S')
# Set outputs for downstream jobs
echo "app_version=$APP_VERSION" >> $GITHUB_OUTPUT
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
echo "build_date=$BUILD_DATE" >> $GITHUB_OUTPUT
echo "is_production=$IS_PRODUCTION" >> $GITHUB_OUTPUT
# Export environment variables
echo "APP_VERSION=$APP_VERSION" >> $GITHUB_ENV
echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_ENV
echo "BUILD_DATE=$BUILD_DATE" >> $GITHUB_ENV
# EAS Setup & Auth
- name: "🔠Setup pnpm global bin"
env:
SHELL: /bin/bash
run: |
mkdir -p $HOME/.pnpm-global
echo "PNPM_HOME=$HOME/.pnpm-global" >> $GITHUB_ENV
echo "$HOME/.pnpm-global" >> $GITHUB_PATH
pnpm setup
- name: "⚙️ Install EAS CLI"
run: pnpm add -g eas-cli@latest
- name: "🔠Verify Expo Credentials"
run: eas whoami --token $EXPO_TOKEN
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
# Force reinstallation of dependencies
- name: "Set pnpm global store directory"
run: pnpm config set store-dir "$HOME/.local/share/pnpm/store" --global
- name: "Reinstall dependencies with new store"
run: pnpm install --force
- name: "Install @expo/config-plugins"
run: pnpm add @expo/config-plugins
# Install @babel/runtime to resolve bundling error
- name: "Install @babel/runtime"
run: pnpm add @babel/runtime
# Debug Dependency Tree
- name: "🔠Debug Dependency Tree"
run: |
echo "Listing installed dependencies..."
pnpm list --depth=0
echo "Checking for expo-constants..."
ls node_modules/expo-constants || echo "expo-constants not found!"
# Build Execution
- name: "🚠Trigger EAS Build"
id: build
run: |
echo "🔠Initializing build process..."
sudo apt-get install -y jq
BUILD_JSON=$(eas build -p android --profile production --non-interactive --json)
echo "Raw build output: $BUILD_JSON"
BUILD_ID=$(echo "$BUILD_JSON" | jq -r '.[0].id')
if [[ -z "$BUILD_ID" || "$BUILD_ID" == "null" ]]; then
echo "Error: Failed to retrieve BUILD_ID!"
exit 1
fi
echo "EAS Build started with ID: $BUILD_ID"
echo "BUILD_ID=$BUILD_ID" >> $GITHUB_ENV
echo "BUILD_ID=$BUILD_ID" >> $GITHUB_OUTPUT
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
download-apk:
name: "📠APK Artifact Handler"
runs-on: ubuntu-latest
needs: build-android
outputs:
apk_path: ${{ steps.download.outputs.APK_PATH }}
steps:
# Environment Setup
- name: "📠Checkout Repository"
uses: actions/checkout@v4
- name: "⚙️ Setup Node.js"
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: "🔠Install pnpm"
run: |
npm install -g pnpm
pnpm --version
- name: "📠Install Dependencies"
run: pnpm install --frozen-lockfile
# Dependency Management
- name: "🧠Install Build Tools"
run: |
pnpm add -g eas-cli@latest
sudo apt-get update
sudo apt-get install -y jq curl dotenv
# Build Monitoring
- name: "⏳ Wait for Build Completion"
run: |
echo "⏰ Monitoring build status..."
cd $GITHUB_WORKSPACE
BUILD_ID=${{ needs.build-android.outputs.build_id }}
echo "🔠Starting build monitoring for BUILD_ID: $BUILD_ID"
# Initial check without JSON for better error visibility
eas build:view $BUILD_ID || true
RETRY_COUNT=0
MAX_RETRIES=120
SLEEP_TIME=30
while [[ $RETRY_COUNT -lt $MAX_RETRIES ]]; do
echo -e "\n=== Attempt $((RETRY_COUNT+1))/$MAX_RETRIES ==="
# Fetch build status in JSON format
BUILD_STATUS_JSON=$(eas build:view --json $BUILD_ID)
echo "📠Raw API response: $BUILD_STATUS_JSON"
# Validate JSON and check for empty response
if ! echo "$BUILD_STATUS_JSON" | jq empty >/dev/null 2>&1 || [[ -z "$BUILD_STATUS_JSON" ]]; then
echo "❌ Error: Invalid or empty response from EAS API! Retrying..."
RETRY_COUNT=$((RETRY_COUNT+1))
sleep $SLEEP_TIME
continue
fi
BUILD_STATUS=$(echo "$BUILD_STATUS_JSON" | jq -r '.status')
ERROR_MESSAGE=$(echo "$BUILD_STATUS_JSON" | jq -r '.error.message // empty')
echo "🔠Parsed status: $BUILD_STATUS"
[[ -n "$ERROR_MESSAGE" ]] && echo "❌ Error message: $ERROR_MESSAGE"
case $BUILD_STATUS in
"FINISHED")
APK_URL=$(echo "$BUILD_STATUS_JSON" | jq -r '.artifacts.buildUrl')
if [[ -z "$APK_URL" || "$APK_URL" == "null" ]]; then
echo "❌ Error: Successful build but no APK URL found!"
exit 1
fi
echo "✅ APK_URL=$APK_URL" >> $GITHUB_ENV
exit 0
;;
"ERRORED"|"CANCELLED")
echo "❌ Build failed! Error details:"
echo "$BUILD_STATUS_JSON" | jq .
exit 1
;;
"NEW"|"IN_QUEUE"|"IN_PROGRESS"|"PENDING")
echo "⏳ Build is still in progress..."
;;
*)
echo "❌ Unknown build status: $BUILD_STATUS"
exit 1
;;
esac
RETRY_COUNT=$((RETRY_COUNT+1))
sleep $SLEEP_TIME
done
echo "❌ Error: Build did not complete within the expected time!"
exit 1
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
# Artifact Handling
- name: "📠Download APK"
id: download
run: |
echo "🔠Retrieving APK URL..."
APK_URL=$(eas build:view --json ${{ needs.build-android.outputs.build_id }} | jq -r '.artifacts.buildUrl')
if [[ -z "$APK_URL" || "$APK_URL" == "null" ]]; then
echo "❌ Error: No APK URL found!"
exit 1
fi
echo "📠Downloading APK from $APK_URL..."
curl -L "$APK_URL" -o app-release.apk
echo "APK_PATH=app-release.apk" >> $GITHUB_OUTPUT
- name: "📠Upload Artifact"
uses: actions/upload-artifact@v4
with:
name: android-apk
path: app-release.apk
generate-changelog:
name: "📠Changelog Generator"
runs-on: ubuntu-latest
needs: build-android
outputs:
changelog: ${{ steps.changelog.outputs.CHANGELOG }}
steps:
# Repository Setup
- name: "📠Checkout with Full History"
uses: actions/checkout@v4
with:
fetch-depth: 0
# Changelog Generation
- name: "📠Create Release Notes"
id: changelog
run: |
echo "📠Generating changelog from git history..."
CHANGELOG=$(git log --pretty=format:"- %s (%h) by %an" -n 15)
echo "$CHANGELOG" > changelog.txt
# FIXED OUTPUT HANDLING (ONLY CHANGE)
delimiter=$(openssl rand -hex 6)
echo "CHANGELOG<<$delimiter" >> $GITHUB_OUTPUT
cat changelog.txt >> $GITHUB_OUTPUT
echo "$delimiter" >> $GITHUB_OUTPUT
- name: "📠Upload Changelog"
uses: actions/upload-artifact@v4
with:
name: changelog
path: changelog.txt
create-release:
name: "🚠Smart Release Publisher"
runs-on: ubuntu-latest
needs:
- build-android
- download-apk
- generate-changelog
steps:
# Artifact Retrieval
- name: "📠Get APK Artifact"
uses: actions/download-artifact@v4
with:
name: android-apk
- name: "📠Get Changelog"
uses: actions/download-artifact@v4
with:
name: changelog
# Release Creation
- name: "ðŸŽï¸ Determine Release Type"
id: release-type
run: |
echo "🔠Detecting release type..."
if [ "${{ needs.build-android.outputs.is_production }}" = "true" ]; then
echo "🟠Production release detected"
RELEASE_TAG="v${{ needs.build-android.outputs.app_version }}"
RELEASE_TITLE="Production Release v${{ needs.build-android.outputs.app_version }}"
else
echo "🟠Nightly build detected"
RELEASE_TAG="nightly-${{ needs.build-android.outputs.build_date }}"
RELEASE_TITLE="Nightly Build (${{ needs.build-android.outputs.build_date }})"
fi
echo "RELEASE_TAG=${RELEASE_TAG}" >> $GITHUB_OUTPUT
- name: "🎠Publish GitHub Release"
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.release-type.outputs.RELEASE_TAG }}
name: ${{ steps.release-type.outputs.RELEASE_TITLE }}
body_path: changelog.txt
files: app-release.apk
prerelease: ${{ needs.build-android.outputs.is_production != 'true' }}