Check cache

# Check if we actually need to build any of the packages and if not, this job will prepare the artifacts
# required by downstream jobs.
#
# Cache hits are detected by hashing all relevant files. This is required as we might be running CI on
# multiple commits on the same branch.
#
# There is a small chance the cache gets invalidated between this check and downstream jobs run.
# This is acceptable as the work-around is just rerunning the build.
#
# Some notes on caching and artifacts:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows
# - Caches are restricted to current back and fall back to default branch (master)
# - Caches cannot be downloaded to a new location.
# - Artifacts are restricted to current workflow.
#
name: Check cache

on:
  workflow_call:
    outputs:
      version-label:
        value: ${{ jobs.check-cache.outputs.version-label }}
      packages-metadata-cache-hit:
        value: ${{ jobs.check-cache.outputs.packages-metadata-cache-hit }}
      packages-jvm-cache-hit:
        value: ${{ jobs.check-cache.outputs.packages-jvm-cache-hit }}
      packages-android-cache-hit:
        value: ${{ jobs.check-cache.outputs.packages-android-cache-hit }}
      android-test-base-apk-cache-hit:
        value: ${{ jobs.check-cache.outputs.android-test-base-apk-cache-hit }}
      android-test-sync-apk-cache-hit:
        value: ${{ jobs.check-cache.outputs.android-test-sync-apk-cache-hit }}
      packages-macos-x64-cache-hit:
        value: ${{ jobs.check-cache.outputs.packages-macos-x64-cache-hit }}
      packages-macos-arm64-cache-hit:
        value: ${{ jobs.check-cache.outputs.packages-macos-arm64-cache-hit }}
      packages-ios-x64-cache-hit:
        value: ${{ jobs.check-cache.outputs.packages-ios-x64-cache-hit }}
      packages-ios-arm64-cache-hit:
        value: ${{ jobs.check-cache.outputs.packages-ios-arm64-cache-hit }}
      jni-swig-stub-cache-hit:
        value: ${{ jobs.check-cache.outputs.jni-swig-stub-cache-hit }}
      jni-linux-lib-cache-hit:
        value: ${{ jobs.check-cache.outputs.jni-linux-lib-cache-hit }}
      jni-macos-lib-cache-hit:
        value: ${{ jobs.check-cache.outputs.jni-macos-lib-cache-hit }}
      jni-windows-lib-cache-hit:
        value: ${{ jobs.check-cache.outputs.jni-windows-lib-cache-hit }}
      packages-sha:
        value: ${{ jobs.check-cache.outputs.packages-sha }}
      benchmarks-sha:
        value: ${{ jobs.check-cache.outputs.benchmarks-sha }}
      core-commit-sha:
        value: ${{ jobs.check-cache.outputs.core-commit-sha }}

