Skip to content

Merge pull request #12 from codebuilderinc/feature/local-build-workfl… #2

Merge pull request #12 from codebuilderinc/feature/local-build-workfl…

Merge pull request #12 from codebuilderinc/feature/local-build-workfl… #2

name: πŸ—οΈ Local Android Build (Self-Hosted)
permissions:
contents: write
on:
workflow_dispatch:
push:
branches: ['main'] #["**"]
paths:
- '.github/workflows/local-android-build.yml' # Allow manual re-runs of this work6flow
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build-android-local:
name: πŸ”¨ Build Android APK (Local Gradle)
runs-on: self-hosted # Use your self-hosted runner / local machine
outputs:
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 }}
branch_name: ${{ steps.extract-branch.outputs.branch_name }}
steps:
# ========================
# πŸ› οΈ Repository Setup
# ========================
- name: 'πŸ“¦ Checkout (Full History)'
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 'πŸ” Extract branch name'
id: extract-branch
shell: bash
run: |
BRANCH_NAME=${GITHUB_REF#refs/heads/}
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
echo "Branch: $BRANCH_NAME"
# ========================
# βš™οΈ Environment Configuration
# ========================
- name: 'πŸ“¦ Setup Node.js 22.x'
uses: actions/setup-node@v4
with:
node-version: 22.x
cache: 'npm'
- name: '🧩 Install dependencies'
run: npm ci --legacy-peer-deps
# ========================
# πŸ”„ 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 "actions@github.com"
- name: 'πŸ’Ύ Commit Version Update'
if: github.ref == 'refs/heads/main'
run: |
git add version.json
git commit -m "chore: Auto-increment version [skip ci]" || true
git push || true
# ========================
# πŸ“Œ Version Setup
# ========================
- name: '🏷️ Set Build Versions'
id: version-control
run: |
# Use version from version.json
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
APP_VERSION=$(jq -r '.version' version.json)
IS_PRODUCTION="true"
else
# For non-main branches, create a prerelease version with branch name
BRANCH_NAME=${{ steps.extract-branch.outputs.branch_name }}
SANITIZED_BRANCH=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9]/-/g')
# Get base version from version.json
BASE_VERSION=$(jq -r '.version' version.json)
APP_VERSION="${BASE_VERSION}-pre.${SANITIZED_BRANCH}.${{ 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
# ========================
# πŸ› οΈ Android SDK Check
# ========================
- name: 'πŸ” Verify & Configure Android SDK'
run: |
# Force a fixed SDK location for the runner
ANDROID_HOME="/home/digitalnomad91/Android/sdk"
# Export for subsequent steps
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
echo "βœ… ANDROID_HOME: $ANDROID_HOME"
# Verify SDK exists
if [ ! -d "$ANDROID_HOME" ]; then
echo "❌ ANDROID_HOME path does not exist: $ANDROID_HOME"
exit 1
fi
echo "βœ… Checking for gradle wrapper..."
ls -la android/gradlew || echo "⚠️ No gradle wrapper found, will use globally installed gradle"
# ========================
# πŸ—οΈ Build Execution
# ========================
- name: 'πŸš€ Prepare Expo Bundle'
run: |
echo "πŸ“¦ Creating Expo bundle for embedded use..."
npm run prepare
- name: 'πŸ”§ Make Gradle Wrapper Executable'
run: |
chmod +x android/gradlew
- name: 'πŸ—οΈ Build Release APK with Gradle'
run: |
export ANDROID_HOME="/home/digitalnomad91/Android/sdk"
cd android
./gradlew clean assembleRelease \
-x bundleRelease \
--no-daemon \
-Dorg.gradle.jvmargs=-Xmx4096m
cd ..
echo "βœ… Build completed successfully!"
# ========================
# πŸ“¦ APK Verification & Naming
# ========================
- name: 'πŸ“ Locate APK Output'
id: apk-path
run: |
APK_FILE=$(find android/app/build/outputs/apk -name "*.apk" -type f | head -1)
if [ -z "$APK_FILE" ]; then
echo "❌ Error: No APK file generated!"
find android/app/build -name "*.apk" -o -name "*.aab" 2>/dev/null
exit 1
fi
echo "βœ… Found APK: $APK_FILE"
echo "APK_PATH=$APK_FILE" >> $GITHUB_OUTPUT
ls -lh "$APK_FILE"
- name: '✏️ Rename APK with Version'
id: final-apk
run: |
SOURCE_APK="${{ steps.apk-path.outputs.APK_PATH }}"
DEST_APK="app-release-${{ env.APP_VERSION }}-build-${{ env.BUILD_NUMBER }}.apk"
cp "$SOURCE_APK" "$DEST_APK"
echo "FINAL_APK=$DEST_APK" >> $GITHUB_OUTPUT
echo "βœ… Final APK: $DEST_APK"
ls -lh "$DEST_APK"
# ========================
# πŸ“€ Artifact Upload
# ========================
- name: 'πŸ“€ Upload APK Artifact'
uses: actions/upload-artifact@v4
with:
name: android-apk-local
path: app-release-${{ env.APP_VERSION }}-build-${{ env.BUILD_NUMBER }}.apk
retention-days: 14
create-release:
name: 'πŸš€ Create GitHub Release'
runs-on: ubuntu-latest
needs: build-android-local
steps:
# ========================
# πŸ“₯ Artifact Retrieval
# ========================
- name: 'πŸ“¦ Checkout Repository'
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 'πŸ“₯ Download APK Artifact'
uses: actions/download-artifact@v4
with:
name: android-apk-local
# ========================
# πŸ“œ Changelog Generation
# ========================
- name: 'πŸ“‹ Create Release Notes'
id: changelog
run: |
echo "πŸ“ Generating changelog from git history..."
CHANGELOG=$(git log --oneline --no-decorate -n 20 | sed 's/^/- /')
echo "$CHANGELOG" > changelog.txt
# Format for GitHub release body
{
echo "## Release: ${{ needs.build-android-local.outputs.app_version }}"
echo ""
echo "**Build Info:**"
echo "- Build Number: ${{ needs.build-android-local.outputs.build_number }}"
echo "- Build Date: ${{ needs.build-android-local.outputs.build_date }}"
echo "- Branch: ${{ needs.build-android-local.outputs.branch_name }}"
echo ""
echo "**Recent Changes:**"
cat changelog.txt
} > release-body.txt
# ========================
# 🏷️ Release Creation
# ========================
- name: '🎚️ Determine Release Type'
id: release-type
run: |
echo "πŸ” Detecting release type..."
if [ "${{ needs.build-android-local.outputs.is_production }}" = "true" ]; then
echo "🟒 Production release detected"
RELEASE_TAG="v${{ needs.build-android-local.outputs.app_version }}"
RELEASE_TITLE="πŸ“± Production Release v${{ needs.build-android-local.outputs.app_version }} (Local Build)"
else
echo "🟑 Pre-release build detected"
BRANCH_NAME="${{ needs.build-android-local.outputs.branch_name }}"
RELEASE_TAG="prerelease-local-${BRANCH_NAME}-${{ needs.build-android-local.outputs.build_date }}"
RELEASE_TITLE="πŸ“± Pre-release (${BRANCH_NAME}) v${{ needs.build-android-local.outputs.app_version }} (Local Build)"
fi
echo "RELEASE_TAG=${RELEASE_TAG}" >> $GITHUB_OUTPUT
echo "RELEASE_TITLE=${RELEASE_TITLE}" >> $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: release-body.txt
files: app-release-${{ needs.build-android-local.outputs.app_version }}-build-${{ needs.build-android-local.outputs.build_number }}.apk
prerelease: ${{ needs.build-android-local.outputs.is_production != 'true' }}
notify-completion:
name: 'βœ… Build Completion Notification'
runs-on: ubuntu-latest
needs: [build-android-local, create-release]
if: always()
steps:
- name: 'πŸ“’ Build Status'
run: |
if [ "${{ needs.build-android-local.result }}" = "success" ] && [ "${{ needs.create-release.result }}" = "success" ]; then
echo "βœ… BUILD SUCCESSFUL!"
echo "πŸ“± APK Version: ${{ needs.build-android-local.outputs.app_version }}"
echo "πŸ“¦ Build completed without Expo.dev charges"
else
echo "❌ BUILD FAILED"
exit 1
fi