diff --git a/.github/workflows/artifact-comment.yml b/.github/workflows/artifact-comment.yml index c4773b62..08710fe8 100644 --- a/.github/workflows/artifact-comment.yml +++ b/.github/workflows/artifact-comment.yml @@ -10,8 +10,7 @@ on: types: [opened, synchronize, reopened] workflow_run: # Triggered when build workflows complete workflows: - - "🤖 Android APK Build (Phone + TV)" - - "🤖 iOS IPA Build (Phone + TV)" + - "🏗️ Build Apps" types: - completed @@ -116,6 +115,7 @@ jobs: // Filter for build workflows only and sort by creation time (most recent first) const buildRuns = workflowRuns.workflow_runs .filter(run => + run.name.includes('Build Apps') || run.name.includes('Android APK Build') || run.name.includes('iOS IPA Build') ) @@ -132,57 +132,61 @@ jobs: let allArtifacts = []; let buildStatuses = {}; - // Get the most recent run for each workflow type + // Get the most recent run for the unified apps workflow + const latestAppsRun = buildRuns.find(run => run.name.includes('Build Apps')); const latestAndroidRun = buildRuns.find(run => run.name.includes('Android APK Build')); const latestIOSRun = buildRuns.find(run => run.name.includes('iOS IPA Build')); - // Store status for each workflow type - if (latestAndroidRun) { + // Store status for unified workflow (preferred) or fallback to separate workflows + const appsWorkflowRun = latestAppsRun || latestAndroidRun; + if (appsWorkflowRun) { buildStatuses['Android'] = { - name: latestAndroidRun.name, - status: latestAndroidRun.status, - conclusion: latestAndroidRun.conclusion, - url: latestAndroidRun.html_url, - runId: latestAndroidRun.id, - created_at: latestAndroidRun.created_at + name: appsWorkflowRun.name, + status: appsWorkflowRun.status, + conclusion: appsWorkflowRun.conclusion, + url: appsWorkflowRun.html_url, + runId: appsWorkflowRun.id, + created_at: appsWorkflowRun.created_at }; // Collect artifacts if completed successfully - if (latestAndroidRun.conclusion === 'success') { + if (appsWorkflowRun.conclusion === 'success') { try { const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, - run_id: latestAndroidRun.id + run_id: appsWorkflowRun.id }); allArtifacts.push(...artifacts.artifacts); } catch (error) { - console.log(`Failed to get Android artifacts for run ${latestAndroidRun.id}:`, error.message); + console.log(`Failed to get apps artifacts for run ${appsWorkflowRun.id}:`, error.message); } } } - if (latestIOSRun) { + // For iOS, use the same workflow run (since it's all in one now) or fallback to separate + const iosWorkflowRun = latestAppsRun || latestIOSRun; + if (iosWorkflowRun) { buildStatuses['iOS'] = { - name: latestIOSRun.name, - status: latestIOSRun.status, - conclusion: latestIOSRun.conclusion, - url: latestIOSRun.html_url, - runId: latestIOSRun.id, - created_at: latestIOSRun.created_at + name: iosWorkflowRun.name, + status: iosWorkflowRun.status, + conclusion: iosWorkflowRun.conclusion, + url: iosWorkflowRun.html_url, + runId: iosWorkflowRun.id, + created_at: iosWorkflowRun.created_at }; - // Collect artifacts if completed successfully - if (latestIOSRun.conclusion === 'success') { + // Only collect artifacts if not already collected from apps workflow + if (!latestAppsRun && iosWorkflowRun.conclusion === 'success') { try { const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, - run_id: latestIOSRun.id + run_id: iosWorkflowRun.id }); allArtifacts.push(...artifacts.artifacts); } catch (error) { - console.log(`Failed to get iOS artifacts for run ${latestIOSRun.id}:`, error.message); + console.log(`Failed to get iOS artifacts for run ${iosWorkflowRun.id}:`, error.message); } } } diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml deleted file mode 100644 index bc9b9ea1..00000000 --- a/.github/workflows/build-android.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: 🤖 Android APK Build (Phone + TV) - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - branches: [develop, master] - push: - branches: [develop, master] - -jobs: - build-android: - if: (!contains(github.event.head_commit.message, '[skip ci]')) - runs-on: ubuntu-24.04 - name: 🏗️ Build Android APK - permissions: - contents: read - - strategy: - fail-fast: false - matrix: - target: [phone, tv] - - steps: - - name: 📥 Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - fetch-depth: 0 - submodules: recursive - show-progress: false - - - name: 🍞 Setup Bun - uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 - with: - bun-version: latest - - - name: 💾 Cache Bun dependencies - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }} - restore-keys: | - ${{ runner.os }}-${{ runner.arch }}-bun-develop - ${{ runner.os }}-bun-develop - - - name: 📦 Install dependencies and reload submodules - run: | - bun install --frozen-lockfile - bun run submodule-reload - - - name: 💾 Cache Gradle global - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: ${{ runner.os }}-gradle-develop - - - name: 🛠️ Generate project files - run: | - if [ "${{ matrix.target }}" = "tv" ]; then - bun run prebuild:tv - else - bun run prebuild - fi - - - name: 💾 Cache project Gradle (.gradle) - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: android/.gradle - key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: ${{ runner.os }}-android-gradle-develop - - - name: 🚀 Build APK - env: - EXPO_TV: ${{ matrix.target == 'tv' && 1 || 0 }} - run: bun run build:android:local - - - name: 📅 Set date tag - run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV - - - name: 📤 Upload APK artifact - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: streamyfin-android-${{ matrix.target }}-apk-${{ env.DATE_TAG }} - path: | - android/app/build/outputs/apk/release/*.apk - retention-days: 7 diff --git a/.github/workflows/build-apps.yml b/.github/workflows/build-apps.yml new file mode 100644 index 00000000..ad770414 --- /dev/null +++ b/.github/workflows/build-apps.yml @@ -0,0 +1,280 @@ +name: 🏗️ Build Apps + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + workflow_dispatch: + pull_request: + branches: [develop, master] + push: + branches: [develop, master] + +jobs: + build-android-phone: + if: (!contains(github.event.head_commit.message, '[skip ci]')) + runs-on: ubuntu-24.04 + name: 🤖 Build Android APK (Phone) + permissions: + contents: read + + steps: + - name: 📥 Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + fetch-depth: 0 + submodules: recursive + show-progress: false + + - name: 🍞 Setup Bun + uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 + with: + bun-version: latest + + - name: 💾 Cache Bun dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }} + restore-keys: | + ${{ runner.os }}-${{ runner.arch }}-bun-develop + ${{ runner.os }}-bun-develop + + - name: 📦 Install dependencies and reload submodules + run: | + bun install --frozen-lockfile + bun run submodule-reload + + - name: 💾 Cache Gradle global + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: 🛠️ Generate project files + run: bun run prebuild + + - name: 💾 Cache project Gradle (.gradle) + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: android/.gradle + key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-android-gradle-develop + + - name: 🚀 Build APK + env: + EXPO_TV: 0 + run: bun run build:android:local + + - name: 📅 Set date tag + run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV + + - name: 📤 Upload APK artifact + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: streamyfin-android-phone-apk-${{ env.DATE_TAG }} + path: | + android/app/build/outputs/apk/release/*.apk + retention-days: 7 + + build-android-tv: + if: (!contains(github.event.head_commit.message, '[skip ci]')) + runs-on: ubuntu-24.04 + name: 🤖 Build Android APK (TV) + permissions: + contents: read + + steps: + - name: 📥 Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + fetch-depth: 0 + submodules: recursive + show-progress: false + + - name: 🍞 Setup Bun + uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 + with: + bun-version: latest + + - name: 💾 Cache Bun dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }} + restore-keys: | + ${{ runner.os }}-${{ runner.arch }}-bun-develop + ${{ runner.os }}-bun-develop + + - name: 📦 Install dependencies and reload submodules + run: | + bun install --frozen-lockfile + bun run submodule-reload + + - name: 💾 Cache Gradle global + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: 🛠️ Generate project files + run: bun run prebuild:tv + + - name: 💾 Cache project Gradle (.gradle) + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: android/.gradle + key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-android-gradle-develop + + - name: 🚀 Build APK + env: + EXPO_TV: 1 + run: bun run build:android:local + + - name: 📅 Set date tag + run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV + + - name: 📤 Upload APK artifact + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: streamyfin-android-tv-apk-${{ env.DATE_TAG }} + path: | + android/app/build/outputs/apk/release/*.apk + retention-days: 7 + + build-ios-phone: + if: (!contains(github.event.head_commit.message, '[skip ci]') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'streamyfin/streamyfin')) + runs-on: macos-15 + name: 🍎 Build iOS IPA (Phone) + permissions: + contents: read + + steps: + - name: 📥 Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + fetch-depth: 0 + submodules: recursive + show-progress: false + + - name: 🍞 Setup Bun + uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 + with: + bun-version: latest + + - name: 💾 Cache Bun dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} + restore-keys: | + ${{ runner.os }}-bun-cache + + - name: 📦 Install dependencies and reload submodules + run: | + bun install --frozen-lockfile + bun run submodule-reload + + - name: 🛠️ Generate project files + run: bun run prebuild + + - name: 🏗️ Setup EAS + uses: expo/expo-github-action@main + with: + eas-version: latest + token: ${{ secrets.EXPO_TOKEN }} + eas-cache: true + + - name: ⚙️ Ensure iOS SDKs installed + run: xcodebuild -downloadPlatform iOS + + - name: 🚀 Build iOS app + env: + EXPO_TV: 0 + run: eas build -p ios --local --non-interactive + + - name: 📅 Set date tag + run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV + + - name: 📤 Upload IPA artifact + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: streamyfin-ios-phone-ipa-${{ env.DATE_TAG }} + path: build-*.ipa + retention-days: 7 + + # Disabled for now - uncomment when ready to build iOS TV + # build-ios-tv: + # if: (!contains(github.event.head_commit.message, '[skip ci]') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'streamyfin/streamyfin')) + # runs-on: macos-15 + # name: 🍎 Build iOS IPA (TV) + # permissions: + # contents: read + # + # steps: + # - name: 📥 Checkout code + # uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + # with: + # ref: ${{ github.event.pull_request.head.sha || github.sha }} + # fetch-depth: 0 + # submodules: recursive + # show-progress: false + # + # - name: 🍞 Setup Bun + # uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 + # with: + # bun-version: latest + # + # - name: 💾 Cache Bun dependencies + # uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + # with: + # path: ~/.bun/install/cache + # key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} + # restore-keys: | + # ${{ runner.os }}-bun-cache + # + # - name: 📦 Install dependencies and reload submodules + # run: | + # bun install --frozen-lockfile + # bun run submodule-reload + # + # - name: 🛠️ Generate project files + # run: bun run prebuild:tv + # + # - name: 🏗️ Setup EAS + # uses: expo/expo-github-action@main + # with: + # eas-version: latest + # token: ${{ secrets.EXPO_TOKEN }} + # eas-cache: true + # + # - name: ⚙️ Ensure tvOS SDKs installed + # run: xcodebuild -downloadPlatform tvOS + # + # - name: 🚀 Build iOS app + # env: + # EXPO_TV: 1 + # run: eas build -p ios --local --non-interactive + # + # - name: 📅 Set date tag + # run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV + # + # - name: 📤 Upload IPA artifact + # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + # with: + # name: streamyfin-ios-tv-ipa-${{ env.DATE_TAG }} + # path: build-*.ipa + # retention-days: 7 diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml deleted file mode 100644 index 76e4a4d2..00000000 --- a/.github/workflows/build-ios.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: 🤖 iOS IPA Build (Phone + TV) - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -on: - workflow_dispatch: - pull_request: - branches: [develop, master] - paths-ignore: - - "*.md" - push: - branches: [develop, master] - paths-ignore: - - "*.md" - -jobs: - build-ios: - if: (!contains(github.event.head_commit.message, '[skip ci]') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'streamyfin/streamyfin')) - runs-on: macos-15 - name: 🏗️ Build iOS IPA - permissions: - contents: read - - strategy: - fail-fast: false - matrix: - target: [phone] - # target: [phone, tv] - - steps: - - name: 📥 Checkout code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - fetch-depth: 0 - submodules: recursive - show-progress: false - - - name: 🍞 Setup Bun - uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 - with: - bun-version: latest - - - name: 💾 Cache Bun dependencies - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - with: - path: ~/.bun/install/cache - key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} - restore-keys: | - ${{ runner.os }}-bun-cache - - - name: 📦 Install dependencies and reload submodules - run: | - bun install --frozen-lockfile - bun run submodule-reload - - - name: 🛠️ Generate project files - run: | - if [ "${{ matrix.target }}" = "tv" ]; then - bun run prebuild:tv - else - bun run prebuild - fi - - - name: 🏗️ Setup EAS - uses: expo/expo-github-action@main - with: - eas-version: latest - token: ${{ secrets.EXPO_TOKEN }} - eas-cache: true - - - name: ⚙️ Ensure iOS/tvOS SDKs installed - run: | - if [ "${{ matrix.target }}" = "tv" ]; then - xcodebuild -downloadPlatform tvOS - else - xcodebuild -downloadPlatform iOS - fi - - - name: 🚀 Build iOS app - env: - EXPO_TV: ${{ matrix.target == 'tv' && 1 || 0 }} - run: eas build -p ios --local --non-interactive - - - name: 📅 Set date tag - run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV - - - name: 📤 Upload IPA artifact - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: streamyfin-ios-${{ matrix.target }}-ipa-${{ env.DATE_TAG }} - path: build-*.ipa - retention-days: 7