jobs:
  check-cache:
    runs-on: ubuntu-latest
    name: Check cache
    env:
      CACHE_SKIP_SAVE: true
    outputs:
      version-label: ${{ steps.find-library-version.outputs.label }}
      packages-metadata-cache-hit: ${{ steps.kotlin-metadata-cache.outputs.cache-hit }}
      packages-jvm-cache-hit: ${{ steps.jvm-cache.outputs.cache-hit }}
      packages-android-cache-hit: ${{ steps.android-cache.outputs.cache-hit }}
      android-test-base-apk-cache-hit: ${{ steps.android-test-base-apk.outputs.cache-hit }}
      android-test-sync-apk-cache-hit: ${{ steps.android-test-sync-apk.outputs.cache-hit }}
      packages-macos-x64-cache-hit: ${{ steps.macos-x64-cache.outputs.cache-hit }}
      packages-macos-arm64-cache-hit: ${{ steps.macos-arm64-cache.outputs.cache-hit }}
      packages-ios-x64-cache-hit: ${{ steps.ios-x64-cache.outputs.cache-hit }}
      packages-ios-arm64-cache-hit: ${{ steps.ios-arm64-cache.outputs.cache-hit }}
      jni-swig-stub-cache-hit: ${{ steps.jni-swig-stub-cache.outputs.cache-hit }}
      jni-linux-lib-cache-hit: ${{ steps.jni-linux-lib-cache.outputs.cache-hit }}
      jni-macos-lib-cache-hit: ${{ steps.jni-macos-lib-cache.outputs.cache-hit }}
      jni-windows-lib-cache-hit: ${{ steps.jni-windows-lib-cache.outputs.cache-hit }}
      packages-sha: ${{ steps.packages-cache-key.outputs.sha }}
      benchmarks-sha: ${{ steps.calculate-benchmarks-cache-key.outputs.sha }}
      core-commit-sha: ${{ steps.calculate-core-commmit-sha.outputs.commit }}

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

    - name: Find library version
      id: find-library-version
      run: |
        version=$(grep "const val version" buildSrc/src/main/kotlin/Config.kt | cut -d \" -f2)
        echo "label=$version" >> $GITHUB_OUTPUT

    # This also include changes to Realm Core as they are hashed as part of `/packages/external/core`
    - name: Calculate ./packages SHAs
      id: packages-cache-key
      run: echo "sha=${{ hashFiles('./packages/**', './buildSrc/**') }}" >> $GITHUB_OUTPUT

    - name: Calculate ./benchmarks SHAs
      id: calculate-benchmarks-cache-key
      run: echo "sha=${{ hashFiles('./benchmarks/**') }}" >> $GITHUB_OUTPUT

    - name: Calculate Realm Core commit SHA
      id: calculate-core-commit-sha
      working-directory: packages/external/core
      run: echo "commit=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT

    #
    # For each specific package we need to perform 3 steps:
    #
    # 1. Check if a cache is available and download it if it is.
    # 2. If (1), store this cache as an artifact for jobs downstream to use.
    # 3. Cleanup the build folder. This is required so we can download the next
    #    platform into a fresh cache location. It does not look possible to download
    #    a cache into a different location.
    #
    # TODO There doesn't seem to be a good way to check if a cache key exists without download it.
    # https://github.com/actions/cache/issues/321
    #
    # TODO Create a custom action for this until we have a work-around?
    #

    #
    # Kotlin Metadata and Gradle/Compiler Plugin
    #
    - name: Check Kotlin Metadata cache
      id: kotlin-metadata-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/build/m2-buildrepo
        key: packages-m2-metadata-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save Kotlin Metadata packages
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.kotlin-metadata-cache.outputs.cache-hit == 'true'
      with:
        name: packages-metadata-${{ steps.find-library-version.outputs.label }}
        path: ./packages/build/m2-buildrepo/**/*
        retention-days: 1

    - name: Delete downloaded JVM cache files
      id: delete-cache-metadata
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.kotlin-metadata-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/build/m2-buildrepo

    #
    # JVM (All platforms)
    #
    - name: Check JVM cache
      id: jvm-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/build/m2-buildrepo
        key: packages-m2-jvm-sync-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save JVM packages
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.jvm-cache.outputs.cache-hit == 'true'
      with:
        name: packages-jvm-${{ steps.find-library-version.outputs.label }}
        path: ./packages/build/m2-buildrepo/**/*
        retention-days: 1

    - name: Delete downloaded JVM cache files
      id: delete-cache-jvm
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.jvm-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/build/m2-buildrepo

    #
    # JNI Stub (JVM)
    #
    - name: Check JNI Swig stub cache
      id: jni-swig-stub-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/jni-swig-stub/build/generated/sources/jni
        key: jni-swig-stubs-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save JNI Stub packages
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.jni-swig-stub-cache.outputs.cache-hit == 'true'
      with:
        name: jni-stub-${{ steps.find-library-version.outputs.label }}
        path: ./packages/jni-swig-stub/build/generated/sources/jni/*
        retention-days: 1

    - name: Delete downloaded JVM cache files
      id: delete-cache-jni-stub
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.jni-swig-stub-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/jni-swig-stub/build/generated/sources/jni

    #
    # JNI MacOS Lib
    #
    - name: Check JNI MacOS lib cache
      id: jni-macos-lib-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/cinterop/build/realmMacOsBuild
        key: jni-macos-lib-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save JNI MacOS lib package
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.jni-macos-lib-cache.outputs.cache-hit == 'true'
      with:
        name: jni-macos-lib-${{ steps.find-library-version.outputs.label }}
        path: ./packages/cinterop/build/realmMacOsBuild/**/*
        retention-days: 1

    - name: Delete downloaded JVM cache files
      id: delete-cache-macos-lib
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.jni-macos-lib-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/cinterop/build/realmMacOsBuild

    #
    # JNI Linux Lib
    #
    - name: Check JNI Linux lib cache
      id: jni-linux-lib-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/cinterop/build/realmLinuxBuild
        key: jni-linux-lib-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save JNI Linux lib package
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.jni-linux-lib-cache.outputs.cache-hit == 'true'
      with:
        name: jni-linux-lib-${{ steps.find-library-version.outputs.label }}
        path: ./packages/cinterop/build/realmLinuxBuild/**/*
        retention-days: 1

    - name: Delete downloaded JVM cache files
      id: delete-cache-linux-lib
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.jni-linux-lib-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/cinterop/build/realmLinuxBuild

    #
    # Android
    #
    - name: Check Android cache
      id: android-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/build/m2-buildrepo
        key: packages-m2-android-sync-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save Android packages
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.android-cache.outputs.cache-hit == 'true'
      with:
        name: packages-android-${{ steps.find-library-version.outputs.label }}
        path: ./packages/build/m2-buildrepo/**/*
        retention-days: 1

    - name: Delete downloaded Android cache files
      id: delete-cache-android
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.android-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/build/m2-buildrepo

      #
      # Android Base Test APK
      #
    - name: Check Android Base Test APK
      id: android-test-base-apk
      uses: cmelchior/cache@main
      with:
        path: ./packages/test-base/build/outputs/apk/androidTest/debug/test-base-debug-androidTest.apk
        key: android-base-test-apk-key-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save Android Base Test APK
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.android-test-base-apk.outputs.cache-hit == 'true'
      with:
        name: android-base-test-apk-${{ steps.find-library-version.outputs.label }}
        path: ./packages/test-base/build/outputs/apk/androidTest/debug/test-base-debug-androidTest.apk
        retention-days: 1

    - name: Delete Android Base Test APK cache files
      id: delete-cache-android-base-test-apk
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.android-test-base-apk.outputs.cache-hit == 'true'
      with:
        path: ./packages/test-base/build/outputs/apk/androidTest/debug/test-base-debug-androidTest.apk

      #
      # Android Sync Test APK
      #
    - name: Check Android Sync Test APK
      id: android-test-sync-apk
      uses: cmelchior/cache@main
      with:
        key: android-sync-test-apk-key-${{ steps.packages-cache-key.outputs.sha }}
        path: |
          ./packages/test-sync/build/outputs/apk/androidTest/debug/test-sync-debug-androidTest.apk
          ./packages/test-sync/build/outputs/apk/debug/test-sync-debug.apk

    - name: Save Android Sync Test APK
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.android-test-sync-apk.outputs.cache-hit == 'true'
      with:
        name: android-sync-test-apk-${{ steps.find-library-version.outputs.label }}
        retention-days: 1
        path: |
          ./packages/test-sync/build/outputs/apk/androidTest/debug/test-sync-debug-androidTest.apk
          ./packages/test-sync/build/outputs/apk/debug/test-sync-debug.apk

    - name: Delete Android Sync Test APK cache files
      id: delete-cache-android-sync-test-apk
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.android-test-sync-apk.outputs.cache-hit == 'true'
      with:
        path: |
          ./packages/test-sync/build/outputs/apk/androidTest/debug/test-sync-debug-androidTest.apk
          ./packages/test-sync/build/outputs/apk/debug/test-sync-debug.apk

    #
    # MacOS arm64
    #
    - name: Check MacOS arm64 cache
      id: macos-arm64-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/build/m2-buildrepo
        key: packages-m2-macos-arm64-sync-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save MacOS arm64 packages
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.macos-arm64-cache.outputs.cache-hit == 'true'
      with:
        name: packages-macos-arm64-${{ steps.find-library-version.outputs.label }}
        path: ./packages/build/m2-buildrepo/**/*
        retention-days: 1

    - name: Delete downloaded MacOS arm64 cache files
      id: delete-cache-macos-arm64
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.macos-arm64-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/build/m2-buildrepo

    #
    # MacOS x64
    #
    - name: Check MacOS X64 cache
      id: macos-x64-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/build/m2-buildrepo
        key: packages-m2-macos-x64-sync-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save MacOS x64 packages
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.macos-x64-cache.outputs.cache-hit == 'true'
      with:
        name: packages-macos-x64-${{ steps.find-library-version.outputs.label }}
        path: ./packages/build/m2-buildrepo/**/*
        retention-days: 1

    - name: Delete downloaded MacOS x64 cache files
      id: delete-cache-macos-x64
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.macos-x64-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/build/m2-buildrepo

    #
    # iOS arm64
    #
    - name: Check iOS arm64 cache
      id: ios-arm64-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/build/m2-buildrepo
        key: packages-m2-ios-arm64-sync-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save iOS arm64 packages
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.ios-arm64-cache.outputs.cache-hit == 'true'
      with:
        name: packages-ios-arm64-${{ steps.find-library-version.outputs.label }}
        path: ./packages/build/m2-buildrepo/**/*
        retention-days: 1

    - name: Delete downloaded iOS arm64 cache files
      id: delete-cache-ios-arm64
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.ios-arm64-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/build/m2-buildrepo

    #
    # iOS x64
    #
    - name: Check iOS X64 cache
      id: ios-x64-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/build/m2-buildrepo
        key: packages-m2-ios-x64-sync-${{ steps.packages-cache-key.outputs.sha }}

    - name: Save iOS x64 packages
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.ios-x64-cache.outputs.cache-hit == 'true'
      with:
        name: packages-ios-x64-${{ steps.find-library-version.outputs.label }}
        path: ./packages/build/m2-buildrepo/**/*
        retention-days: 1

    - name: Delete downloaded iOS x64 cache files
      id: delete-cache-ios-x64
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.ios-x64-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/build/m2-buildrepo

    #
    # JNI Windows Lib
    #
    - name: Check JNI Windows lib cache
      id: jni-windows-lib-cache
      uses: cmelchior/cache@main
      with:
        path: ./packages/cinterop/build/realmWindowsBuild
        key: jni-windows-lib-${{ steps.packages-cache-key.outputs.sha }}
        enableCrossOsArchive: true

    - name: Save JNI Windows lib package
      uses: actions/upload-artifact@v3
      if: always() && !cancelled() && steps.jni-windows-lib-cache.outputs.cache-hit == 'true'
      with:
        name: jni-windows-lib-${{ steps.find-library-version.outputs.label }}
        path: ./packages/cinterop/build/realmWindowsBuild/Release/realmc.dll
        retention-days: 1

    - name: Delete downloaded JNI Windows lib cache files
      id: delete-cache-windows-lib
      uses: JesseTG/rm@v1.0.3
      if: always() && !cancelled() && steps.jni-windows-lib-cache.outputs.cache-hit == 'true'
      with:
        path: ./packages/cinterop/build/realmWindowsBuild


Deploy release

name: Deploy release

on:
  workflow_call:
    inputs:
      version-label:
        required: true
        type: string

      packages-sha-label:
        required: true
        type: string

jobs:
  deploy:
    runs-on: macos-12
    name: Deploy release

    steps:
      - name: git checkout
        uses: actions/checkout@v3
        with:
          submodules: "recursive"

      - name: Setup Java 11
        uses: actions/setup-java@v3
        with:
          distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION  }}
          java-version: ${{ vars.VERSION_JAVA }}

      - name: Setup Gradle and task/dependency caching
        uses: gradle/gradle-build-action@v2
        with:
          cache-read-only: false

      - name: Setup cmake
        uses: jwlawson/actions-setup-cmake@v1.13
        with:
          cmake-version: ${{ vars.VERSION_CMAKE }}

      - name: Setup ninja
        uses: cmelchior/setup-ninja@master
        with:
          version: ${{ vars.VERSION_NINJA  }}

      - name: Install ccache
        uses: hendrikmuhs/ccache-action@v1.2.2
        with:
          key: 'jvm-package'
          max-size: '2.0G'

      - name: Install coreutils and s3cmd
        run: brew install coreutils s3cmd

      - name: Prepend ccache executables to the PATH
        run: echo "/usr/lib/ccache:/usr/local/opt/ccache/libexec" >> $GITHUB_PATH

      # See https://github.com/hendrikmuhs/ccache-action/issues/94
      - name: Configure ccache
        run: |
          ccache --set-config="compiler_check=content"
          ccache --show-config
          echo '#!/bin/bash\nccache clang "$@"%"' > /usr/local/bin/ccache-clang
          echo '#!/bin/bash\nccache clang++ "$@"%"' > /usr/local/bin/ccache-clang++

      # TODO This matches 23.2.8568313, but what happens if we define specific ndk version in our build?
      - name: Setup NDK
        uses: nttld/setup-ndk@v1
        with:
          ndk-version: r23c

      # We cannot use artifacts as they cannot be shared between workflows, so use cache instead.
      - name: Setup build cache
        uses: actions/cache@v3
        with:
          path: ./packages/build/m2-buildrepo
          key: packages-m2-jvm-sync-${{ inputs.packages-sha-label }}

      - name: Restore Linux JNI lib
        uses: actions/download-artifact@v3
        with:
          name: jni-linux-lib-${{ inputs.version-label }}
          path: ./packages/cinterop/build/realmLinuxBuild

      - name: Restore Windows JNI lib
        uses: actions/download-artifact@v3
        with:
          name: jni-windows-lib-${{ inputs.version-label }}
          path: ./packages/cinterop/build/realmWindowsBuild/Release

      - name: Restore MacOS JNI lib
        uses: actions/download-artifact@v3
        with:
          name: jni-macos-lib-${{ inputs.version-label }}
          path: ./packages/cinterop/build/realmMacOsBuild

      - name: Restore m2-buildrepo
        uses: actions/download-artifact@v3
        with:
          name: all-packages-${{ inputs.version-label }}
          path: ./packages/build/m2-buildrepo

      - name: Publish release to Maven Central
        run: |
         set +x
         sh ./tools/publish_release.sh "${{ secrets.MAVEN_CENTRAL_USER_DBG }}" "${{ secrets.MAVEN_CENTRAL_KEY_DBG }}" \
         "${{ secrets.AWS_S3_ACCESS_KEY_ID }}" "${{ secrets.AWS_S3_SECRET_ACCESS_KEY }}" \
         "${{ secrets.DOCS_S3_ACCESS_KEY }}" "${{ secrets.DOCS_S3_SECRET_KEY }}" \
         "${{ secrets.SLACK_URL_RELEASE }}" "${{ secrets.SLACK_URL_CI }}" \
         "${{ secrets.GRADLE_PORTAL_KEY }}" "${{ secrets.GRADLE_PORTAL_SECRET }}" \
         '-PsignBuild=true -PsignSecretRingFileKotlin="${{ secrets.GPG_SIGNING_KEY_BASE_64_DBG }}" -PsignPasswordKotlin=${{ secrets.GPG_PASS_PHRASE_DBG }} -Prealm.kotlin.copyNativeJvmLibs=linux,windows'


