diff --git a/.github/workflows/build-binaries.yml b/.github/workflows/build-binaries.yml index e2f04a9489..6965128a33 100644 --- a/.github/workflows/build-binaries.yml +++ b/.github/workflows/build-binaries.yml @@ -17,14 +17,13 @@ jobs: strategy: matrix: target: [macosx, iphoneos, iphonesimulator, appletvos, appletvsimulator, watchos, watchsimulator, maccatalyst, xros, xrsimulator] - xcode: ["15.3"] + env: + DEVELOPER_DIR: /Applications/Xcode_15.3.app/Contents/Developer steps: - uses: actions/checkout@v4 - - - name: Switch to Xcode ${{ matrix.xcode }} - uses: maxim-lobanov/setup-xcode@v1.6.0 - with: - xcode-version: ${{ matrix.xcode }} + - name: Download visionOS + if: matrix.target == 'xros' || matrix.target == 'xrsimulator' + run: xcodebuild -downloadPlatform visionOS - name: Get Core Version id: get-core-version @@ -44,6 +43,11 @@ jobs: fetch-depth: 0 fetch-tags: true + # CMake 3.30 introduced a check which tries to validate that the compiler + # supports the requested architextures but it doesn't work. + - name: Patch CMake + run: sed -i '' 's/CMAKE_HOST_APPLE AND CMAKE_SYSTEM_NAME STREQUAL "Darwin"/CMAKE_HOST_APPLE AND CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT CMAKE_GENERATOR STREQUAL "Xcode"/' /opt/homebrew/Cellar/cmake/*/share/cmake/Modules/CMakeDetermineCompilerABI.cmake + - name: Checkout Core@${{ steps.get-core-version.outputs.version }} run: git checkout ${{ steps.get-core-version.outputs.version }} --recurse-submodules -f working-directory: core diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml new file mode 100644 index 0000000000..7d24c1b379 --- /dev/null +++ b/.github/workflows/build-pr.yml @@ -0,0 +1,469 @@ + +# This is a generated file produced by scripts/pr-ci-matrix.rb. +name: Pull request build and test +on: + pull_request: + paths-ignore: + - '**.md' + workflow_dispatch: + +jobs: + docs: + runs-on: macos-14 + name: Test docs + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - run: sudo xcode-select -switch /Applications/Xcode_16.app + - run: bundle exec sh build.sh verify-docs + swiftlint: + runs-on: macos-14 + name: Check swiftlint + steps: + - uses: actions/checkout@v4 + - run: sudo xcode-select -switch /Applications/Xcode_16.app + - run: brew install swiftlint + - run: sh build.sh verify-swiftlint + + osx-15_3: + runs-on: macos-14 + name: Test osx on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx + + osx-15_4: + runs-on: macos-14 + name: Test osx on Xcode 15.4 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.4.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx + + osx-16: + runs-on: macos-15 + name: Test osx on Xcode 16 + env: + DEVELOPER_DIR: '/Applications/Xcode_16.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx + + osx-16_1_Release_Candidate: + runs-on: macos-15 + name: Test osx on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx + + osx-encryption-16_1_Release_Candidate: + runs-on: macos-15 + name: Test osx-encryption on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx-encryption + + swiftpm-15_3: + runs-on: macos-14 + name: Test swiftpm on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr swiftpm + + swiftpm-16_1_Release_Candidate: + runs-on: macos-15 + name: Test swiftpm on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr swiftpm + + swiftpm-debug-15_3: + runs-on: macos-14 + name: Test swiftpm-debug on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr swiftpm-debug + + swiftpm-debug-15_4: + runs-on: macos-14 + name: Test swiftpm-debug on Xcode 15.4 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.4.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr swiftpm-debug + + swiftpm-debug-16: + runs-on: macos-15 + name: Test swiftpm-debug on Xcode 16 + env: + DEVELOPER_DIR: '/Applications/Xcode_16.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr swiftpm-debug + + swiftpm-debug-16_1_Release_Candidate: + runs-on: macos-15 + name: Test swiftpm-debug on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr swiftpm-debug + + swiftpm-address-16_1_Release_Candidate: + runs-on: macos-15 + name: Test swiftpm-address on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr swiftpm-address + + swiftpm-thread-16_1_Release_Candidate: + runs-on: macos-15 + name: Test swiftpm-thread on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr swiftpm-thread + + ios-static-15_3: + runs-on: macos-14 + name: Test ios-static on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr ios-static + + ios-static-16_1_Release_Candidate: + runs-on: macos-15 + name: Test ios-static on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr ios-static + + ios-15_3: + runs-on: macos-14 + name: Test ios on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr ios + + ios-16_1_Release_Candidate: + runs-on: macos-15 + name: Test ios on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr ios + + watchos-15_3: + runs-on: macos-14 + name: Test watchos on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr watchos + + watchos-16_1_Release_Candidate: + runs-on: macos-15 + name: Test watchos on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr watchos + + tvos-15_3: + runs-on: macos-14 + name: Test tvos on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr tvos + + tvos-16_1_Release_Candidate: + runs-on: macos-15 + name: Test tvos on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr tvos + + visionos-15_3: + runs-on: macos-14 + name: Test visionos on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr visionos + + visionos-16_1_Release_Candidate: + runs-on: macos-15 + name: Test visionos on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr visionos + + osx-swift-15_3: + runs-on: macos-14 + name: Test osx-swift on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx-swift + + osx-swift-15_4: + runs-on: macos-14 + name: Test osx-swift on Xcode 15.4 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.4.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx-swift + + osx-swift-16: + runs-on: macos-15 + name: Test osx-swift on Xcode 16 + env: + DEVELOPER_DIR: '/Applications/Xcode_16.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx-swift + + osx-swift-16_1_Release_Candidate: + runs-on: macos-15 + name: Test osx-swift on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx-swift + + ios-swift-15_3: + runs-on: macos-14 + name: Test ios-swift on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr ios-swift + + ios-swift-16_1_Release_Candidate: + runs-on: macos-15 + name: Test ios-swift on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr ios-swift + + tvos-swift-15_3: + runs-on: macos-14 + name: Test tvos-swift on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr tvos-swift + + tvos-swift-16_1_Release_Candidate: + runs-on: macos-15 + name: Test tvos-swift on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr tvos-swift + + osx-swift-evolution-16_1_Release_Candidate: + runs-on: macos-15 + name: Test osx-swift-evolution on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr osx-swift-evolution + + ios-swift-evolution-16_1_Release_Candidate: + runs-on: macos-15 + name: Test ios-swift-evolution on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr ios-swift-evolution + + tvos-swift-evolution-16_1_Release_Candidate: + runs-on: macos-15 + name: Test tvos-swift-evolution on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr tvos-swift-evolution + + catalyst-15_3: + runs-on: macos-14 + name: Test catalyst on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr catalyst + + catalyst-16_1_Release_Candidate: + runs-on: macos-15 + name: Test catalyst on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr catalyst + + catalyst-swift-15_3: + runs-on: macos-14 + name: Test catalyst-swift on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr catalyst-swift + + catalyst-swift-16_1_Release_Candidate: + runs-on: macos-15 + name: Test catalyst-swift on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr catalyst-swift + + xcframework-16_1_Release_Candidate: + runs-on: macos-15 + name: Test xcframework on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr xcframework + + cocoapods-osx-15_3: + runs-on: macos-14 + name: Test cocoapods-osx on Xcode 15.3 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.3.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-osx + + cocoapods-osx-15_4: + runs-on: macos-14 + name: Test cocoapods-osx on Xcode 15.4 + env: + DEVELOPER_DIR: '/Applications/Xcode_15.4.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-osx + + cocoapods-osx-16: + runs-on: macos-15 + name: Test cocoapods-osx on Xcode 16 + env: + DEVELOPER_DIR: '/Applications/Xcode_16.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-osx + + cocoapods-osx-16_1_Release_Candidate: + runs-on: macos-15 + name: Test cocoapods-osx on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-osx + + cocoapods-ios-static-16_1_Release_Candidate: + runs-on: macos-15 + name: Test cocoapods-ios-static on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-ios-static + + cocoapods-ios-16_1_Release_Candidate: + runs-on: macos-15 + name: Test cocoapods-ios on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-ios + + cocoapods-watchos-16_1_Release_Candidate: + runs-on: macos-15 + name: Test cocoapods-watchos on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-watchos + + cocoapods-tvos-16_1_Release_Candidate: + runs-on: macos-15 + name: Test cocoapods-tvos on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-tvos + + cocoapods-catalyst-16_1_Release_Candidate: + runs-on: macos-15 + name: Test cocoapods-catalyst on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr cocoapods-catalyst + + ios-swiftui-16_1_Release_Candidate: + runs-on: macos-15 + name: Test ios-swiftui on Xcode 16.1_Release_Candidate + env: + DEVELOPER_DIR: '/Applications/Xcode_16.1_Release_Candidate.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr ios-swiftui diff --git a/.github/workflows/master-push.yml b/.github/workflows/master-push.yml index 9372e9bc7a..25e6bae29d 100644 --- a/.github/workflows/master-push.yml +++ b/.github/workflows/master-push.yml @@ -6,10 +6,10 @@ on: - "master" - "release/**" env: - XCODE_VERSION: "['15.3', '15.4', '16_beta_6', '16.1_beta']" + XCODE_VERSION: "['15.3', '15.4', '16', '16.1_Release_Candidate']" PLATFORM: "['ios', 'osx', 'watchos', 'tvos', 'catalyst', 'visionos']" - DOC_VERSION: '15.4' - RELEASE_VERSION: '15.4' + RELEASE_VERSION: '16' + DEVELOPER_DIR: /Applications/Xcode_16.app/Contents/Developer jobs: prepare: runs-on: ubuntu-latest @@ -30,7 +30,7 @@ jobs: version="$(sed -n 's/^VERSION=\(.*\)$/\1/p' "${GITHUB_WORKSPACE}/dependencies.list")" echo "VERSION=$version" >> $GITHUB_OUTPUT build-docs: - runs-on: macos-14 + runs-on: macos-15 name: Package docs needs: prepare steps: @@ -38,8 +38,6 @@ jobs: - uses: ruby/setup-ruby@v1 with: bundler-cache: true - - name: Select Xcode Version - run: sudo xcode-select -switch /Applications/Xcode_${{ env.DOC_VERSION }}.app - name: Prepare docs for packaging run: bundle exec sh -x build.sh release-package-docs - name: Upload docs to artifacts library @@ -48,7 +46,7 @@ jobs: name: realm-docs path: docs/realm-docs.zip build-examples: - runs-on: macos-14 + runs-on: macos-15 name: Package examples needs: prepare steps: @@ -61,15 +59,27 @@ jobs: name: realm-examples path: realm-examples.zip build-product: # Creates framework for each platform, xcode version, target and configuration - runs-on: macos-14 name: Package framework needs: prepare strategy: - max-parallel: 20 # Blocks of 20, therefore if any of the build fails, we don't get a lot of XCode Clouds builds hanging, which are expensive. + max-parallel: 20 matrix: platform: ${{ fromJSON(needs.prepare.outputs.PLATFORM_MATRIX) }} xcode-version: ${{ fromJSON(needs.prepare.outputs.XCODE_VERSIONS_MATRIX) }} configuration: [swift, static] + include: + - xcode-version: 15.3 + xcode-version-tag: 15.3 + os: macos-14 + - xcode-version: 15.4 + xcode-version-tag: 15.4 + os: macos-14 + - xcode-version: 16 + xcode-version-tag: '16.0' + os: macos-15 + - xcode-version: 16.1_Release_Candidate + xcode-version-tag: 16.1 + os: macos-15 exclude: - platform: osx configuration: static @@ -81,79 +91,39 @@ jobs: configuration: static - platform: catalyst configuration: static - - platform: visionos - xcode-version: 15.1 + runs-on: ${{ matrix.os }} + env: + DEVELOPER_DIR: /Applications/Xcode_${{matrix.xcode-version}}.app/Contents/Developer steps: - uses: actions/checkout@v4 - - name: Build ${{ matrix.platform }} with Xcode ${{ matrix.xcode-version }} - run: DEVELOPER_DIR=/Applications/Xcode_${{ matrix.xcode-version }}.app/Contents/Developer sh build.sh ${{ matrix.platform }}-${{matrix.configuration}} - - run: rm -r build/DerivedData + - name: Download visionOS + if: matrix.platform == 'visionos' && matrix.os == 'macos-14' + run: xcodebuild -downloadPlatform visionOS + - run: sh build.sh ${{matrix.platform}}-${{matrix.configuration}} + - run: tar cf build.tar build/*/${{matrix.platform}} - name: Upload framework uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.platform }}-${{ matrix.xcode-version }}-${{ matrix.configuration }} - path: build + name: build-${{matrix.platform}}-${{matrix.xcode-version-tag}}-${{matrix.configuration}} + path: build.tar compression-level: 1 - package-xcframework-platform: # Creates xcframework for each platform and xcode version - runs-on: macos-14 - name: Package xcframework for platform - needs: [build-product, prepare] - strategy: - matrix: - platform: ${{ fromJSON(needs.prepare.outputs.PLATFORM_MATRIX) }} - xcode-version: ${{ fromJSON(needs.prepare.outputs.XCODE_VERSIONS_MATRIX) }} - exclude: - - platform: visionos - xcode-version: 15.1 - steps: - - uses: actions/checkout@v4 - - name: Select Xcode Version - run: sudo xcode-select -switch /Applications/Xcode_${{ env.RELEASE_VERSION }}.app - - name: Install the Apple certificate and provisioning profile - env: - DEVELOPMENT_CERTIFICATE_BASE64: ${{ secrets.DEVELOPMENT_CERTIFICATE_BASE64 }} - P12_PASSWORD: ${{ secrets.P12_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - run: | - sh -x build.sh install-apple-certificates - - name: Restore frameworks - uses: actions/download-artifact@v4 - with: - pattern: build-${{ matrix.platform }}*-${{ matrix.xcode-version }}-* - - name: Create xcframework - env: - SIGNING_IDENTITY: ${{ secrets.SIGNING_IDENTITY }} - run: | - sh -x build.sh release-create-xcframework-${{ matrix.xcode-version }} ${{ matrix.platform }} - - name: Upload xcframework - uses: actions/upload-artifact@v4 - with: - name: realm-${{ matrix.platform }}-${{ matrix.xcode-version }} - path: realm-${{ matrix.platform }}-${{ matrix.xcode-version }}.zip - package-release: # Creates xcframework for each platform and xcode version - runs-on: macos-14 + package-release: + runs-on: macos-15 name: Package release file - needs: [package-xcframework-platform, prepare] + needs: [build-product, prepare] steps: - uses: actions/checkout@v4 - - name: Select Xcode Version - run: sudo xcode-select -switch /Applications/Xcode_${{ env.RELEASE_VERSION }}.app + - uses: actions/download-artifact@v4 - name: Install the Apple certificate and provisioning profile env: DEVELOPMENT_CERTIFICATE_BASE64: ${{ secrets.DEVELOPMENT_CERTIFICATE_BASE64 }} P12_PASSWORD: ${{ secrets.P12_PASSWORD }} KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - run: | - sh -x build.sh install-apple-certificates - - name: Restore packages xcframeworks - uses: actions/download-artifact@v4 - with: - pattern: realm-* + run: sh build.sh install-apple-certificates - name: Create release env: SIGNING_IDENTITY: ${{ secrets.SIGNING_IDENTITY }} - run: | - sh -x build.sh release-package + run: sh -x build.sh release-package - name: Upload release artifactss uses: actions/upload-artifact@v4 with: @@ -162,52 +132,48 @@ jobs: - name: Upload release for testing uses: actions/upload-artifact@v4 with: - name: realm-swift-${{ needs.prepare.outputs.VERSION }} + name: test-release-package path: pkg/realm-swift-${{ needs.prepare.outputs.VERSION }}.zip test-package-examples: - runs-on: macos-14 + runs-on: macos-15 name: Test examples needs: [package-release, prepare] steps: - uses: actions/checkout@v4 - - name: Select Xcode Version - run: sudo xcode-select -switch /Applications/Xcode_${{ env.RELEASE_VERSION }}.app - name: Restore release uses: actions/download-artifact@v4 with: - name: realm-swift-${{ needs.prepare.outputs.VERSION }} + name: test-release-package - name: Test examples run: sh -x build.sh release-test-examples test-ios-static: - runs-on: macos-14 + runs-on: macos-15 name: Run tests on iOS with configuration Static needs: package-release steps: - uses: actions/checkout@v4 - - name: Select Xcode Version - run: sudo xcode-select -switch /Applications/Xcode_${{ env.RELEASE_VERSION }}.app - name: Test ios static run: sh -x build.sh test-ios-static test-osx-static: - runs-on: macos-14 + runs-on: macos-15 name: Run tests on macOS needs: package-release steps: - uses: actions/checkout@v4 - - name: Select Xcode Version - run: sudo xcode-select -switch /Applications/Xcode_${{ env.RELEASE_VERSION }}.app - name: Test osx static run: | export REALM_DISABLE_METADATA_ENCRYPTION=1 sh -x build.sh test-osx test-installation: - runs-on: macos-14 + runs-on: macos-15 name: Run installation test needs: [package-release, prepare] + env: + REALM_TEST_BRANCH: "${{github.ref_name}}" strategy: matrix: platform: ${{ fromJSON(needs.prepare.outputs.PLATFORM_MATRIX) }} - installation: [cocoapods, spm, carthage, xcframework] + installation: [cocoapods, spm, carthage] linkage: [dynamic, static] exclude: - platform: visionos @@ -215,8 +181,6 @@ jobs: installation: carthage - installation: carthage linkage: static - - installation: xcframework - linkage: static include: - platform: ios installation: xcframework @@ -226,50 +190,51 @@ jobs: - uses: ruby/setup-ruby@v1 with: bundler-cache: true - - name: Select Xcode Version - run: sudo xcode-select -switch /Applications/Xcode_${{ env.RELEASE_VERSION }}.app + - name: Download visionOS + if: matrix.platform == 'visionos' && matrix.os == 'macos-14' + run: xcodebuild -downloadPlatform visionOS - name: Restore release uses: actions/download-artifact@v4 if: ${{ matrix.installation == 'xcframework' }} with: - name: realm-${{ matrix.platform }}-${{ env.RELEASE_VERSION }} - - name: Unzip package release - if: ${{ matrix.installation == 'xcframework' }} - run: | - mkdir -p build - unzip realm-${{ matrix.platform }}-${{ env.RELEASE_VERSION }}.zip -d build + name: test-release-package - name: Run installation test run: | - echo "REALM_TEST_BRANCH=${{ github.ref_name }}" >> $GITHUB_OUTPUT + find . -name '*.zip' -depth 1 -exec mv {} examples/installation \; cd examples/installation bundle exec ./build.rb ${{ matrix.platform }} ${{ matrix.installation }} ${{ matrix.linkage }} test-installation-xcframework: - runs-on: macos-14 name: Run installation test for xcframework needs: [package-release, prepare] - env: - PLATFORM: 'osx' strategy: matrix: xcode-version: ${{ fromJSON(needs.prepare.outputs.XCODE_VERSIONS_MATRIX) }} + include: + - xcode-version: 15.3 + os: macos-14 + - xcode-version: 15.4 + os: macos-14 + - xcode-version: 16 + os: macos-15 + - xcode-version: 16.1_Release_Candidate + os: macos-15 + env: + PLATFORM: 'osx' + DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode-version }}.app/Contents/Developer + REALM_TEST_BRANCH: "${{github.ref_name}}" + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: bundler-cache: true - - name: Select Xcode Version - run: sudo xcode-select -switch /Applications/Xcode_${{ matrix.xcode-version }}.app - name: Restore release uses: actions/download-artifact@v4 with: - name: realm-${{ env.PLATFORM }}-${{ matrix.xcode-version }} - - name: Unzip package release - run: | - mkdir -p build - unzip realm-${{ env.PLATFORM }}-${{ matrix.xcode-version }}.zip -d build + name: test-release-package - name: Run installation test run: | - echo "REALM_TEST_BRANCH=${{ github.ref_name }}" >> $GITHUB_OUTPUT + find . -name '*.zip' -depth 1 -exec mv {} examples/installation \; cd examples/installation bundle exec ./build.rb osx xcframework dynamic diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 9ab1a8bb95..a8b6902f63 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -1,8 +1,8 @@ name: Publish release on: workflow_dispatch env: - XCODE_VERSION: "['15.3', '15.4', '16_beta_6', '16.1_beta']" - TEST_XCODE_VERSION: '15.4' + XCODE_VERSION: "['15.3', '15.4', '16', '16.1_beta_3']" + TEST_XCODE_VERSION: '16' jobs: prepare: runs-on: ubuntu-latest @@ -33,7 +33,7 @@ jobs: tag_exists_error: false message: "" publish-docs: - runs-on: macos-latest + runs-on: macos-15 name: Publish docs to S3 Bucket needs: tag-release env: @@ -49,7 +49,7 @@ jobs: - name: Publish docs run: bundle exec sh -x build.sh publish-docs ${{ github.sha }} create-release: - runs-on: macos-latest + runs-on: macos-15 name: Create github release needs: [tag-release, prepare] env: @@ -62,7 +62,7 @@ jobs: - name: Create Github release run: bundle exec ./build.sh publish-github ${{ github.sha }} publish-cocoapods: - runs-on: macos-latest + runs-on: macos-15 name: Publish Cocoapods specs needs: [tag-release, prepare] env: @@ -74,8 +74,22 @@ jobs: bundler-cache: true - name: Publish run: bundle exec ./build.sh publish-cocoapods v${{ needs.prepare.outputs.VERSION }} + update-checker: + runs-on: macos-15 + name: Update to latest version update checker file + needs: tag-release + env: + AWS_ACCESS_KEY_ID: ${{ secrets.UPDATE_CHECKER_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.UPDATE_CHECKER_SECRET_KEY }} + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - run: brew install s3cmd + - run: bundle exec ./build.sh publish-update-checker test-installation: - runs-on: macos-14 + runs-on: macos-15 name: Run installation test for ${{ matrix.platform }}, ${{ matrix.installation }} and ${{ matrix.linkage }} needs: [create-release, prepare, publish-cocoapods] strategy: @@ -119,10 +133,10 @@ jobs: - uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: ${{ env.TEST_XCODE_VERSION }} - - name: Set REALM_TEST_RELEASE - run: echo "REALM_TEST_RELEASE=${{ needs.prepare.outputs.VERSION }}" >> $GITHUB_ENV - name: Run installation test uses: nick-fields/retry@v3 + env: + REALM_TEST_RELEASE: ${{ needs.prepare.outputs.VERSION }} with: command: | cd examples/installation @@ -132,9 +146,9 @@ jobs: retry_wait_seconds: 60 retry_on: error post-slack-release: - runs-on: macos-latest + runs-on: macos-15 name: Publish to release Slack channel - needs: [create-release, prepare, publish-cocoapods, publish-docs] + needs: [create-release, prepare, publish-cocoapods, update-checker, publish-docs] env: WEBHOOK_URL: ${{ secrets.SLACK_RELEASES_WEBHOOK }} steps: @@ -152,7 +166,7 @@ jobs: webhook-url: ${{ env.WEBHOOK_URL }} version: ${{ needs.prepare.outputs.VERSION }} add-empty-changelog: - runs-on: macos-latest + runs-on: macos-15 permissions: contents: write name: Add empty changelog and commits/push it diff --git a/.github/workflows/update-xcode-cloud-workflows.yml b/.github/workflows/update-xcode-cloud-workflows.yml deleted file mode 100644 index c4d5dd66d6..0000000000 --- a/.github/workflows/update-xcode-cloud-workflows.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Update XCode Cloud Workflows -on: workflow_dispatch -jobs: - main: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Get Token - id: token - run: | - token=$(ruby ./scripts/xcode_cloud_helper.rb --issuer-id ${{ secrets.APPLE_STORE_CONNECT_ISSUER_ID }} --key-id ${{ secrets.APPLE_STORE_CONNECT_KEY_ID }} --pk "${{ secrets.APPLE_STORE_CONNECT_API_KEY }}" get-token) - echo "TOKEN=$token" >> $GITHUB_OUTPUT - - name: Run ruby script - run: echo "both" | ./scripts/xcode_cloud_helper.rb -t ${{ steps.token.outputs.TOKEN }} synchronize-workflows - - diff --git a/CHANGELOG.md b/CHANGELOG.md index babb10b6b4..13572f0cae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,26 @@ x.y.z Release notes (yyyy-MM-dd) ### Internal * Upgraded realm-core from ? to ? +20.0.1 Release notes (2024-09-21) +============================================================= + +### Fixed + +* Having a query with a number of predicates ORed together may result in a + crash on some platforms (strict weak ordering check failing on iphone) + ([#8028](https://github.com/realm/realm-core/issues/8028), since v10.50.0) + +### Compatibility + +* Realm Studio: 15.0.0 or later. +* Carthage release for Swift is built with Xcode 15.4.0. +* CocoaPods: 1.10 or later. +* Xcode: 15.3.0-16.1 beta. + +### Internal + +* Upgraded realm-core from v20.0.0 to 20.1.0 + 20.0.0 Release notes (2024-09-09) ============================================================= diff --git a/Package.swift b/Package.swift index d54319d7c8..e26ff5be42 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription import Foundation -let coreVersion = Version("20.0.0") -let cocoaVersion = Version("20.0.0") +let coreVersion = Version("20.1.0") +let cocoaVersion = Version("20.0.1") #if compiler(>=6) let swiftVersion = [SwiftVersion.version("6")] diff --git a/Realm/Realm-Info.plist b/Realm/Realm-Info.plist index c21b79da64..24aa1812db 100644 --- a/Realm/Realm-Info.plist +++ b/Realm/Realm-Info.plist @@ -17,11 +17,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 20.0.0 + 20.0.1 CFBundleSignature ???? CFBundleVersion - 20.0.0 + 20.0.1 NSHumanReadableCopyright Copyright © 2014-2021 Realm. All rights reserved. NSPrincipalClass diff --git a/build.sh b/build.sh index f6227f8c4e..83104a650e 100755 --- a/build.sh +++ b/build.sh @@ -21,17 +21,13 @@ if [ -n "${CI}" ]; then CODESIGN_PARAMS=(CODE_SIGN_IDENTITY='' CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO) fi -if [ -n "${CI_XCODE_CLOUD}" ]; then - DERIVED_DATA="$CI_DERIVED_DATA_PATH" - ROOT_WORKSPACE="$CI_WORKSPACE" - BRANCH="$CI_BRANCH" -elif [ -n "${GITHUB_WORKSPACE}" ]; then - DERIVED_DATA="$GITHUB_WORKSPACE/build/DerivedData/Realm" +if [ -n "${GITHUB_WORKSPACE}" ]; then + DERIVED_DATA="$GITHUB_WORKSPACE/build/DerivedData" ROOT_WORKSPACE="$GITHUB_WORKSPACE" - BRANCH="$GITHUB_REF" + BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF}}" else ROOT_WORKSPACE="$(pwd)" - DERIVED_DATA="$ROOT_WORKSPACE/build/DerivedData/Realm" + DERIVED_DATA="$ROOT_WORKSPACE/build/DerivedData" BRANCH="$(git branch --show-current)" fi @@ -74,6 +70,7 @@ command: examples-tvos-swift: builds all Swift tvOS examples get-version: get the current version + get-ioplatformuuid: get io platform uuid set-version version: set the version set-core-version version: set the version of core to use @@ -88,6 +85,7 @@ command: publish-github: create a Github release for the currently checked-out tag publish-docs: publish a built docs release to the website + publish-update-checker: publish cocoa file with a version to check for update logic publish-cocoapods [tag]: publish the requested tag to CocoaPods prepare-publish-changelog: creates a changelog file to be used in Slack @@ -175,7 +173,7 @@ build_combined() { build_args=(-scheme "$product" -configuration "$config" build REALM_HIDE_SYMBOLS=YES) # Derive build paths - local build_products_path="$DERIVED_DATA/Build/Products" + local build_products_path="$DERIVED_DATA/Realm/Build/Products" local product_name="$product.framework" local os_path="$build_products_path/$config${config_suffix}/$product_name" local simulator_path="$build_products_path/$config-$simulator_suffix/$product_name" @@ -196,89 +194,12 @@ build_combined() { -framework "$os_path" "${simulator_framework[@]}" } -# To be used with Github actions runner -build_platform() { - local product="$1" - local platform="$2" - local config="$CONFIGURATION" - - local destination build_args config_suffix - case "$platform" in - osx) - config_suffix= - destination='generic/platform=macOS' - ;; - ios) - config_suffix=-iphoneos - destination='generic/platform=iOS' - ;; - watchos) - config_suffix=-watchos - destination='generic/platform=watchOS' - ;; - tvos) - config_suffix=-appletvos - destination='generic/platform=tvOS' - ;; - visionos) - config_suffix=-xros - destination='generic/platform=visionOS' - ;; - catalyst) - config_suffix=-maccatalyst - destination='generic/platform=macOS,variant=Mac Catalyst' - ;; - osx) - destination='generic/platform=macOS' - ;; - iossimulator) - config_suffix=-iphonesimulator - destination='generic/platform=iOS' - ;; - watchossimulator) - config_suffix=-watchsimulator - destination='generic/platform=watchOS' - ;; - tvossimulator) - config_suffix=-appletvsimulator - destination='generic/platform=tvOS' - ;; - visionossimulator) - config_suffix=-xrsimulator - destination='generic/platform=visionOS' - ;; - esac - - build_products_path="$DERIVED_DATA/Build/Products" - build_path="$build_products_path/$config${config_suffix}" - - build_args=(-scheme "$product" -configuration "$config" build REALM_HIDE_SYMBOLS=YES) - - if [[ "$platform" = *"simulator" ]]; then - xc -destination "$destination Simulator" "${build_args[@]}" - else - xc -destination "$destination" "${build_args[@]}" - fi - - # This is only for test, and simulates how it is packaged by XCode Cloud - number="$((10000 + $RANDOM % 99999))" - folder_name="RealmSwift Build $number Build Products for $product on iOS" - dir="$folder_name/$config${config_suffix}" - mkdir -p "$dir" - cp -a "$build_path/." "$dir" - - config_name="$(tr [A-Z] [a-z] <<< "$config")" - zip -r product.zip "$dir" - rm -rf "$folder_name" -} - create_xcframework() { local product="$1" local config="$2" - local platform="$3" - local out_path="$ROOT_WORKSPACE/$config/$platform/$product.xcframework" - find "$ROOT_WORKSPACE" -path "*/$config*/$product.framework" \ + local out_path="$ROOT_WORKSPACE/$config/$product.xcframework" + find "$ROOT_WORKSPACE"/build-*/"$config" -name "$product.framework" \ | sed 's/.*/-framework &/' \ | xargs xcodebuild -create-xcframework -allow-internal-distribution -output "$out_path" codesign --timestamp -s "$SIGNING_IDENTITY" "$out_path" @@ -306,6 +227,14 @@ plist_get() { /usr/libexec/PlistBuddy -c "Print :$2" "$1" 2> /dev/null } +iphone_name() { + if (( $(xcode_version_major) < 16 )); then + echo 'iPhone 14' + else + echo 'iPhone 16' + fi +} + ###################################### # Device Test Helper ###################################### @@ -510,21 +439,17 @@ case "$COMMAND" in "xcframework") # Build all of the requested frameworks shift - if (( $(xcode_version_major) < 15 )); then - PLATFORMS="${*:-osx ios watchos tvos catalyst}" - else - PLATFORMS="${*:-osx ios watchos tvos catalyst visionos}" - fi + PLATFORMS="${*:-osx ios watchos tvos catalyst visionos}" for platform in $PLATFORMS; do sh build.sh "$platform-swift" done # Assemble them into xcframeworks - rm -rf "$DERIVED_DATA/Build/Products"*.xcframework - find "$DERIVED_DATA/Build/Products" -name 'Realm.framework' \ + rm -rf "$DERIVED_DATA/Realm/Build/Products"*.xcframework + find "$DERIVED_DATA/Realm/Build/Products" -name 'Realm.framework' \ | sed 's/.*/-framework &/' \ | xargs xcodebuild -create-xcframework -allow-internal-distribution -output "build/$CONFIGURATION/Realm.xcframework" - find "$DERIVED_DATA/Build/Products" -name 'RealmSwift.framework' \ + find "$DERIVED_DATA/Realm/Build/Products" -name 'RealmSwift.framework' \ | sed 's/.*/-framework &/' \ | xargs xcodebuild -create-xcframework -allow-internal-distribution -output "build/$CONFIGURATION/RealmSwift.xcframework" @@ -581,12 +506,12 @@ case "$COMMAND" in ;; "test-ios") - xctest Realm -configuration "$CONFIGURATION" -sdk iphonesimulator -destination 'name=iPhone 14' + xctest Realm -configuration "$CONFIGURATION" -sdk iphonesimulator -destination "name=$(iphone_name)" exit 0 ;; "test-ios-swift") - xctest RealmSwift -configuration "$CONFIGURATION" -sdk iphonesimulator -destination 'name=iPhone 14' + xctest RealmSwift -configuration "$CONFIGURATION" -sdk iphonesimulator -destination "name=$(iphone_name)" exit 0 ;; @@ -650,7 +575,7 @@ case "$COMMAND" in ;; "test-ios-swiftui") - xctest 'SwiftUITestHost' -configuration "$CONFIGURATION" -sdk iphonesimulator -destination 'name=iPhone 11' + xctest 'SwiftUITestHost' -configuration "$CONFIGURATION" -sdk iphonesimulator -destination "name=$(iphone_name)" exit 0 ;; @@ -664,6 +589,16 @@ case "$COMMAND" in exit 0 ;; + "test-visionos") + xctest Realm -configuration "$CONFIGURATION" -sdk xrsimulator -destination 'platform=visionOS Simulator,name=Apple Vision Pro' CODE_SIGN_IDENTITY='' + exit 0 + ;; + + "test-visionos-swift") + xctest RealmSwift -configuration "$CONFIGURATION" -sdk xrsimulator -destination 'platform=visionOS Simulator,name=Apple Vision Pro' CODE_SIGN_IDENTITY='' + exit 0 + ;; + ###################################### # Full verification ###################################### @@ -697,15 +632,15 @@ case "$COMMAND" in ;; "verify-cocoapods") - export REALM_TEST_BRANCH="$sha" + export REALM_TEST_BRANCH="$BRANCH" if [[ -d .git ]]; then # Verify the current branch, unless one was already specified in the sha environment variable. - if [[ -z $sha ]]; then + if [[ -z $BRANCH ]]; then export REALM_TEST_BRANCH=$(git rev-parse --abbrev-ref HEAD) fi if [[ $(git log -1 '@{push}..') != "" ]] || ! git diff-index --quiet HEAD; then - echo "WARNING: verify-cocoapods will test the latest revision of $sha found on GitHub." + echo "WARNING: verify-cocoapods will test the latest revision of $BRANCH found on GitHub." echo " Any unpushed local changes will not be tested." echo "" sleep 1 @@ -725,7 +660,7 @@ case "$COMMAND" in PLATFORM=$(echo "$COMMAND" | cut -d - -f 3) cd examples/installation - REALM_TEST_BRANCH="$sha" ./build.rb "$PLATFORM" cocoapods "$LINKAGE" + REALM_TEST_BRANCH="$BRANCH" ./build.rb "$PLATFORM" cocoapods "$LINKAGE" ;; "verify-docs") @@ -742,15 +677,15 @@ case "$COMMAND" in ;; "verify-spm") - export REALM_TEST_BRANCH="$sha" + export REALM_TEST_BRANCH="$BRANCH" if [[ -d .git ]]; then # Verify the current branch, unless one was already specified in the sha environment variable. - if [[ -z $sha ]]; then + if [[ -z $BRANCH ]]; then export REALM_TEST_BRANCH=$(git rev-parse --abbrev-ref HEAD) fi if [[ $(git log -1 '@{push}..') != "" ]] || ! git diff-index --quiet HEAD; then - echo "WARNING: verify-spm will test the latest revision of $sha found on GitHub." + echo "WARNING: verify-spm will test the latest revision of $BRANCH found on GitHub." echo " Any unpushed local changes will not be tested." echo "" sleep 1 @@ -771,7 +706,7 @@ case "$COMMAND" in PLATFORM=$(echo "$COMMAND" | cut -d - -f 3) cd examples/installation - REALM_TEST_BRANCH="$sha" ./build.rb "$PLATFORM" spm "$LINKAGE" + REALM_TEST_BRANCH="$BRANCH" ./build.rb "$PLATFORM" spm "$LINKAGE" exit 0 ;; @@ -806,9 +741,7 @@ case "$COMMAND" in sh build.sh examples-osx ( - DERIVED_EXAMPLE_DATA=${DERIVED_DATA:-examples/osx/objc/build/DerivedData/RealmExamples} - - cd $DERIVED_EXAMPLE_DATA/Build/Products/$CONFIGURATION + cd examples/osx/objc/build/DerivedData/RealmExamples/Build/Products/Release DYLD_FRAMEWORK_PATH=. ./JSONImport >/dev/null ) exit 0 @@ -1024,9 +957,12 @@ case "$COMMAND" in "ci-pr") echo "Building with Xcode Version $(xcodebuild -version)" - export sha="$BRANCH" export REALM_EXTRA_BUILD_ARGUMENTS='GCC_GENERATE_DEBUGGING_SYMBOLS=NO -allowProvisioningUpdates' - target=$(echo "$CI_WORKFLOW" | cut -f1 -d_) + target="$2" + if [[ "$target" == visionos ]] && (( $(xcode_version_major) < 16 )); then + echo 'Installing visionOS' + xcodebuild -downloadPlatform visionOS + fi sh build.sh "verify-$target" ;; @@ -1044,29 +980,10 @@ case "$COMMAND" in zip -r docs/realm-docs.zip docs/objc_output docs/swift_output ;; - release-create-xcframework-*) - platform="$2" - xcode_version=$(echo "$COMMAND" | cut -d- -f4) - - find . -name 'build-*.zip' -exec unzip {} \; - - create_xcframework Realm Release "$platform" - create_xcframework RealmSwift Release "$platform" - - if [ "$platform" = "ios" ]; then - create_xcframework Realm Static "$platform" - else - mkdir -p "Static/$platform" - fi - - zip --symlinks -r "realm-$platform-$xcode_version.zip" "Release/$platform" "Static/$platform" - exit 0 - ;; - "release-package") version="$(sed -n 's/^VERSION=\(.*\)$/\1/p' "${source_root}/dependencies.list")" - find . -name 'realm-*-1*' -maxdepth 1 \ - | sed 's@./realm-[a-z]*-\(.*\)@\1@' \ + find . -name 'build-*-1*' -maxdepth 1 \ + | sed 's@./build-[a-z]*-\(.*\)-.*@\1@' \ | sort -u --version-sort \ | xargs ./scripts/create-release-package.rb "${ROOT_WORKSPACE}/pkg" "${version}" ;; @@ -1117,90 +1034,6 @@ case "$COMMAND" in # Release tests ###################################### - # Should select xcode version `xcode-select` first. - # Pass xcode version as argument - # This simulates what is done in XCode Cloud - "test-create-frameworks") - xcode_version="$2" - targets="Realm RealmSwift" - - platforms=("ios" "iossimulator" "osx" "tvos" "tvossimulator" "watchos" "watchossimulator" "catalyst") - if [ "$xcode_version" == "15.2" ]; then - platforms+=("visionos" "visionossimulator") - fi - - for platform in "${platforms[@]}"; do - for target in $targets; do - echo "Building $platform and $target release" - ./build.sh "release-package-$platform-$xcode_version-$target-release" - ./build.sh "release-build_$platform-$xcode_version-$target-release" - - # Only generates Realm framework for Static configuration and ios platform - if [[ "$platform" == "ios" || "$platform" == "iossimulator" ]] && [[ "$target" == "Realm" ]]; then - echo "Building $platform and $target static" - ./build.sh "release-package-$platform-$xcode_version-$target-static" - ./build.sh "release-package-build_$platform-$xcode_version-$target-static" - fi - done - done - ;; - - "test-build-product-workflow-xcode-cloud") - issuer_id="" - key_id="" - pk_path="" - - token=$(ruby ./scripts/xcode_cloud_helper.rb --issuer-id $issuer_id --key-id $key_id --pk-path $pk_path get-token) - echo "Authentication token -> $token" - - # Test parameters - platform="ios" - target="RealmSwift" - xcode_version="15.2" - configuration="release" - - workflow_id=$(ruby ./scripts/xcode_cloud_helper.rb create-workflow release-package-build $platform $xcode_version $target $configuration -t $token) - echo "Created workflow -> $workflow_id" - build_run_id=$(ruby ./scripts/xcode_cloud_helper.rb build-workflow $workflow_id dp/new_migration_branch -t $token) - echo "Build Run -> $build_run_id" - while [ "$status" != 'COMPLETE' ] - do - token=$(ruby ./scripts/xcode_cloud_helper.rb --issuer-id $issuer_id --key-id $key_id --pk-path $pk_path get-token) - status=$(ruby ./scripts/xcode_cloud_helper.rb get-build-status $build_run_id -t $token) - echo "Status $status" | ts - sleep 20 - done - completion_status=$(ruby ./scripts/xcode_cloud_helper.rb get-build-result $build_run_id -t $token) - echo "Completion Status $completion_status" | ts - if [ "$completion_status" != 'SUCCEEDED' ]; then - echo "XCode build failed" - ruby ./scripts/xcode_cloud_helper.rb print-build-logs $build_run_id -t $token - exit 1 - fi - - ruby ./scripts/xcode_cloud_helper.rb print-build-logs $build_run_id -t $token - ruby ./scripts/xcode_cloud_helper.rb download-artifact $build_run_id -t $token - ruby ./scripts/xcode_cloud_helper.rb delete-workflow $workflow_id -t $token - ;; - - # Pass xcode version as argument - # For this to work, product builds should be located in the root of the project - "test-create-platform-xcframeworks") - xcode_version="$2" - - platforms=("ios" "osx" "tvos" "watchos" "catalyst") - if [ "$xcode_version" == "15.1" ]; then - platforms+=("visionos") - fi - - for platform in "${platforms[@]}"; do - ./build.sh release-create-xcframework_$xcode_version $platform - - rm -rf "$ROOT_WORKSPACE/Release" - rm -rf "$ROOT_WORKSPACE/Static" - done - ;; - "test-package-examples") VERSION="$(sed -n 's/^VERSION=\(.*\)$/\1/p' "${source_root}/dependencies.list")" dir="realm-swift-${VERSION}" @@ -1226,22 +1059,6 @@ case "$COMMAND" in sh build.sh examples-tvos-swift ;; - # This is used for test or if we want to use Github Actions to build each framework - release-package-build_*) - filename="Configuration/Release.xcconfig" - sed -i '' "s/REALM_HIDE_SYMBOLS = NO;/REALM_HIDE_SYMBOLS = YES;/" "$filename" - - # Remove the identifier of the command, so we can obtain the parameters from the command - build_command=${COMMAND#"release-package-build_"} - parameters=(${build_command//-/ }) - - platform=${parameters[0]} - target=${parameters[1]} - - build_platform "$target" "$platform" - exit 0 - ;; - ###################################### # Publish ###################################### diff --git a/ci_scripts/ci_post_clone.sh b/ci_scripts/ci_post_clone.sh deleted file mode 100755 index c8da17df76..0000000000 --- a/ci_scripts/ci_post_clone.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/bash - -set -eo pipefail - -###################################### -# Dependency Installer -###################################### - -USE_BUNDLE_EXEC='' -install_dependencies() { - if [[ "$CI_WORKFLOW" == "docs"* ]]; then - install_ruby - elif [[ "$CI_WORKFLOW" == "swiftlint"* ]]; then - brew install swiftlint - elif [[ "$CI_WORKFLOW" == "cocoapods"* ]]; then - install_ruby - elif [[ "$CI_WORKFLOW" = *"spm"* ]] || [[ "$CI_WORKFLOW" = "xcframework"* ]]; then - install_ruby - elif [[ "$CI_WORKFLOW" == *"carthage"* ]]; then - brew install carthage - else - sh build.sh download-core - fi -} - -install_ruby() { - brew install rbenv ruby-build - rbenv install - eval "$(rbenv init -)" - bundle install - USE_BUNDLE_EXEC=true -} - -env - -cd "$(dirname "$0")"/.. -install_dependencies - -# Xcode Cloud doesn't let us set the configuration to build, so set it by -# modifying the scheme files -target=$(echo "$CI_WORKFLOW" | cut -f1 -d_) -configuration="Release" -case "$target" in - *-debug) configuration="Debug" ;; - *-static) configuration="Static" ;; -esac - -find Realm.xcodeproj -name '*.xcscheme' \ - -exec sed -i '' "s/buildConfiguration = \"Debug\"/buildConfiguration = \"$configuration\"/" {} \; - -# If testing library evolution mode, patch the config to enable it -if [[ "$target" == *-evolution ]]; then - filename='Configuration/RealmSwift/RealmSwift.xcconfig' - sed -i '' "s/REALM_BUILD_LIBRARY_FOR_DISTRIBUTION = NO;/REALM_BUILD_LIBRARY_FOR_DISTRIBUTION = YES;/" "$filename" -fi - -# If testing encryption, patch the scheme to enable it -if [[ "$target" == *-encryption ]]; then - filename='Realm.xcodeproj/xcshareddata/xcschemes/Realm.xcscheme' - xmllint --shell "$filename" << EOF - cd /Scheme/LaunchAction/EnvironmentVariables/EnvironmentVariable[@key='REALM_ENCRYPT_ALL']/@isEnabled - set YES - save -EOF -fi - -# In release we are creating some workflows which build the framework for each platform, target and configuration, -# and we need to set the linker flags in the Configuration file. -if [[ "$target" == "release-package-build-"* ]]; then - filename="Configuration/Release.xcconfig" - sed -i '' "s/REALM_HIDE_SYMBOLS = NO;/REALM_HIDE_SYMBOLS = YES;/" "$filename" -fi - -# Xcode cloud currently doesn't have visionOS installed for Xcode 15.3 -if [[ "$CI_WORKFLOW" == release-package-build-vision*_15.3 ]]; then - xcodebuild -downloadAllPlatforms -fi - -# If we're building the dummy CI target then run the test. Other schemes are -# built via Xcode cloud's xcodebuild invocation. We can't do this via a build -# step on the CI target as that results in nested invocations of xcodebuild, -# which doesn't work. -if [[ "$CI_XCODE_SCHEME" == CI ]]; then - if [[ -n "$USE_BUNDLE_EXEC" ]]; then - bundle exec sh build.sh ci-pr - else - sh build.sh ci-pr - fi -fi diff --git a/dependencies.list b/dependencies.list index ca8211e69a..bd708bd499 100755 --- a/dependencies.list +++ b/dependencies.list @@ -1,2 +1,2 @@ -VERSION=20.0.0 -REALM_CORE_VERSION=v20.0.0 +VERSION=20.0.1 +REALM_CORE_VERSION=v20.1.0 diff --git a/examples/installation/SubRealm/SubRealm.podspec b/examples/installation/SubRealm/SubRealm.podspec index 8af535de9a..015ba2ef72 100644 --- a/examples/installation/SubRealm/SubRealm.podspec +++ b/examples/installation/SubRealm/SubRealm.podspec @@ -11,6 +11,7 @@ Pod::Spec.new do |s| s.osx.deployment_target = '10.15' s.watchos.deployment_target = '5.0' s.tvos.deployment_target = '12.0' + s.visionos.deployment_target = '1.0' s.source_files = "*.swift" s.dependency 'RealmSwift' end diff --git a/scripts/pr-ci-matrix.rb b/scripts/pr-ci-matrix.rb index f91e99ec5b..3ea97e04ea 100755 --- a/scripts/pr-ci-matrix.rb +++ b/scripts/pr-ci-matrix.rb @@ -1,137 +1,101 @@ #!/usr/bin/env ruby -# Matrix of current targets and XCode versions, and is used to add/update/delete XCode cloud workflows. +XCODE_VERSIONS = %w(15.3 15.4 16 16.1_Release_Candidate) +DOC_VERSION = '16' -Destination = Struct.new(:build_platform, :test_destination) do |cls| - def cls.macOS - Destination.new('MACOS', { - 'deviceTypeName' => 'Mac', - 'deviceTypeIdentifier' => 'mac', - 'runtimeName' => 'Same As Selected macOS Version', - 'runtimeIdentifier' => 'builder', - 'kind' => 'MAC' - }) - end +all = ->(v) { true } +latest_only = ->(v) { v == XCODE_VERSIONS.last } +oldest_and_latest = ->(v) { v == XCODE_VERSIONS.first or v == XCODE_VERSIONS.last } - def cls.catalyst - Destination.new('MACOS', { - 'deviceTypeName' => 'Mac (Mac Catalyst)', - 'deviceTypeIdentifier' => 'mac_catalyst', - 'runtimeName' => 'Same As Selected macOS Version', - 'runtimeIdentifier' => 'builder', - 'kind' => 'MAC' - }) - end - - def cls.iOS - Destination.new('IOS', { - 'deviceTypeName' => 'iPhone 11', - 'deviceTypeIdentifier' => 'com.apple.CoreSimulator.SimDeviceType.iPhone-11', - 'runtimeName' => 'Latest from Selected Xcode (iOS 16.1)', - 'runtimeIdentifier' => 'default', - 'kind' => 'SIMULATOR' - }) - end - - def cls.tvOS - Destination.new('TVOS', { - 'deviceTypeName' => 'Recommended Apple TVs', - 'deviceTypeIdentifier' => 'recommended_apple_tvs', - 'runtimeName' => 'Latest from Selected Xcode (tvOS 16.4)', - 'runtimeIdentifier' => 'default', - 'kind' => 'SIMULATOR' - }) - end - - def cls.generic - Destination.new('MACOS', nil) - end +def minimum_version(major) + ->(v) { v.split('.').first.to_i >= major } end -Target = Struct.new(:name, :scheme, :filter, :destination) do - def action - action = { - name: self.name, - actionType: 'BUILD', - destination: nil, - buildDistributionAudience: nil, - scheme: self.scheme, - platform: self.destination.build_platform, - isRequiredToPass: true - } - - test_destination = self.destination.test_destination - if test_destination - action[:actionType] = 'TEST' - action[:destination] = 'ANY_MAC' - action[:testConfiguration] = { - kind: 'USE_SCHEME_SETTINGS', - testPlanName: '', - testDestinations: [test_destination] - } +targets = { + 'osx' => all, + 'osx-encryption' => latest_only, + + 'swiftpm' => oldest_and_latest, + 'swiftpm-debug' => all, + 'swiftpm-address' => latest_only, + 'swiftpm-thread' => latest_only, + + 'ios-static' => oldest_and_latest, + 'ios' => oldest_and_latest, + 'watchos' => oldest_and_latest, + 'tvos' => oldest_and_latest, + 'visionos' => oldest_and_latest, + + 'osx-swift' => all, + 'ios-swift' => oldest_and_latest, + 'tvos-swift' => oldest_and_latest, + + 'osx-swift-evolution' => latest_only, + 'ios-swift-evolution' => latest_only, + 'tvos-swift-evolution' => latest_only, + + 'catalyst' => oldest_and_latest, + 'catalyst-swift' => oldest_and_latest, + + 'xcframework' => latest_only, + + 'cocoapods-osx' => all, + 'cocoapods-ios-static' => latest_only, + 'cocoapods-ios' => latest_only, + 'cocoapods-watchos' => latest_only, + 'cocoapods-tvos' => latest_only, + 'cocoapods-catalyst' => latest_only, + 'ios-swiftui' => latest_only, +} + +output_file = """ +# This is a generated file produced by scripts/pr-ci-matrix.rb. +name: Pull request build and test +on: + pull_request: + paths-ignore: + - '**.md' + workflow_dispatch: + +jobs: + docs: + runs-on: macos-14 + name: Test docs + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - run: sudo xcode-select -switch /Applications/Xcode_#{DOC_VERSION}.app + - run: bundle exec sh build.sh verify-docs + swiftlint: + runs-on: macos-14 + name: Check swiftlint + steps: + - uses: actions/checkout@v4 + - run: sudo xcode-select -switch /Applications/Xcode_#{DOC_VERSION}.app + - run: brew install swiftlint + - run: sh build.sh verify-swiftlint +""" + +targets.each { |name, filter| + XCODE_VERSIONS.each { |version| + if not filter.call(version) + next end - - return action - end -end - -# Each test target has a name, a scheme, an xcode version filter, and a -# destination to run tests on. Targets which aren't testing a framework -# use the 'CI' target and always the a 'generic' destination. -# -# To avoid using excess CI resources we don't build the full matrix of -# combinations of targets and Xcode version. We generally test each build -# method (Xcode project, Swift package, and podspec) on every Xcode version for -# a single platform, and everything else is tested with the oldest and newest -# supported Xcode versions. Some things (e.g. swiftlint) only test the latest -# because they don't care about Xcode versions, while some others are latest-only -# because they're particularly slow to run. -module Workflows - XCODE_VERSIONS = %w(15.3 15.4 16\ beta\ 6 16.1\ beta) - - all = ->(v) { true } - latest_only = ->(v) { v == XCODE_VERSIONS.last } - oldest_and_latest = ->(v) { v == XCODE_VERSIONS.first or v == XCODE_VERSIONS.last } - - TARGETS = [ - Target.new('osx', 'Realm', all, Destination.macOS), - Target.new('osx-encryption', 'Realm', latest_only, Destination.macOS), - Target.new('osx-swift', 'RealmSwift', all, Destination.macOS), - Target.new('osx-swift-evolution', 'RealmSwift', latest_only, Destination.macOS), - - Target.new('ios', 'Realm', oldest_and_latest, Destination.iOS), - Target.new('ios-static', 'Realm', oldest_and_latest, Destination.iOS), - Target.new('ios-swift', 'RealmSwift', oldest_and_latest, Destination.iOS), - Target.new('ios-swift-evolution', 'RealmSwift', latest_only, Destination.iOS), - - Target.new('tvos', 'Realm', oldest_and_latest, Destination.tvOS), - Target.new('tvos-static', 'Realm', oldest_and_latest, Destination.tvOS), - Target.new('tvos-swift', 'RealmSwift', oldest_and_latest, Destination.tvOS), - Target.new('tvos-swift-evolution', 'RealmSwift', latest_only, Destination.tvOS), - - Target.new('catalyst', 'Realm', oldest_and_latest, Destination.catalyst), - Target.new('catalyst-swift', 'RealmSwift', oldest_and_latest, Destination.catalyst), - - Target.new('watchos', 'Realm', oldest_and_latest, Destination.generic), - Target.new('watchos-swift', 'RealmSwift', oldest_and_latest, Destination.generic), - - Target.new('swiftui', 'SwiftUITests', latest_only, Destination.iOS), - - Target.new('docs', 'CI', latest_only, Destination.generic), - Target.new('swiftlint', 'CI', latest_only, Destination.generic), - - Target.new('swiftpm', 'CI', oldest_and_latest, Destination.generic), - Target.new('swiftpm-debug', 'CI', all, Destination.generic), - Target.new('swiftpm-address', 'CI', latest_only, Destination.generic), - Target.new('swiftpm-thread', 'CI', latest_only, Destination.generic), - Target.new('spm-ios', 'CI', all, Destination.generic), - - Target.new('xcframework', 'CI', latest_only, Destination.generic), - - Target.new('cocoapods-osx', 'CI', all, Destination.generic), - Target.new('cocoapods-ios', 'CI', latest_only, Destination.generic), - Target.new('cocoapods-ios-static', 'CI', latest_only, Destination.generic), - Target.new('cocoapods-watchos', 'CI', latest_only, Destination.generic), - Target.new('cocoapods-tvos', 'CI', latest_only, Destination.generic), - Target.new('cocoapods-catalyst', 'CI', latest_only, Destination.generic), - ] + image = version.start_with?('16') ? 'macos-15' : 'macos-14' + output_file << """ + #{name}-#{version.gsub(' ', '_').gsub('.', '_')}: + runs-on: #{image} + name: Test #{name} on Xcode #{version} + env: + DEVELOPER_DIR: '/Applications/Xcode_#{version}.app/Contents/Developer' + steps: + - uses: actions/checkout@v4 + - run: sh -x build.sh ci-pr #{name} +""" + } +} + +File.open('.github/workflows/build-pr.yml', "w") do |file| + file.puts output_file end diff --git a/scripts/xcode_cloud_helper.rb b/scripts/xcode_cloud_helper.rb deleted file mode 100755 index 52726474f9..0000000000 --- a/scripts/xcode_cloud_helper.rb +++ /dev/null @@ -1,603 +0,0 @@ -#!/usr/bin/env ruby -require 'base64' -require 'json' -require 'jwt' -require 'net/http' -require 'net/https' -require 'optparse' -require 'pp' -require 'uri' -require_relative "pr-ci-matrix" -require_relative "release-matrix" - -include Workflows - -APP_STORE_URL = 'https://api.appstoreconnect.apple.com/v1' -HTTP = Net::HTTP.new('api.appstoreconnect.apple.com', 443) -HTTP.use_ssl = true -HTTP.max_retries = 2 - -def sh(*args) - puts "executing: #{args.join(' ')}" if false - system(*args, false ? {} : {:out => '/dev/null'}) || exit(1) -end - -def request(req) - req['Authorization'] = "Bearer #{JWT_TOKEN}" - # puts req.path - counter = 0 - while true do - sleep 5 - counter +=1 - response = HTTP.request(req) - break if (response.code =~ /20./ ) == 0 - break if counter == 2 - end - - raise "Error: #{response.code} #{response.body}" unless response.code =~ /20./ - response -end - -def get(path) - req = Net::HTTP::Get.new("/v1/#{path}") - req['Accept'] = 'application/json' - response = request req - # puts response.body - JSON.parse(response.body) -end - -def post(path, body) - req = Net::HTTP::Post.new("/v1/#{path}") - req['Content-Type'] = 'application/json' - req.body = body.to_json - response = request req - JSON.parse(response.body) -end - -def get_jwt_bearer_from_file(issuer_id, key_id, pk_path) - private_key = File.read(pk_path) - get_jwt_bearer(issuer_id, key_id, private_key) -end - -def get_jwt_bearer(issuer_id, key_id, pk) - private_key = OpenSSL::PKey.read(pk) - info = { - iss: issuer_id, - exp: Time.now.to_i + 20 * 60, - aud: 'appstoreconnect-v1' - } - header_fields = { kid: key_id } - JWT.encode(info, private_key, 'ES256', header_fields) -end - -def get_workflows - product_id = get_realm_product_id - get("/ciProducts/#{product_id}/workflows?limit=200")['data'] -end - -def get_products - get('ciProducts')['data'].map do |product| - { - id: product['id'], - product: product['attributes']['name'], - type: product['attributes']['productType'] - } - end -end - -def get_repositories - response = get('scmRepositories')['data'].map do |repo| - { - id: repo['id'], - name: repo['attributes']['repositoryName'], - url: repo['attributes']['httpCloneUrl'] - } - end -end - -def get_macos_versions - get('ciMacOsVersions')['data'].map do |macos| - { - id: macos['id'], - name: macos['attributes']['name'], - version: macos['attributes']['version'] - } - end -end - -def get_xcode_versions - data = get('ciXcodeVersions')['data'] - Hash[data.collect { |xcode| - [xcode['attributes']['name'], xcode['id']] - }] -end - -def get_build_actions(build_run) - get("/ciBuildRuns/#{build_run}/actions")['data'].map do |build_run| - { - id: build_run['id'], - } - end -end - -def get_artifacts(build_action) - get("/ciBuildActions/#{build_action}/artifacts")['data'].map do |artifact| - { - id: artifact['id'], - } - end -end - -def get_git_references - repository_id = get_realm_repository_id - get("/scmRepositories/#{repository_id}/gitReferences?limit=200") -end - -def get_workflow_info(id) - get("ciWorkflows/#{id}") -end - -def get_build_info(id) - get("/ciBuildRuns/#{id}") -end - -def get_artifact_info(id) - get("/ciArtifacts/#{id}") -end - -def create_workflow(target, xcode_version, pull_request) - result = post('ciWorkflows', create_workflow_request(target, xcode_version, pull_request)) - id = result["data"]["id"] - return id -end - -def create_workflow_request(target, xcode_version, pull_request) - xcode_version_id = get_xcode_id(xcode_version) - data = { - data: { - type: 'ciWorkflows', - attributes: { - name: "#{target.name}_#{xcode_version}", - description: 'Create by Github Action Update XCode Cloud Workflows', - isLockedForEditing: false, - containerFilePath: 'Realm.xcodeproj', - isEnabled: true, - clean: false, - actions: [target.action] - }, - relationships: { - xcodeVersion: { - data: { - type: 'ciXcodeVersions', - id: xcode_version_id - } - }, - macOsVersion: { - data: { - type: 'ciMacOsVersions', - id: get_macos_latest_release(xcode_version_id) - } - }, - product: { - data: { - type: 'ciProducts', - id: get_realm_product_id - } - }, - repository: { - data: { - type: 'scmRepositories', - id: get_realm_repository_id - } - } - } - } - } - - if pull_request - data[:data][:attributes][:pullRequestStartCondition] = { - source: { - isAllMatch: true, - }, - destination: { - isAllMatch: true, - }, - autoCancel: true - } - else - data[:data][:attributes][:manualBranchStartCondition] = { - source: { - isAllMatch: true, - }, - destination: { - isAllMatch: true, - }, - autoCancel: true - } - end - - data -end - -def enable_workflow(id) - req = Net::HTTP::Patch.new("/v1/ciWorkflows/#{id}") - req['Content-type'] = 'application/json' - req.body = { - data: { - type: 'ciWorkflows', - attributes: { - isEnabled: true - }, - id: id - } - }.to_json - response = request req - puts response.body - result = JSON.parse(response.body) - id = result['data']['id'] - puts "Workflow updated #{id}" - return id -end - -def delete_workflow(id) - req = Net::HTTP::Delete.new("/v1/ciWorkflows/#{id}") - req['Content-type'] = 'application/json' - response = request req -end - -def start_build(id, branch) - branch_id = find_git_reference_for_branch(branch) - result = post('ciBuildRuns', { - data: { - type: 'ciBuildRuns', - attributes: {}, - relationships: { - workflow: { - data: { - type: 'ciWorkflows', - id: id - } - }, - sourceBranchOrTag: { - data: { - type: 'scmGitReferences', - id: branch_id - } - } - } - } - }) - id = result['data']['id'] - return id -end - -def get_macos_version_for_xcode_version(version) - result = get("ciXcodeVersions/#{version}/macOsVersions") - latest = result['data'].find { |version| version['attributes']['name'] == 'Latest Release' } - latest['id'] -end - -def synchronize_workflows() - desired_workflows = Workflows::TARGETS.flat_map { |target| - Workflows::XCODE_VERSIONS.filter_map { |version| - if target.filter.call(version) - {target: target, version: version} - end - } - } - current_workflows = get_workflows.filter_map { |workflow| - name = workflow['attributes']['name'] - # don't touch release pipeline jobs - next if name.start_with? 'release-' - pieces = name.partition('_') - {name: pieces.first, version: pieces.last, id: workflow['id']} - } - - workflows_to_remove = current_workflows.reject { |current| - desired_workflows.find { |desired| - desired[:target].name == current[:name] && desired[:version] == current[:version] - } - } - workflows_to_create = desired_workflows.reject { |desired| - current_workflows.find { |current| - desired[:target].name == current[:name] && desired[:version] == current[:version] - } - } - - puts 'Workflows to remove:' - workflows_to_remove.each { |w| - puts "- #{w[:name]}: #{w[:version]}" - } - puts '' - puts 'Workflows to create:' - workflows_to_create.each { |w| - puts "- #{w[:target].name}: #{w[:version]}" - } - puts '' - print 'Do you wish to continue [create/delete/both/quit]? ' - - case STDIN.gets.chomp.downcase - when 'create' - workflows_to_remove = [] - when 'delete' - workflows_to_create = [] - when 'both' - when 'quit' - puts 'Exiting without making any changes' - exit 0 - else - puts 'Unrecoginized command' - exit 1 - end - - workflows_to_create.each { |w| - id = create_workflow(w[:target], w[:version], true) - puts "#{w[:target]}: https://appstoreconnect.apple.com/teams/69a6de86-7f37-47e3-e053-5b8c7c11a4d1/frameworks/#{get_realm_product_id}/workflows/#{id}" - } - workflows_to_remove.each { |w| - delete_workflow(w[:id]) - puts "Workflow deleted #{w[:name]}" - } -end - -def get_build_status(build_run) - build_state = get_build_info(build_run) - status = build_state["data"]["attributes"]["executionProgress"] - return status -end - -def get_build_result(build_run) - build_state = get_build_info(build_run) - completion_status = build_state["data"]["attributes"]["completionStatus"] - return completion_status -end - -def get_logs_for_build(build_run) - actions = get_build_actions(build_run) - artifacts = get_artifacts(actions[0][:id]) # we are only running one action, so we use the first one in the list - artifact_url = '' - artifacts.each { |artifact| - artifact_info = get_artifact_info(artifact[:id]) - if artifact_info["data"]["attributes"]["fileName"].include? 'Logs' - artifact_url = artifact_info["data"]["attributes"]["downloadUrl"] - end - } - print_logs(artifact_url) -end - -def print_logs(url) - sh 'curl', '--output', 'logs.zip', "#{url}" - sh 'unzip', '-o', 'logs.zip' - log_files = Dir["RealmSwift*/*.log"] - log_files.each { |log_file| - text = File.readlines("#{log_file}").map do |line| - puts line - end - } -end - -def find_git_reference_for_branch(branch) - next_page = '' - references = get_git_references - branch_reference = references["data"].find { |reference| - reference["attributes"]["kind"] == "BRANCH" && reference["attributes"]["name"] == branch - } - while branch_reference == nil || next_page == nil - next_page = references["links"]["next"] - next_page.slice!(APP_STORE_URL) - references = get(next_page) - branch_reference = references["data"].find { |reference| reference["attributes"]["kind"] == "BRANCH" && reference["attributes"]["name"] == branch } - end - return branch_reference["id"] -end - -def download_artifact_for_build(build_id_run) - actions = get_build_actions(build_id_run) - artifacts = get_artifacts(actions[0][:id]) # One actions per workflow - artifact_url = '' - artifacts.each { |artifact| - artifact_info = get_artifact_info(artifact[:id]) - if artifact_info["data"]["attributes"]["fileName"].include? 'Products' - artifact_url = artifact_info["data"]["attributes"]["downloadUrl"] - end - } - - sh 'curl', '--output', "xcode-cloud-build-#{build_id_run}.zip", "#{artifact_url}" -end - -def clean_up_release_workflows() - workflows_to_remove = get_workflows.filter_map { |workflow| - if workflow['attributes']['name'].start_with?('release-package-build') - {name: workflow['attributes']['name'], id: workflow['id']} - end - } - workflows_to_remove.each { |w| - delete_workflow(w[:id]) - puts "Workflow deleted #{w[:name]}" - } -end - -$xcode_ids = nil -def get_xcode_id(version) - $xcode_ids ||= get_xcode_versions - id = $xcode_ids["Xcode #{version}"] - if not id - puts "Nonexistent Xcode version #{version}" - puts "Valid versions are:" - $xcode_ids.keys.each { |v| puts "- #{v}"} - exit 1 - end - id -end - -$mac_dict = Hash.new { |h, k| h[k] = get_macos_version_for_xcode_version(k) } -def get_macos_latest_release(xcodeVersionId) - return $mac_dict[xcodeVersionId] -end - -$product_id = nil -def get_realm_product_id - $product_id ||= get_products.find { |p| p[:product] == 'RealmSwift' }[:id] -end - -$repository_id = nil -def get_realm_repository_id - $repository_id ||= get_repositories.find { |repo| repo[:name] == 'realm-swift' }[:id] -end - -$workflows_list = nil -def get_workflow_id_for_name(name) - $workflows_list ||= get_workflows - $workflows_list.find { |w| w['attributes']['name'].split('_')[0] == name }['id'] -end - -Options = Struct.new(:token, :team_id, :issuer_id, :key_id, :pk_path, :pk) -options = Options.new() -$parser = OptionParser.new do |opts| - opts.banner = "Usage: ruby #{__FILE__} [options] command" - opts.separator <<~END - - All commands require either --token or all three of --issuer-id, --key-id, - and --pk-path or --pk to automatically create a token. - - Commands: - list-workflows - Returns a list of current workflows for the RealmSwift product. - list-products - Returns a list of products associated to the Apple Connect Store account. - list-repositories - Returns a list of repositories integrated with XCode Cloud. - list-mac-versions - Returns a list of available mac versions. - list-xcode-versions - Returns a list of available xcode version. - info-workflow workflow_id - Returns the info for the corresponding workflow. - synchronize-workflows - Delete old workflows and/or create new ones. - build-workflow workflow-id - Run a build for the corresponding workflow. - create-workflow platform xcode_version target configuration - Creates a workflow to create platform framework for an specific configuration, target and xcode version. - delete-workflow workflow-id - Deletes the workflow. - wait-build build_id - Check status of a current build and waits, returns when completed or fails. - download-artifact build_id - Download a build artifact for any given build run with a build action. - clean-up-release-workflows - Cleans all workflows created for a release (starts with release-package-build). - get-build-status - Get build current status. - get-build-result - Get build run completion status (Complete, Error). - print-build-logs - Print build logs. - get-token - Get Apple Connect Store API Token for local use. - - Options: - END - - opts.on("-h", "--help", "Display this help") do - puts opts - exit 0 - end - opts.on('-t TOKEN', '--token TOKEN', 'Apple Connect API token') do |token| - options[:token] = token - end - opts.on('--issuer-id ID', 'Apple Connect API Issuer ID.') do |id| - options[:issuer_id] = id - end - opts.on('--key-id ID', 'Apple Connect API Key ID.') do |id| - options[:key_id] = id - end - opts.on('--pk-path PATH', 'Apple Connect API path to private key file.') do |path| - options[:pk_path] = path - end - opts.on('--pk PK', 'Apple Connect API private key.') do |pk| - options[:pk] = pk - end -end -$parser.parse! - -def usage() - puts $parser - exit 1 -end - -if options[:issuer_id] and options[:key_id] and options[:pk_path] - JWT_TOKEN = get_jwt_bearer_from_file(options[:issuer_id], options[:key_id], options[:pk_path]) -elsif options[:issuer_id] and options[:key_id] and options[:pk] - JWT_TOKEN = get_jwt_bearer(options[:issuer_id], options[:key_id], options[:pk]) -elsif options[:token] - JWT_TOKEN = options[:token] -else - usage -end - -COMMAND = ARGV.shift -usage unless COMMAND - -case COMMAND -when 'list-workflows' - pp get_workflows -when 'list-products' - pp get_products -when 'list-repositories' - pp get_repositories -when 'list-mac-versions' - pp get_macos_versions -when 'list-xcode-versions' - pp get_xcode_versions -when 'info-workflow' - workflow_id = ARGV.shift - usage unless workflow_id - pp get_workflow_info(workflow_id) -when 'enable-workflow' - workflow_id = ARGV.shift - usage unless workflow_id - enable_workflow(workflow_id) -when 'synchronize-workflows' - synchronize_workflows() -when 'build-workflow' - workflow_id = ARGV.shift - branch = ARGV.shift - usage unless workflow_id - id = start_build(workflow_id, branch) - puts id -when 'create-workflow' - prefix = ARGV.shift - platform = ARGV.shift - xcode_version = ARGV.shift - target = ARGV.shift - configuration = ARGV.shift - usage unless platform and xcode_version and target and configuration - release_target = ReleaseTarget.new("#{prefix}-#{platform}-#{target}-#{configuration}", target, platform) - id = create_workflow(release_target, xcode_version, false) - puts id -when 'delete-workflow' - workflow_id = ARGV.shift - delete_workflow(workflow_id) -when 'download-artifact' - build_id = ARGV.shift - usage unless build_id - download_artifact_for_build(build_id) -when 'clean-up-release-workflows' - clean_up_release_workflows() -when 'get-build-status' - build_id = ARGV.shift - status = get_build_status(build_id) - puts status -when 'get-build-result' - build_id = ARGV.shift - usage unless build_id - completion_status = get_build_result(build_id) - puts completion_status -when 'print-build-logs' - build_id = ARGV.shift - usage unless build_id - get_logs_for_build(build_id) -when 'get-token' - puts JWT_TOKEN -end