Build and Push App #15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Push App | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| platform: | |
| type: choice | |
| description: Platform to build for | |
| default: "both" | |
| required: true | |
| options: | |
| - both | |
| - ios | |
| - android | |
| action: | |
| type: choice | |
| description: What to do with the built app | |
| default: "file" | |
| required: true | |
| options: | |
| - none | |
| - file | |
| - release | |
| - submit | |
| jobs: | |
| build: | |
| name: build-${{ matrix.platform }} | |
| runs-on: ${{ matrix.platform == 'ios' && 'macos-26' || 'blacksmith-4vcpu-ubuntu-2404' }} | |
| strategy: | |
| matrix: | |
| platform: ${{ github.event.inputs.platform == 'both' && fromJSON('["ios", "android"]') || fromJSON(format('["{0}"]', github.event.inputs.platform)) }} | |
| node: [20.x] | |
| steps: | |
| - name: Setup repo | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/[email protected] | |
| with: | |
| node-version: ${{ matrix.node }} | |
| cache: 'npm' | |
| - name: Setup Expo and EAS | |
| uses: expo/expo-github-action@v7 | |
| with: | |
| token: ${{ secrets.EXPO_TOKEN }} | |
| expo-version: latest | |
| eas-version: latest | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Validate EAS configuration | |
| run: | | |
| echo "EAS configuration:" | |
| cat eas.json | |
| echo "Validating configuration..." | |
| eas build:configure --platform ${{ matrix.platform }} | |
| - name: Build app | |
| run: | | |
| if [ "${{ github.event.inputs.action }}" = "submit" ]; then | |
| PROFILE="production" | |
| else | |
| PROFILE="preview" | |
| fi | |
| echo "Building for platform: ${{ matrix.platform }}" | |
| echo "Using profile: $PROFILE" | |
| mkdir -p build-artifacts | |
| VERSION=$(node -p "require('./app.json').expo.version") | |
| echo "App version: $VERSION" | |
| eas build --local \ | |
| --non-interactive \ | |
| --clear-cache \ | |
| --platform=${{ matrix.platform }} \ | |
| --profile=$PROFILE | |
| if [ "${{ matrix.platform }}" = "android" ]; then | |
| echo "Searching for Android build artifacts..." | |
| APK_FILE=$(find . -maxdepth 1 -type f -name "build-*.apk" 2>/dev/null | head -1) | |
| if [ -n "$APK_FILE" ]; then | |
| cp "$APK_FILE" "build-artifacts/termix_android.apk" | |
| echo "Copied to build-artifacts/termix_android_universal_${VERSION}.apk" | |
| else | |
| echo "Trying /tmp search..." | |
| APK_FILE=$(find /tmp -type f -name "app-release.apk" 2>/dev/null | grep "eas-build-local-nodejs" | head -1) | |
| if [ -n "$APK_FILE" ]; then | |
| echo "Found APK in /tmp: $APK_FILE" | |
| cp "$APK_FILE" "build-artifacts/termix_android_universal_${VERSION}.apk" | |
| else | |
| echo "ERROR: APK not found after build" | |
| ls -la . | grep -E '\.apk|build-' | |
| fi | |
| fi | |
| if [ "$PROFILE" = "production" ]; then | |
| AAB_FILE=$(find . -maxdepth 1 -type f -name "build-*.aab" 2>/dev/null | head -1) | |
| if [ -n "$AAB_FILE" ]; then | |
| cp "$AAB_FILE" "build-artifacts/termix_android.aab" | |
| else | |
| AAB_FILE=$(find /tmp -type f -name "app-release.aab" 2>/dev/null | grep "eas-build-local-nodejs" | head -1) | |
| if [ -n "$AAB_FILE" ]; then | |
| echo "Found AAB in /tmp: $AAB_FILE" | |
| cp "$AAB_FILE" "build-artifacts/termix_android_${VERSION}.aab" | |
| fi | |
| fi | |
| fi | |
| elif [ "${{ matrix.platform }}" = "ios" ]; then | |
| echo "Searching for iOS build artifacts..." | |
| IPA_FILE=$(find . -maxdepth 1 -type f -name "build-*.ipa" 2>/dev/null | head -1) | |
| if [ -n "$IPA_FILE" ]; then | |
| echo "Found IPA in project root: $IPA_FILE" | |
| cp "$IPA_FILE" "build-artifacts/termix_ios.ipa" | |
| echo "Copied to build-artifacts/termix_ios_universal_${VERSION}.ipa" | |
| else | |
| IPA_FILE=$(find . -type f -name "*.ipa" -not -path "*/node_modules/*" 2>/dev/null | head -1) | |
| if [ -n "$IPA_FILE" ]; then | |
| echo "Found IPA: $IPA_FILE" | |
| cp "$IPA_FILE" "build-artifacts/termix_ios.ipa" | |
| else | |
| echo "ERROR: IPA not found after build" | |
| ls -la . | grep -E '\.ipa|build-' | |
| fi | |
| fi | |
| fi | |
| env: | |
| EAS_SKIP_AUTO_FINGERPRINT: 1 | |
| - name: Verify build artifacts | |
| id: detect-artifacts | |
| run: | | |
| echo "=== Build Artifacts ===" | |
| if [ -d "build-artifacts" ]; then | |
| echo "Contents of build-artifacts/:" | |
| ls -lh build-artifacts/ 2>/dev/null || echo "Directory exists but is empty" | |
| ARTIFACT_COUNT=$(ls -1 build-artifacts/ 2>/dev/null | wc -l) | |
| echo "" | |
| echo "Total artifacts: $ARTIFACT_COUNT" | |
| else | |
| echo "Warning: build-artifacts directory not found" | |
| mkdir -p build-artifacts | |
| ARTIFACT_COUNT=0 | |
| fi | |
| echo "artifact_count=$ARTIFACT_COUNT" >> $GITHUB_OUTPUT | |
| - name: Submit to App Store | |
| if: ${{ github.event.inputs.action == 'submit' }} | |
| run: | | |
| VERSION=$(node -p "require('./app.json').expo.version") | |
| if [ "${{ matrix.platform }}" = "android" ]; then | |
| BUILD_FILE="build-artifacts/termix_android.aab" | |
| if [ -f "$BUILD_FILE" ]; then | |
| echo "Using AAB for Play Store submission: $BUILD_FILE" | |
| else | |
| echo "ERROR: AAB not found for production submission" | |
| echo "Play Store requires AAB format for submissions" | |
| exit 1 | |
| fi | |
| else | |
| BUILD_FILE="build-artifacts/termix_ios.ipa" | |
| fi | |
| if [ -n "$BUILD_FILE" ] && [ -f "$BUILD_FILE" ]; then | |
| echo "Submitting file: $BUILD_FILE" | |
| eas submit -p ${{ matrix.platform }} --profile production --path "$BUILD_FILE" | |
| else | |
| echo "No build file found to submit" | |
| exit 1 | |
| fi | |
| - name: Upload Android APK | |
| if: ${{ github.event.inputs.action == 'file' && matrix.platform == 'android' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: termix_android | |
| path: build-artifacts/termix_android.apk | |
| retention-days: 30 | |
| if-no-files-found: error | |
| - name: Upload iOS IPA | |
| if: ${{ github.event.inputs.action == 'file' && matrix.platform == 'ios' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: termix_ios_universal | |
| path: build-artifacts/termix_ios.ipa | |
| retention-days: 30 | |
| if-no-files-found: error | |
| - name: Upload to GitHub Release | |
| if: ${{ github.event.inputs.action == 'release' }} | |
| env: | |
| GH_TOKEN: ${{ secrets.TERMIX_RELEASE_TOKEN }} | |
| run: | | |
| VERSION=$(node -p "require('./app.json').expo.version") | |
| echo "Fetching latest release from Termix-SSH/Termix..." | |
| LATEST_RELEASE=$(gh release list --repo Termix-SSH/Termix --limit 1 --json tagName,name,isLatest -q '.[0]') | |
| if [ -z "$LATEST_RELEASE" ]; then | |
| echo "ERROR: No releases found in Termix-SSH/Termix" | |
| exit 1 | |
| fi | |
| RELEASE_TAG=$(echo "$LATEST_RELEASE" | jq -r '.tagName') | |
| RELEASE_NAME=$(echo "$LATEST_RELEASE" | jq -r '.name') | |
| RELEASE_URL="https://github.com/Termix-SSH/Termix/releases/tag/$RELEASE_TAG" | |
| echo "Latest release: $RELEASE_NAME ($RELEASE_TAG)" | |
| echo "Release URL: $RELEASE_URL" | |
| echo "Fetching latest release from Termix-SSH/Mobile..." | |
| MOBILE_RELEASE=$(gh release list --repo Termix-SSH/Mobile --limit 1 --json tagName,name,isLatest -q '.[0]') | |
| if [ -z "$MOBILE_RELEASE" ]; then | |
| echo "ERROR: No releases found in Termix-SSH/Mobile" | |
| exit 1 | |
| fi | |
| MOBILE_TAG=$(echo "$MOBILE_RELEASE" | jq -r '.tagName') | |
| MOBILE_NAME=$(echo "$MOBILE_RELEASE" | jq -r '.name') | |
| MOBILE_URL="https://github.com/Termix-SSH/Mobile/releases/tag/$MOBILE_TAG" | |
| echo "Latest Mobile release: $MOBILE_NAME ($MOBILE_TAG)" | |
| echo "Mobile Release URL: $MOBILE_URL" | |
| if [ "${{ matrix.platform }}" = "android" ]; then | |
| APK_FILE="build-artifacts/termix_android.apk" | |
| if [ -f "$APK_FILE" ]; then | |
| echo "Uploading $APK_FILE to Termix-SSH/Termix..." | |
| gh release upload "$RELEASE_TAG" \ | |
| "$APK_FILE" \ | |
| --repo Termix-SSH/Termix \ | |
| --clobber | |
| echo "✓ Android APK uploaded to Termix-SSH/Termix" | |
| echo "Uploading $APK_FILE to Termix-SSH/Mobile..." | |
| gh release upload "$MOBILE_TAG" \ | |
| "$APK_FILE" \ | |
| --repo Termix-SSH/Mobile \ | |
| --clobber | |
| echo "✓ Android APK uploaded to Termix-SSH/Mobile" | |
| else | |
| echo "ERROR: Android APK not found: $APK_FILE" | |
| exit 1 | |
| fi | |
| elif [ "${{ matrix.platform }}" = "ios" ]; then | |
| IPA_FILE="build-artifacts/termix_ios.ipa" | |
| if [ -f "$IPA_FILE" ]; then | |
| echo "Uploading $IPA_FILE to Termix-SSH/Termix..." | |
| gh release upload "$RELEASE_TAG" \ | |
| "$IPA_FILE" \ | |
| --repo Termix-SSH/Termix \ | |
| --clobber | |
| echo "✓ iOS IPA uploaded to Termix-SSH/Termix" | |
| echo "Uploading $IPA_FILE to Termix-SSH/Mobile..." | |
| gh release upload "$MOBILE_TAG" \ | |
| "$IPA_FILE" \ | |
| --repo Termix-SSH/Mobile \ | |
| --clobber | |
| echo "✓ iOS IPA uploaded to Termix-SSH/Mobile" | |
| else | |
| echo "ERROR: iOS IPA not found: $IPA_FILE" | |
| exit 1 | |
| fi | |
| fi | |
| echo "" | |
| echo "Build uploaded to releases:" | |
| echo " - Termix: $RELEASE_URL" | |
| echo " - Mobile: $MOBILE_URL" |