Deploy SNAPSHOT release

name: Deploy SNAPSHOT release

on:
  workflow_call:
    inputs:
      version-label:
        required: true
        type: string

jobs:
  deploy:
    runs-on: ubuntu-latest
    name: Deploy SNAPSHOT

    steps:
      - name: Remove unnecessary files
        run: |
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf "$AGENT_TOOLSDIRECTORY"

      - name: git checkout
        uses: actions/checkout@v3
        with:
          submodules: "recursive"

      - name: Setup Java 11
        uses: actions/setup-java@v3
        with:
          distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION  }}
          java-version: ${{ vars.VERSION_JAVA }}

      - name: Install Kotlin Commandline Tools
        uses: fwilhe2/setup-kotlin@0.2.0
        with:
          version: ${{ vars.VERSION_KOTLIN_COMMANDLINE_TOOLS }}

      - name: Restore m2-buildrepo
        uses: actions/download-artifact@v3
        with:
          name: all-packages-${{ inputs.version-label }}
          path: ./packages/build/m2-buildrepo

      - name: Publish SNAPSHOT to Maven Central
        # env:
        #   GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY_BASE_64 }}
        #   GPG_PASS_PHRASE: ${{ secrets.GPG_PASS_PHRASE }}
        #   MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }}
        #   MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
        working-directory: tools
        run: |
          export GPG_TTY=$(tty)
          kotlin ./publish_snapshots.main.kts "../" "${{ inputs.version-label }}" "${{ secrets.GPG_SIGNING_KEY_BASE_64 }}" "${{ secrets.GPG_PASS_PHRASE }}" "${{ secrets.MAVEN_CENTRAL_USER }}" "${{ secrets.MAVEN_CENTRAL_PASSWORD }}"


