name: Reusable SideStore Build

on:
  workflow_call:
    inputs:
      is_beta:
        required: false
        default: false
        type: boolean
      publish:
        required: false
        default: false
        type: boolean
      is_shared_build_num:
        required: false
        default: true
        type: boolean
      release_name:
        required: true
        type: string
      release_tag:
        required: true
        type: string
      upstream_tag:
        required: true
        type: string
      upstream_name:
        required: true
        type: string
      bundle_id:
        default: com.SideStore.SideStore
        required: true
        type: string
      bundle_id_suffix:
        default: ''
        required: false
        type: string

    secrets:
    #   GITHUB_TOKEN:
    #     required: true
      CROSS_REPO_PUSH_KEY:
        required: true
      BUILD_LOG_ZIP_PASSWORD:
        required: false

jobs:
  serialize:
    name: Wait for other jobs
    concurrency:
      group: build-number-increment   # serialize for build num cache access
    strategy:
      fail-fast: false
    runs-on: 'macos-15'
    steps:
    - run: echo "No other contending jobs are running now...Build is ready to start"
    - name: Set short commit hash
      id: commit-id
      run: |
        # SHORT_COMMIT="${{ github.sha }}"
        SHORT_COMMIT=${GITHUB_SHA:0:7}
        echo "Short commit hash: $SHORT_COMMIT"
        echo "SHORT_COMMIT=$SHORT_COMMIT" >> $GITHUB_OUTPUT
    outputs:
      short-commit: ${{ steps.commit-id.outputs.SHORT_COMMIT }}

  build:
    name: Build SideStore - ${{ inputs.release_tag }}
    needs: serialize
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: 'macos-15'
            version: '16.1'

    runs-on: ${{ matrix.os }}
    outputs:
      version: ${{ steps.version.outputs.version }}
      marketing-version: ${{ steps.marketing-version.outputs.MARKETING_VERSION }}
      release-channel: ${{ steps.release-channel.outputs.RELEASE_CHANNEL }}

    steps:
      - name: Set beta status
        run: echo "IS_BETA=${{ inputs.is_beta }}" >> $GITHUB_ENV

      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install dependencies - ldid & xcbeautify
        run: |
          brew install ldid xcbeautify

      - name: Set ref based on is_shared_build_num
        if: ${{ inputs.is_beta }}
        id: set_ref
        run: |
          if [ "${{ inputs.is_shared_build_num }}" == "true" ]; then
            echo "ref=main" >> $GITHUB_ENV
          else
            echo "ref=${{ inputs.release_tag }}" >> $GITHUB_ENV
          fi

      - name: Checkout SideStore/beta-build-num repo
        if: ${{ inputs.is_beta }}
        uses: actions/checkout@v4
        with:
          repository: 'SideStore/beta-build-num'
          ref: ${{ env.ref }}
          token: ${{ secrets.CROSS_REPO_PUSH_KEY }}
          path: 'SideStore/beta-build-num'

      - name: Copy build_number.txt to repo root
        if: ${{ inputs.is_beta }}
        run: |
          cp SideStore/beta-build-num/build_number.txt .
          echo "cat build_number.txt"
          cat build_number.txt

      - name: Echo Build.xcconfig
        run: |
          echo "cat Build.xcconfig"
          cat Build.xcconfig

      - name: Set Release Channel info for build number bumper
        id: release-channel
        run: |
          RELEASE_CHANNEL="${{ inputs.release_tag }}"
          echo "RELEASE_CHANNEL=${RELEASE_CHANNEL}" >> $GITHUB_ENV
          echo "RELEASE_CHANNEL=${RELEASE_CHANNEL}" >> $GITHUB_OUTPUT
          echo "RELEASE_CHANNEL=${RELEASE_CHANNEL}"
          
          
      - name: Increase build number for beta builds
        if: ${{ inputs.is_beta }}
        run: |
          bash .github/workflows/increase-beta-build-num.sh

      - name: Extract MARKETING_VERSION from Build.xcconfig
        id: version
        run: |
          version=$(grep MARKETING_VERSION Build.xcconfig | sed -e 's/MARKETING_VERSION = //g')
          echo "version=$version" >> $GITHUB_OUTPUT
          echo "version=$version"

      - name: Set MARKETING_VERSION
        if: ${{ inputs.is_beta }}
        id: marketing-version
        run: |
          # Extract version number (e.g., "0.6.0")
          version=$(echo "${{ steps.version.outputs.version }}" | sed -E 's/^[^0-9]*([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
          # Extract date (YYYYMMDD) (e.g., "20250205")
          date=$(echo "${{ steps.version.outputs.version }}" | sed -E 's/.*\.([0-9]{4})\.([0-9]{2})\.([0-9]{2})\..*/\1\2\3/')
          # Extract build number (e.g., "2")
          build_num=$(echo "${{ steps.version.outputs.version }}" | sed -E 's/.*\.([0-9]+)\+.*/\1/')

          # Combine them into the final output
          MARKETING_VERSION="${version}-${date}.${build_num}+${{ needs.serialize.outputs.short-commit }}"

          echo "MARKETING_VERSION=$MARKETING_VERSION" >> $GITHUB_ENV
          echo "MARKETING_VERSION=$MARKETING_VERSION" >> $GITHUB_OUTPUT
          echo "MARKETING_VERSION=$MARKETING_VERSION"

      - name: Echo Updated Build.xcconfig, build_number.txt
        if: ${{ inputs.is_beta }}
        run: |
          cat Build.xcconfig
          cat build_number.txt

      - name: Setup Xcode
        uses: maxim-lobanov/setup-xcode@v1.6.0
        with:
          xcode-version: ${{ matrix.version }}

      - name: (Build) Cache Build
        uses: irgaly/xcode-cache@v1
        with:
          key: xcode-cache-deriveddata-build-${{ github.sha }}
          restore-keys: xcode-cache-deriveddata-build-
          swiftpm-cache-key: xcode-cache-sourcedata-build-${{ github.sha }}
          swiftpm-cache-restore-keys: |
            xcode-cache-sourcedata-build-

      - name: (Build) Restore Pods from Cache (Exact match)
        id: pods-restore
        uses: actions/cache/restore@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-build-${{ hashFiles('Podfile') }}
          # restore-keys: |         # commented out to strictly check cache for this particular podfile
          #   pods-cache-

      - name: (Build) Restore Pods from Cache (Last Available)
        if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
        id: pods-restore-recent
        uses: actions/cache/restore@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-build-


      - name: (Build) Install CocoaPods
        run: pod install

      - name: (Build) Save Pods to Cache
        id: save-pods
        if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
        uses: actions/cache/save@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-build-${{ hashFiles('Podfile') }}

      - name: (Build) Clean previous build artifacts
        # using 'tee' to intercept stdout and log for detailed build-log
        run: |
          make clean
          mkdir -p build/logs

      - name: (Build) List Files and derived data
        if: always()
        run: |
          echo ">>>>>>>>> Workdir <<<<<<<<<<"
          ls -la .
          echo ""

          echo ">>>>>>>>> Pods <<<<<<<<<<"
          find Pods -maxdepth 2 -exec ls -ld {} + || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> SideStore <<<<<<<<<<"
          find SideStore -maxdepth 2 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> Dependencies <<<<<<<<<<"
          find Dependencies -maxdepth 2 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<"
          ls -la ~/Library/Developer/Xcode/DerivedData || true  # List contents if directory exists
          echo ""

      - name: Set BundleID Suffix for Sidestore build
        run: |
          echo "BUNDLE_ID_SUFFIX=${{ inputs.bundle_id_suffix }}" >> $GITHUB_ENV


      - name: Build SideStore.xcarchive
        # using 'tee' to intercept stdout and log for detailed build-log
        run: |
          NSUnbufferedIO=YES make -B build 2>&1 | tee -a build/logs/build.log | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]}

      - name: Fakesign app
        run: make fakesign | tee -a build/logs/build.log

      - name: Convert to IPA
        run: make ipa | tee -a build/logs/build.log

      - name: (Build) List Files and Build artifacts
        run: |
          echo ">>>>>>>>> Workdir <<<<<<<<<<"
          ls -la .
          echo ""

          echo ">>>>>>>>> Build <<<<<<<<<<"
          find build -maxdepth 3 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> SideStore <<<<<<<<<<"
          find SideStore -maxdepth 3 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> SideStore.xcarchive <<<<<<<<<<"
          find SideStore.xcarchive -maxdepth 3 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

      - name: Encrypt build-logs for upload
        id: encrypt-build-log
        run: |
          DEFAULT_BUILD_LOG_PASSWORD=12345

          BUILD_LOG_ZIP_PASSWORD=${{ secrets.BUILD_LOG_ZIP_PASSWORD }}
          BUILD_LOG_ZIP_PASSWORD=${BUILD_LOG_ZIP_PASSWORD:-$DEFAULT_BUILD_LOG_PASSWORD}

          if [ "$BUILD_LOG_ZIP_PASSWORD" == "$DEFAULT_BUILD_LOG_PASSWORD" ]; then
            echo "Warning: BUILD_LOG_ZIP_PASSWORD is not set. Defaulting to '${DEFAULT_BUILD_LOG_PASSWORD}'."
          fi
          
          pushd build/logs && zip -e -P "$BUILD_LOG_ZIP_PASSWORD" ../../encrypted-build-logs.zip * || popd
          echo "::set-output name=encrypted::true"
      
      - name: Upload encrypted-build-logs.zip
        id: attach-encrypted-build-log
        if: ${{ always() && steps.encrypt-build-log.outputs.encrypted == 'true' }}
        uses: actions/upload-artifact@v4
        with:
          name: encrypted-build-logs-${{ steps.version.outputs.version }}.zip
          path: encrypted-build-logs.zip

      - name: Upload SideStore.ipa Artifact
        uses: actions/upload-artifact@v4
        with:
          name: SideStore-${{ steps.version.outputs.version }}.ipa
          path: SideStore.ipa

      - name: Zip dSYMs
        run: zip -r -9 ./SideStore.dSYMs.zip ./SideStore.xcarchive/dSYMs
  
      - name: Upload *.dSYM Artifact
        uses: actions/upload-artifact@v4
        with:
          name: SideStore-${{ steps.version.outputs.version }}-dSYMs.zip
          path: SideStore.dSYMs.zip

      - name: Zip beta-beta-build-num & update_apps.py
        run: |
          zip -r -9 ./beta-build-num.zip ./SideStore/beta-build-num update_apps.py

      - name: Upload beta-build-num artifact
        if: ${{ inputs.is_beta }}
        uses: actions/upload-artifact@v4
        with:
          name: beta-build-num-${{ steps.version.outputs.version }}.zip
          path: beta-build-num.zip


  tests-build:
    name: Tests-Build SideStore - ${{ inputs.release_tag }}
    needs: serialize
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: 'macos-15'
            version: '16.1'
    runs-on: ${{ matrix.os }}

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install dependencies - xcbeautify
        run: |
          brew install xcbeautify

      - name: Setup Xcode
        uses: maxim-lobanov/setup-xcode@v1.6.0
        with:
          xcode-version: '16.1'

      - name: (Tests-Build) Cache Build
        uses: irgaly/xcode-cache@v1
        with:
          key: xcode-cache-deriveddata-test-${{ github.sha }}
          restore-keys: xcode-cache-deriveddata-test-
          swiftpm-cache-key: xcode-cache-sourcedata-test-${{ github.sha }}
          swiftpm-cache-restore-keys: |
            xcode-cache-sourcedata-test-

      - name: (Tests-Build) Restore Pods from Cache (Exact match)
        id: pods-restore
        uses: actions/cache/restore@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-test-${{ hashFiles('Podfile') }}

      - name: (Tests-Build) Restore Pods from Cache (Last Available)
        if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
        id: pods-restore-recent
        uses: actions/cache/restore@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-test-

      - name: (Tests-Build) Install CocoaPods
        run: pod install

      - name: (Tests-Build) Save Pods to Cache
        if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
        uses: actions/cache/save@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-test-${{ hashFiles('Podfile') }}

      - name: (Tests-Build) Clean previous build artifacts
        run: |
          make clean
          mkdir -p build/logs

      - name: (Tests-Build) List Files and derived data
        run: |
          echo ">>>>>>>>> Workdir <<<<<<<<<<"
          ls -la .
          echo ""

          echo ">>>>>>>>> Pods <<<<<<<<<<"
          find Pods -maxdepth 2 -exec ls -ld {} + || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> SideStore <<<<<<<<<<"
          find SideStore -maxdepth 2 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> Dependencies <<<<<<<<<<"
          find Dependencies -maxdepth 2 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<"
          ls -la ~/Library/Developer/Xcode/DerivedData || true  # List contents if directory exists
          echo ""

      - name: Build SideStore Tests
        # using 'tee' to intercept stdout and log for detailed build-log
        run: |
          NSUnbufferedIO=YES make -B build-tests 2>&1 | tee -a build/logs/tests-build.log | xcbeautify --renderer github-actions && exit ${PIPESTATUS[0]}

      - name: (Tests-Build) List Files and Build artifacts
        if: always()
        run: |
          echo ">>>>>>>>> Workdir <<<<<<<<<<"
          ls -la .
          echo ""

          echo ">>>>>>>>> Build <<<<<<<<<<"
          find build -maxdepth 3 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

      - name: Encrypt tests-build-logs for upload
        id: encrypt-test-log
        if: always()
        run: |
          DEFAULT_BUILD_LOG_PASSWORD=12345

          BUILD_LOG_ZIP_PASSWORD=${{ secrets.BUILD_LOG_ZIP_PASSWORD }}
          BUILD_LOG_ZIP_PASSWORD=${BUILD_LOG_ZIP_PASSWORD:-$DEFAULT_BUILD_LOG_PASSWORD}

          if [ "$BUILD_LOG_ZIP_PASSWORD" == "$DEFAULT_BUILD_LOG_PASSWORD" ]; then
            echo "Warning: BUILD_LOG_ZIP_PASSWORD is not set. Defaulting to '${DEFAULT_BUILD_LOG_PASSWORD}'."
          fi

          pushd build/logs && zip -e -P "$BUILD_LOG_ZIP_PASSWORD" ../../encrypted-tests-build-logs.zip * || popd
          echo "::set-output name=encrypted::true"
      
      - name: Upload encrypted-tests-build-logs.zip
        id: attach-encrypted-test-log
        if: always() && steps.encrypt-test-log.outputs.encrypted == 'true'
        uses: actions/upload-artifact@v4
        with:
          name: encrypted-tests-build-logs-${{ needs.serialize.outputs.short-commit }}.zip
          path: encrypted-tests-build-logs.zip

  tests-run:
    name: Tests-Run SideStore - ${{ inputs.release_tag }}
    needs: [serialize, tests-build]
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: 'macos-15'
            version: '16.1'
    runs-on: ${{ matrix.os }}

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Boot Simulator for testing
        run: |
          mkdir -p build/logs
          make -B boot-sim-async | tee -a build/logs/tests-run.log
          exit ${PIPESTATUS[0]}

      - name: Setup Xcode
        uses: maxim-lobanov/setup-xcode@v1.6.0
        with:
          xcode-version: '16.1'

      - name: (Tests-Run) Cache Build
        uses: irgaly/xcode-cache@v1
        with:
          key: xcode-cache-deriveddata-test-${{ github.sha }}
          restore-keys: xcode-cache-deriveddata-test-
          swiftpm-cache-key: xcode-cache-sourcedata-test-${{ github.sha }}
          swiftpm-cache-restore-keys: |
            xcode-cache-sourcedata-test-

      - name: (Tests-Run) Restore Pods from Cache (Exact match)
        id: pods-restore
        uses: actions/cache/restore@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-test-${{ hashFiles('Podfile') }}

      - name: (Tests-Run) Restore Pods from Cache (Last Available)
        if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
        id: pods-restore-recent
        uses: actions/cache/restore@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-test-

      - name: (Tests-Run) Install CocoaPods
        run: pod install

      - name: (Tests-Run) Save Pods to Cache
        if: ${{ steps.pods-restore.outputs.cache-hit != 'true' }}
        uses: actions/cache/save@v3
        with:
          path: |
            ./Podfile.lock
            ./Pods/
            ./AltStore.xcworkspace/
          key: pods-cache-test-${{ hashFiles('Podfile') }}

      - name: (Tests-Run) Clean previous build artifacts
        run: |
          make clean
          mkdir -p build/logs

      - name: (Tests-Run) List Files and derived data
        run: |
          echo ">>>>>>>>> Workdir <<<<<<<<<<"
          ls -la .
          echo ""

          echo ">>>>>>>>> Pods <<<<<<<<<<"
          find Pods -maxdepth 2 -exec ls -ld {} + || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> SideStore <<<<<<<<<<"
          find SideStore -maxdepth 2 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> Dependencies <<<<<<<<<<"
          find Dependencies -maxdepth 2 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

          echo ">>>>>>>>> Xcode-Derived-Data <<<<<<<<<<"
          ls -la ~/Library/Developer/Xcode/DerivedData || true  # List contents if directory exists
          echo ""

      # we expect simulator to have been booted by now, so exit otherwise
      - name: Simulator Boot Check
        run: |
          mkdir -p build/logs
          make -B sim-boot-check | tee -a build/logs/tests-run.log
          exit ${PIPESTATUS[0]}

      - name: Start Recording UI tests (if DEBUG_RECORD_TESTS is set to 1)
        if: ${{ vars.DEBUG_RECORD_TESTS == '1' }}
        run: |
          nohup xcrun simctl io booted recordVideo -f tests-recording.mp4 --codec h264 </dev/null > tests-recording.log 2>&1 &
          RECORD_PID=$!
          echo "RECORD_PID=$RECORD_PID" >> $GITHUB_ENV

      - name: Run SideStore Tests
        # using 'tee' to intercept stdout and log for detailed build-log
        run: |
          make run-tests 2>&1 | tee -a build/logs/tests-run.log && exit ${PIPESTATUS[0]}
        # NSUnbufferedIO=YES make -B run-tests 2>&1 | tee build/logs/tests-run.log | xcpretty -r junit --output ./build/tests/test-results.xml && exit ${PIPESTATUS[0]}

      - name: Stop Recording tests
        if: ${{ always() && env.RECORD_PID != '' }}
        run: |
          kill -INT ${{ env.RECORD_PID }}

      - name: (Tests-Run) List Files and Build artifacts
        if: always()
        run: |
          echo ">>>>>>>>> Workdir <<<<<<<<<<"
          ls -la .
          echo ""

          echo ">>>>>>>>> Build <<<<<<<<<<"
          find build -maxdepth 3 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""

      - name: Encrypt tests-run-logs for upload
        id: encrypt-test-log
        if: always()
        run: |
          DEFAULT_BUILD_LOG_PASSWORD=12345

          BUILD_LOG_ZIP_PASSWORD=${{ secrets.BUILD_LOG_ZIP_PASSWORD }}
          BUILD_LOG_ZIP_PASSWORD=${BUILD_LOG_ZIP_PASSWORD:-$DEFAULT_BUILD_LOG_PASSWORD}

          if [ "$BUILD_LOG_ZIP_PASSWORD" == "$DEFAULT_BUILD_LOG_PASSWORD" ]; then
            echo "Warning: BUILD_LOG_ZIP_PASSWORD is not set. Defaulting to '${DEFAULT_BUILD_LOG_PASSWORD}'."
          fi

          pushd build/logs && zip -e -P "$BUILD_LOG_ZIP_PASSWORD" ../../encrypted-tests-run-logs.zip * || popd
          echo "::set-output name=encrypted::true"
      
      - name: Upload encrypted-tests-run-logs.zip
        id: attach-encrypted-test-log
        if: always() && steps.encrypt-test-log.outputs.encrypted == 'true'
        uses: actions/upload-artifact@v4
        with:
          name: encrypted-tests-run-logs-${{ needs.serialize.outputs.short-commit }}.zip
          path: encrypted-tests-run-logs.zip

      - name: Print tests-recording.log contents (if exists)
        if: ${{ always() && env.RECORD_PID != '' }}
        run: |
          if [ -f tests-recording.log ]; then
            echo "tests-recording.log found. Its contents:"
            cat tests-recording.log
          else
            echo "tests-recording.log not found."
          fi

      - name: Check for tests-recording.mp4 presence
        id: check-recording
        if: ${{ always() && env.RECORD_PID != '' }}
        run: |
          if [ -f tests-recording.mp4 ]; then
            echo "::set-output name=found::true"
            echo "tests-recording.mp4 found."
          else
            echo "tests-recording.mp4 not found, skipping upload."
            echo "::set-output name=found::false"
          fi

      - name: Upload tests-recording.mp4
        id: upload-recording
        if: ${{ always() && steps.check-recording.outputs.found == 'true' }}
        uses: actions/upload-artifact@v4
        with:
          name: tests-recording-${{ needs.serialize.outputs.short-commit }}.mp4
          path: tests-recording.mp4

      - name: Zip test-results
        run: zip -r -9 ./test-results.zip ./build/tests
  
      - name: Upload Test Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: test-results-${{ needs.serialize.outputs.short-commit }}.zip
          path: test-results.zip

  deploy:
    name: Deploy SideStore - ${{ inputs.release_tag }}
    runs-on: macos-15
    # needs: [serialize, build]
    needs: [serialize, build, tests-build, tests-run]
    steps:
      - name: Download IPA artifact
        uses: actions/download-artifact@v4
        with:
          name: SideStore-${{ needs.build.outputs.version }}.ipa

      - name: Download dSYM artifact
        uses: actions/download-artifact@v4
        with:
          name: SideStore-${{ needs.build.outputs.version }}-dSYMs.zip

      - name: Download encrypted-build-logs artifact
        uses: actions/download-artifact@v4
        with:
          name: encrypted-build-logs-${{ needs.build.outputs.version }}.zip

      - name: Download encrypted-tests-build-logs artifact
        uses: actions/download-artifact@v4
        with:
          name: encrypted-tests-build-logs-${{ needs.serialize.outputs.short-commit }}.zip

      - name: Download encrypted-tests-run-logs artifact
        uses: actions/download-artifact@v4
        with:
          name: encrypted-tests-run-logs-${{ needs.serialize.outputs.short-commit }}.zip

      - name: Download tests-recording artifact
        uses: actions/download-artifact@v4
        with:
          name: tests-recording-${{ needs.serialize.outputs.short-commit }}.mp4

      - name: Download test-results artifact
        uses: actions/download-artifact@v4
        with:
          name: test-results-${{ needs.serialize.outputs.short-commit }}.zip

      - name: Download beta-build-num artifact
        if: ${{ inputs.is_beta }}
        uses: actions/download-artifact@v4
        with:
          name: beta-build-num-${{ needs.build.outputs.version }}.zip
      - name: Un-Zip beta-beta-build-num & update_apps.py
        run: |
          unzip beta-build-num.zip -d .
  
  
      - name: List files before upload
        run: |
          echo ">>>>>>>>> Workdir <<<<<<<<<<"
          find . -maxdepth 4 -exec ls -ld {} +  || true  # List contents if directory exists
          echo ""
  
      - name: Get current date
        id: date
        run: echo "date=$(date -u +'%c')" >> $GITHUB_OUTPUT

      - name: Get current date in AltStore date form
        id: date_altstore
        run: echo "date=$(date -u +'%Y-%m-%d')" >> $GITHUB_OUTPUT

      - name: Upload to releases
        uses: IsaacShelton/update-existing-release@v1.3.1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          release: ${{ inputs.release_name }}
          tag: ${{ inputs.release_tag }}
          prerelease: ${{ inputs.is_beta }}
          files: SideStore.ipa SideStore.dSYMs.zip encrypted-build-logs.zip encrypted-tests-build-logs.zip encrypted-tests-run-logs.zip test-results.zip tests-recording.mp4
          body: |
              This is an ⚠️ **EXPERIMENTAL** ⚠️ ${{ inputs.release_name }} build for commit [${{ github.sha }}](https://github.com/${{ github.repository }}/commit/${{ github.sha }}).

              ${{ inputs.release_name }} builds are **extremely experimental builds only meant to be used by developers and beta testers. They often contain bugs and experimental features. Use at your own risk!**

              If you want to try out new features early but want a lower chance of bugs, you can look at [SideStore ${{ inputs.upstream_name }}](https://github.com/${{ github.repository }}/releases?q=${{ inputs.upstream_tag }}).

              ## Build Info

              Built at (UTC): `${{ steps.date.outputs.date }}`
              Built at (UTC date): `${{ steps.date_altstore.outputs.date }}`
              Commit SHA: `${{ github.sha }}`
              Version: `${{ needs.build.outputs.version }}`

      - name: Publish to SideStore/beta-build-num
        if: ${{ inputs.is_beta }}
        run: |
          pushd SideStore/beta-build-num/
  
          echo "Configure Git user (committer details)"
          git config user.name "GitHub Actions"
          git config user.email "github-actions@github.com"
          
          echo "Adding files to commit"
          git add --verbose build_number.txt
          git commit -m " - updated for ${{ inputs.release_tag }} - ${{ needs.serialize.outputs.short-commit }} deployment" || echo "No changes to commit"

          echo "Pushing to remote repo"
          git push --verbose
          popd

      - name: Get formatted date
        run: |
          FORMATTED_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
          echo "Formatted date: $FORMATTED_DATE"
          echo "FORMATTED_DATE=$FORMATTED_DATE" >> $GITHUB_ENV

      - name: Get size of IPA in bytes (macOS/Linux)
        run: |
          if [[ "$(uname)" == "Darwin" ]]; then
            # macOS
            IPA_SIZE=$(stat -f %z SideStore.ipa)
          else
            # Linux
            IPA_SIZE=$(stat -c %s SideStore.ipa)
          fi
          echo "IPA size in bytes: $IPA_SIZE"
          echo "IPA_SIZE=$IPA_SIZE" >> $GITHUB_ENV

      - name: Compute SHA-256 of IPA
        run: |
          SHA256_HASH=$(shasum -a 256 SideStore.ipa | awk '{ print $1 }')
          echo "SHA-256 Hash: $SHA256_HASH"
          echo "SHA256_HASH=$SHA256_HASH" >> $GITHUB_ENV

      - name: Set Release Info variables
        run: |
          # Format localized description
          LOCALIZED_DESCRIPTION=$(cat <<EOF
          This is release for:
            - version: "${{ needs.build.outputs.version }}"
            - revision: "${{ needs.serialize.outputs.short-commit }}"
            - timestamp: "${{ steps.date.outputs.date }}"
          EOF
          )

          echo "IS_BETA=${{ inputs.is_beta }}" >> $GITHUB_ENV
          echo "BUNDLE_IDENTIFIER=${{ inputs.bundle_id }}" >> $GITHUB_ENV
          echo "VERSION_IPA=${{ needs.build.outputs.marketing-version }}" >> $GITHUB_ENV
          echo "VERSION_DATE=$FORMATTED_DATE" >> $GITHUB_ENV
          echo "RELEASE_CHANNEL=${{ needs.build.outputs.release-channel }}" >> $GITHUB_ENV
          echo "SIZE=$IPA_SIZE" >> $GITHUB_ENV
          echo "SHA256=$SHA256_HASH" >> $GITHUB_ENV
          echo "DOWNLOAD_URL=https://github.com/SideStore/SideStore/releases/download/${{ inputs.release_tag }}/SideStore.ipa" >> $GITHUB_ENV

          # multiline strings
          echo "LOCALIZED_DESCRIPTION<<EOF" >> $GITHUB_ENV
          echo "$LOCALIZED_DESCRIPTION" >> $GITHUB_ENV
          echo "EOF" >> $GITHUB_ENV

      - name: Check if Publish updates is set
        id: check_publish
        run: |
          echo "Publish updates to source.json = ${{ inputs.publish }}"

      - name: Checkout SideStore/apps-v2.json
        if: ${{ inputs.is_beta && inputs.publish }}
        uses: actions/checkout@v4
        with:
          repository: 'SideStore/apps-v2.json'
          ref: 'main'   # this branch is shared by all beta builds, so beta build workflows are serialized
          token: ${{ secrets.CROSS_REPO_PUSH_KEY }}
          path: 'SideStore/apps-v2.json'

      # for stable builds, let the user manually edit the source.json
      - name: Publish to SideStore/apps-v2.json
        if: ${{ inputs.is_beta && inputs.publish }}
        id: publish-release
        run: |
          # Copy and execute the update script
          pushd SideStore/apps-v2.json/

          # Configure Git user (committer details)
          git config user.name "GitHub Actions"
          git config user.email "github-actions@github.com"

          # update the source.json
          python3 ../../update_apps.py "./_includes/source.json"

          # Commit changes and push using SSH
          git add --verbose ./_includes/source.json
          git commit -m " - updated for ${{ needs.serialize.outputs.short-commit }} deployment" || echo "No changes to commit"

          git push --verbose
          popd
