Build and Push App #26
Workflow file for this run
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" | |
| if [ "${{ matrix.platform }}" = "android" ]; then | |
| APK_FILE="build-artifacts/termix_android.apk" | |
| if [ -f "$APK_FILE" ]; then | |
| echo "Uploading $APK_FILE..." | |
| gh release upload "$RELEASE_TAG" \ | |
| "$APK_FILE" \ | |
| --repo Termix-SSH/Termix \ | |
| --clobber | |
| echo "✓ Android APK uploaded successfully" | |
| 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..." | |
| gh release upload "$RELEASE_TAG" \ | |
| "$IPA_FILE" \ | |
| --repo Termix-SSH/Termix \ | |
| --clobber | |
| echo "✓ iOS IPA uploaded successfully" | |
| else | |
| echo "ERROR: iOS IPA not found: $IPA_FILE" | |
| exit 1 | |
| fi | |
| fi | |
| echo "" | |
| echo "Build uploaded to release: $RELEASE_URL" |