Gradle Project Integration Tests

name: Gradle Project Integration Tests

on:
  workflow_call:
    inputs:
      version-label:
        required: true
        type: string

env:
  REALM_DISABLE_ANALYTICS: true
  REALM_PRINT_ANALYTICS: true
  REALM_FAIL_ON_ANALYTICS_ERRORS: true

jobs:

  # TODO: The Monkey seems to crash the app all the time, but with failures that are not coming from the app. Figure out why.
  # android-sample-app:
  #   runs-on: macos-12
  #   steps:
  #     - name: Checkout code
  #       uses: actions/checkout@v3

  #     - name: Setup Java 11
  #       uses: actions/setup-java@v3
  #       with:
  #         distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION  }}
  #         java-version: 11

  #     - name: Setup Gradle and task/dependency caching
  #       uses: gradle/gradle-build-action@v2
  #       with:
  #         cache-read-only: false

  #     - name: Restore m2-buildrepo
  #       uses: actions/download-artifact@v3
  #       with:
  #         name: all-packages-${{ needs.check-cache.outputs.version-label }}
  #         path: ./packages/build/m2-buildrepo

  #     # TODO Can we read api level from Config.kt
  #     - name: Run Monkey on Android Sample
  #       env:
  #         SSH_AUTH_SOCK: /tmp/ssh_agent.sock
  #       uses: reactivecircus/android-emulator-runner@v2
  #       with:
  #         api-level: 33
  #         target: google_apis # default is not available on 33 yet.
  #         arch: x86_64
  #         profile: Nexus 6
  #         disk-size: 4096M
  #         ram-size: 2048M
  #         heap-size: 1024M
  #         script: |
  #               cd examples/kmm-sample && ./gradlew installRelease
  #               $ANDROID_SDK_ROOT/platform-tools/adb shell monkey --throttle 50 --pct-syskeys 0 -p  io.realm.example.kmmsample.androidApp -v 500 --kill-process-after-error

  android-min-versions-compatibility:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Java 11
        uses: actions/setup-java@v3
        with:
          distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION }}
          java-version: ${{ vars.VERSION_JAVA }}

      - name: Setup Gradle and task/dependency caching
        uses: gradle/gradle-build-action@v2
        with:
          cache-read-only: false

      - name: Restore m2-buildrepo
        uses: actions/download-artifact@v3
        with:
          name: all-packages-${{ inputs.version-label }}
          path: ./packages/build/m2-buildrepo

      # TODO Can we read api level from Config.kt
      - name: Build Android on minimum versions
        working-directory: examples/min-android-sample
        run: |
          java --version
          ./gradlew assembleDebug jvmJar

  realm-java-compatibiliy:
    runs-on: macos-12
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Java 11
        uses: actions/setup-java@v3
        with:
          distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION }}
          java-version: ${{ vars.VERSION_JAVA }}

      - name: Setup Gradle and task/dependency caching
        uses: gradle/gradle-build-action@v2
        with:
          cache-read-only: false

      - name: Restore m2-buildrepo
        uses: actions/download-artifact@v3
        with:
          name: all-packages-${{ inputs.version-label }}
          path: ./packages/build/m2-buildrepo

      # - name: AVD cache
      #   uses: actions/cache@v3
      #   id: avd-cache
      #   with:
      #     path: |
      #       ~/.android/avd/*
      #       ~/.android/adb*
      #     key: android-emulator-avd-33

      # - name: create AVD and generate snapshot for caching
      #   if: steps.avd-cache.outputs.cache-hit != 'true'
      #   uses: reactivecircus/android-emulator-runner@v2
      #   with:
      #     api-level: 33
      #     target: default
      #     # target: aosp_atd
      #     arch: x86_64
      #     disk-size: 4096M
      #     ram-size: 2048M
      #     heap-size: 1024M
      #     force-avd-creation: false
      #     emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
      #     disable-animations: true
      #     channel: canary
      #     script: echo "Generated AVD snapshot for caching."

      # TODO Can we read api level from Config.kt
      - name: Run Gradle Plugin Test project
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock
        uses: reactivecircus/android-emulator-runner@v2
        with:
          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          force-avd-creation: false
          api-level: ${{ vars.VERSION_ANDROID_EMULATOR_API_LEVEL }}
          target: default
          # target: aosp_atd
          arch: x86_64
          # profile: Nexus 6
          disk-size: 4096M
          ram-size: 2048M
          heap-size: 1024M
          channel: canary
          script: cd examples/realm-java-compatibility && ./gradlew connectedAndroidTest -PincludeSdkModules=false --info

      # TODO: This fails with `Error: Cannot read property 'trim' of undefined`. Possible a bug in the action.
      #  For now, just disable this as there is only a single unit test anyway.
      # - name: Publish Unit Test Results
      #   uses: dorny/test-reporter@v1
      #   if: always() || failure()
      #   with:
      #     name: Results - Realm Java Compatibility
      #     path: ./examples/realm-java-compatibility/app/build/**/TEST-*.xml
      #     reporter: java-junit
      #     list-suites: failed
      #     list-tests: failed
      #     fail-on-error: true

  build-benchmarks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Java 11
        uses: actions/setup-java@v3
        with:
          distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION }}
          java-version: ${{ vars.VERSION_JAVA }}

      - name: Setup Gradle and task/dependency caching
        uses: gradle/gradle-build-action@v2
        with:
          cache-read-only: false

      - name: Restore m2-buildrepo
        uses: actions/download-artifact@v3
        with:
          name: all-packages-${{ inputs.version-label }}
          path: ./packages/build/m2-buildrepo

      - name: Build benchmarks
        working-directory: benchmarks
        run: ./gradlew assemble

  gradle-plugin-integration:
    strategy:
      matrix:
        type: [current, gradle72, gradle75]
        include:
          - type: current
            path: integration-tests/gradle/current
            arguments: integrationTest
          - type: gradle72
            path: integration-tests/gradle/gradle72-test
            arguments: integrationTest
          - type: gradle75
            path: integration-tests/gradle/gradle75-test
            arguments: integrationTest
    runs-on: macos-12
    steps:
      - uses: actions/checkout@v3

      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Java 11
        uses: actions/setup-java@v3
        with:
          distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION }}
          java-version: ${{ vars.VERSION_JAVA }}

      - name: Setup Gradle and task/dependency caching
        uses: gradle/gradle-build-action@v2
        with:
          cache-read-only: false

      - name: Restore m2-buildrepo
        uses: actions/download-artifact@v3
        with:
          name: all-packages-${{ inputs.version-label }}
          path: ./packages/build/m2-buildrepo

      # - name: AVD cache
      #   uses: actions/cache@v3
      #   id: avd-cache
      #   with:
      #     path: |
      #       ~/.android/avd/*
      #       ~/.android/adb*
      #     key: android-emulator-avd-33

      # - name: create AVD and generate snapshot for caching
      #   if: steps.avd-cache.outputs.cache-hit != 'true'
      #   uses: reactivecircus/android-emulator-runner@v2
      #   with:
      #     api-level: 33
      #     target: default
      #     # target: aosp_atd
      #     arch: x86_64
      #     disk-size: 4096M
      #     ram-size: 2048M
      #     heap-size: 1024M
      #     force-avd-creation: false
      #     emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
      #     disable-animations: true
      #     channel: canary
      #     script: echo "Generated AVD snapshot for caching."

      # TODO Can we read api level from Config.kt
      - name: Run Gradle Plugin Test project
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock
        uses: reactivecircus/android-emulator-runner@v2
        with:
          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          force-avd-creation: false
          api-level: ${{ vars.VERSION_ANDROID_EMULATOR_API_LEVEL }}
          target: default
          # target: aosp_atd
          arch: x86_64
          # profile: Nexus 6
          disk-size: 4096M
          ram-size: 2048M
          heap-size: 1024M
          channel: canary
          script: cd ${{ matrix.path }} && ./gradlew ${{ matrix.arguments }} --info

  gradle-plugin-integration-java-17:
    strategy:
      matrix:
        type: [gradle8, gradle85]
        include:
          - type: gradle8
            path: integration-tests/gradle/gradle8-test
            arguments: integrationTest
          - type: gradle85
            path: integration-tests/gradle/gradle85-test
            arguments: integrationTest
    runs-on: macos-12
    steps:
      - uses: actions/checkout@v3

      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Java 17
        uses: actions/setup-java@v3
        with:
          distribution: ${{ vars.VERSION_JAVA_DISTRIBUTION }}
          java-version: 17

      - name: Setup Gradle and task/dependency caching
        uses: gradle/gradle-build-action@v2
        with:
          cache-read-only: false

      - name: Restore m2-buildrepo
        uses: actions/download-artifact@v3
        with:
          name: all-packages-${{ inputs.version-label }}
          path: ./packages/build/m2-buildrepo

      # - name: AVD cache
      #   uses: actions/cache@v3
      #   id: avd-cache
      #   with:
      #     path: |
      #       ~/.android/avd/*
      #       ~/.android/adb*
      #     key: android-emulator-avd-33

      # - name: create AVD and generate snapshot for caching
      #   if: steps.avd-cache.outputs.cache-hit != 'true'
      #   uses: reactivecircus/android-emulator-runner@v2
      #   with:
      #     api-level: 33
      #     target: default
      #     # target: aosp_atd
      #     arch: x86_64
      #     disk-size: 4096M
      #     ram-size: 2048M
      #     heap-size: 1024M
      #     force-avd-creation: false
      #     emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
      #     disable-animations: true
      #     channel: canary
      #     script: echo "Generated AVD snapshot for caching."

      # TODO Can we read api level from Config.kt
      - name: Run Gradle Plugin Test project
        env:
          SSH_AUTH_SOCK: /tmp/ssh_agent.sock
        uses: reactivecircus/android-emulator-runner@v2
        with:
          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          force-avd-creation: false
          api-level: ${{ vars.VERSION_ANDROID_EMULATOR_API_LEVEL }}
          target: default
          # target: aosp_atd
          arch: x86_64
          # profile: Nexus 6
          disk-size: 4096M
          ram-size: 2048M
          heap-size: 1024M
          channel: canary
          script: cd ${{ matrix.path }} && ./gradlew ${{ matrix.arguments }} --info


Static Analysis

name: Static Analysis

on:
  workflow_call:

jobs:
  ktlint:
    runs-on: ubuntu-latest
    steps:

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

      - name: Setup Gradle and task/dependency caching
        uses: gradle/gradle-build-action@v2
        with:
          cache-read-only: false # TODO How to configure caching here?

      - name: Setup cmake
        uses: jwlawson/actions-setup-cmake@v1.13
        with:
          cmake-version: ${{ vars.VERSION_CMAKE }}

      - name: Build Gradle Plugin
        working-directory: packages
        run: ./gradlew :gradle-plugin:publishAllPublicationsToTestRepository --info --stacktrace

      - name: Run Ktlint
        run: ./gradlew ktlintCheck

      - name: Stash Ktlint results
        if: always()
        run: |
          rm -rf /tmp/ktlint
          rm -rf /tmp/detekt
          mkdir /tmp/ktlint
          mkdir /tmp/detekt
          rsync -a --delete --ignore-errors examples/kmm-sample/shared/build/reports/ktlint/ /tmp/ktlint/example/ || true
          rsync -a --delete --ignore-errors packages/cinterop/build/reports/ktlint/ /tmp/ktlint/cinterop/ || true
          rsync -a --delete --ignore-errors packages/library-base/build/reports/ktlint/ /tmp/ktlint/library-base/ || true
          rsync -a --delete --ignore-errors packages/library-sync/build/reports/ktlint/ /tmp/ktlint/library-sync/ || true
          rsync -a --delete --ignore-errors packages/plugin-compiler/build/reports/ktlint/ /tmp/ktlint/plugin-compiler/ || true
          rsync -a --delete --ignore-errors packages/gradle-plugin/build/reports/ktlint/ /tmp/ktlint/plugin-gradle/ || true
          rsync -a --delete --ignore-errors benchmarks/build/reports/ktlint/ /tmp/ktlint/benchmarks/ || true

      - name: Publish Ktlint results
        uses: cmelchior/checkstyle-github-action@master
        if: always()
        with:
          name: Ktlint Results
          title: Ktlint Analyzer report
          path: '/tmp/ktlint/**/*.xml'

  detekt:
    runs-on: ubuntu-latest
    steps:

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

      - name: Setup Gradle and task/dependency caching
        uses: gradle/gradle-build-action@v2
        with:
          cache-read-only: false # TODO How to configure caching here?

      - name: Setup cmake
        uses: jwlawson/actions-setup-cmake@v1.13
        with:
          cmake-version: ${{ vars.VERSION_CMAKE }}

      - name: Build Gradle Plugin
        working-directory: packages
        run: ./gradlew :gradle-plugin:publishAllPublicationsToTestRepository --info --stacktrace

      - name: Run Detekt
        run: ./gradlew detekt

      - name: Stash Detekt results
        if: always()
        run: |
          rm -rf /tmp/detekt
          mkdir /tmp/detekt
          rsync -a --delete --ignore-errors examples/kmm-sample/shared/build/reports/detekt/ /tmp/detekt/example/ || true
          rsync -a --delete --ignore-errors packages/cinterop/build/reports/detekt/ /tmp/detekt/cinterop/ || true
          rsync -a --delete --ignore-errors packages/library-base/build/reports/detekt/ /tmp/detekt/library-base/ || true
          rsync -a --delete --ignore-errors packages/library-sync/build/reports/detekt/ /tmp/detekt/library-sync/ || true
          rsync -a --delete --ignore-errors packages/plugin-compiler/build/reports/detekt/ /tmp/detekt/plugin-compiler/ || true
          rsync -a --delete --ignore-errors packages/gradle-plugin/build/reports/detekt/ /tmp/detekt/plugin-gradle/ || true
          rsync -a --delete --ignore-errors benchmarks/build/reports/detekt/ /tmp/detekt/benchmarks/ || true

      - name: Publish Detekt results
        uses: cmelchior/checkstyle-github-action@master
        if: always()
        with:
          name: Detekt Results
          title: Detekt Analyzer report
          path: '/tmp/detekt/**/*.xml'


Issue labeler (policy)

# NOTE: This is a common file that is overwritten by realm/ci-actions sync service
# and should only be modified in that repository.

# See configuration in .github/advanced-issue-labeler.yml

name: Issue labeler (policy)
on:
  issues:
    types: [ opened ]

jobs:
  label-issues-policy:
    runs-on: ubuntu-latest
    permissions:
      issues: write

    strategy:
      matrix:
        template: [ bug.yml, feature.yml ]

    steps:
      - uses: actions/checkout@v4

      - name: Parse issue form
        uses: stefanbuck/github-issue-parser@c1a559d78bfb8dd05216dab9ffd2b91082ff5324  # v3.0.1
        id: issue-parser
        with:
          template-path: .github/ISSUE_TEMPLATE/${{ matrix.template }}

      - name: Set labels based on policy
        uses: redhat-plumbers-in-action/advanced-issue-labeler@6ee6fddfd744ee26b977e6a0436916f256896971  # v2.0.3
        with:
          issue-form: ${{ steps.issue-parser.outputs.jsonString }}
          template: ${{ matrix.template }}
          token: ${{ secrets.GITHUB_TOKEN }}


Lock Threads

name: 'Lock Threads'

on:
  schedule:
    - cron: '0 * * * *'
  workflow_dispatch:

permissions:
  issues: write
  pull-requests: write
  discussions: write

concurrency:
  group: lock-threads

jobs:
  action:
    runs-on: ubuntu-latest
    steps:
      - uses: dessant/lock-threads@v5
        with:
          issue-inactive-days: 30
          pr-inactive-days: 30
          log-output: true


No Response

# NOTE: This is a common file that is overwritten by realm/ci-actions sync service
# and should only be modified in that repository.

name: No Response

# Both `issue_comment` and `scheduled` event types are required for this Action
# to work properly.
on:
  issue_comment:
    types: [created]
  schedule:
    # Schedule at 00:00 every day
    - cron: '0 0 * * *'

jobs:
  noResponse:
    runs-on: ubuntu-latest
    steps:
      - uses: lee-dohm/no-response@v0.5.0
        with:
          token: ${{ github.token }}
          responseRequiredLabel: More-information-needed