diff --git a/.github/workflows/master-push.yml b/.github/workflows/master-push.yml index c6c4b90345..5c97ffc6ec 100644 --- a/.github/workflows/master-push.yml +++ b/.github/workflows/master-push.yml @@ -3,14 +3,15 @@ on: push: branches: - "master" + - "tg/release-symlink" env: XCODE_VERSION: "['14.2', '14.3.1', '15.1', '15.2']" PLATFORM: "['ios', 'osx', 'watchos', 'tvos', 'catalyst', 'visionos']" BUILD_PLATFORM: "['ios', 'iossimulator', 'osx', 'watchos', 'watchossimulator', 'tvos', 'tvossimulator', 'catalyst', 'visionos', 'visionossimulator']" - DOC_VERSION: '15.1' + DOC_VERSION: '15.2' JAZZY_VERSION: '0.14.4' RELEASE_VERSION: '15.2' - TEST_VERSION: '15.1' + TEST_VERSION: '15.2' jobs: cleanup: # Clean-up XCode cloud workflows, before running the pipeline runs-on: ubuntu-latest @@ -21,7 +22,7 @@ jobs: id: token run: | token=$(echo $(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 + echo "TOKEN=$token" >> $GITHUB_OUTPUT - name: Clean up release-packages xcode cloud workflows run: | ruby ./scripts/xcode_cloud_helper.rb clean-up-release-workflows -t ${{ steps.token.outputs.TOKEN }} @@ -81,13 +82,12 @@ jobs: name: realm-examples build-product: # Creates framework for each platform, xcode version, target and configuration runs-on: macos-13 - name: Package framework + 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. matrix: platform: ${{ fromJSON(needs.prepare.outputs.BUILD_PLATFORM_MATRIX) }} - target: [RealmSwift, Realm] xcode-version: ${{ fromJSON(needs.prepare.outputs.XCODE_VERSIONS_MATRIX) }} configuration: [release, static] exclude: @@ -107,8 +107,6 @@ jobs: configuration: static - platform: visionossimulator configuration: static - - target: RealmSwift - configuration: static - platform: visionos xcode-version: 14.2 - platform: visionossimulator @@ -136,13 +134,13 @@ jobs: timeout_minutes: 10 max_attempts: 3 command: | - workflow_id=$(ruby ./scripts/xcode_cloud_helper.rb create-workflow release-package-build ${{ matrix.platform }} ${{ matrix.xcode-version }} ${{ matrix.target }} ${{ matrix.configuration }} -t ${{ steps.token.outputs.TOKEN }}) + workflow_id=$(ruby ./scripts/xcode_cloud_helper.rb create-workflow release-package-build ${{ matrix.platform }} ${{ matrix.xcode-version }} RealmSwift ${{ matrix.configuration }} -t ${{ steps.token.outputs.TOKEN }}) echo "WORKFLOW_ID=$workflow_id" >> $GITHUB_OUTPUT - name: Runs the XCode Cloud workflow created by the previous step id: build-run uses: nick-fields/retry@v2 with: - timeout_minutes: 10 + timeout_minutes: 15 max_attempts: 3 command: | build_run_id=$(ruby ./scripts/xcode_cloud_helper.rb build-workflow ${{ steps.create-workflow.outputs.WORKFLOW_ID }} ${{ github.ref_name }} -t ${{ steps.token.outputs.TOKEN }}) @@ -150,7 +148,7 @@ jobs: - name: Check build status and wait for it to finish uses: nick-fields/retry@v2 with: - timeout_minutes: 10 + timeout_minutes: 15 max_attempts: 3 command: | while [ "$status" != 'COMPLETE' ] @@ -176,76 +174,12 @@ jobs: command: | 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) ruby ./scripts/xcode_cloud_helper.rb download-artifact ${{ steps.build-run.outputs.BUILD_RUN_ID }} -t $token - - name: Prepare product folder - uses: nick-fields/retry@v2 - with: - timeout_minutes: 10 - max_attempts: 3 - command: | - sh -x build.sh release-package-product - name: Upload framework uses: actions/upload-artifact@v4 with: - name: product-${{ matrix.platform }}-${{ matrix.xcode-version }}-${{ matrix.target }}-${{ matrix.configuration }} - path: product-package - # build-product: # Creates framework for each platform, xcode version, target and configuration - # runs-on: macos-13 - # name: Package framework - # needs: prepare - # strategy: - # matrix: - # platform: ${{ fromJSON(needs.prepare.outputs.BUILD_PLATFORM_MATRIX) }} - # target: [RealmSwift, Realm] - # xcode-version: ${{ fromJSON(needs.prepare.outputs.XCODE_VERSIONS_MATRIX) }} - # configuration: [release, static] - # exclude: - # - platform: osx - # configuration: static - # - platform: tvos - # configuration: static - # - platform: watchos - # configuration: static - # - platform: visionos - # configuration: static - # - platform: catalyst - # configuration: static - # - platform: tvossimulator - # configuration: static - # - platform: watchossimulator - # configuration: static - # - platform: visionossimulator - # configuration: static - # - target: RealmSwift - # configuration: static - # - platform: visionos - # xcode-version: 14.2 - # - platform: visionossimulator - # xcode-version: 14.2 - # - platform: visionos - # xcode-version: 14.3.1 - # - platform: visionossimulator - # xcode-version: 14.3.1 - # - platform: visionos - # xcode-version: 15.1 - # - platform: visionossimulator - # xcode-version: 15.1 - # steps: - # - name: Checkout - # uses: actions/checkout@v4 - # - name: Select Xcode Version - # run: sudo xcode-select -switch /Applications/Xcode_${{ matrix.xcode-version }}.app - # - name: Download visionOS, only for 15.2 - # if: ${{ matrix.platform == 'visionos' || matrix.platform == 'visionossimulator' }} - # run: xcodebuild -downloadPlatform visionOS - # - name: Create framework - # run: sh -x build.sh release-package-build_${{ matrix.platform }}-${{ matrix.target }}-${{ matrix.configuration }} - # - name: Prepare product folder - # run: sh -x build.sh release-package-product - # - name: Upload build product - # uses: actions/upload-artifact@v4 - # with: - # name: product-${{ matrix.platform }}-${{ matrix.xcode-version }}-${{ matrix.target }}-${{ matrix.configuration }} - # path: product-package + name: build-${{ matrix.platform }}-${{ matrix.xcode-version }}-${{ matrix.configuration }} + path: xcode-cloud-build-${{ steps.build-run.outputs.BUILD_RUN_ID }}.zip + compression-level: 0 package-xcframework-platform: # Creates xcframework for each platform and xcode version runs-on: macos-13 name: Package xcframework for platform @@ -254,7 +188,7 @@ jobs: matrix: platform: ${{ fromJSON(needs.prepare.outputs.PLATFORM_MATRIX) }} xcode-version: ${{ fromJSON(needs.prepare.outputs.XCODE_VERSIONS_MATRIX) }} - exclude: + exclude: - platform: visionos xcode-version: 14.2 - platform: visionos @@ -269,10 +203,10 @@ jobs: - name: Restore frameworks uses: actions/download-artifact@v4 with: - pattern: product-${{ matrix.platform }}*-${{ matrix.xcode-version }}-* + pattern: build-${{ matrix.platform }}*-${{ matrix.xcode-version }}-* - name: Create xcframework - run: sh -x build.sh release-create-xcframework_${{ matrix.xcode-version }} ${{ matrix.platform }} - - name: Upload xcframework + 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 }} @@ -301,7 +235,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: realm-swift-${{ needs.prepare.outputs.VERSION }} - path: pkg/realm-swift-${{ needs.prepare.outputs.VERSION }}.zip + path: pkg/realm-swift-${{ needs.prepare.outputs.VERSION }}.zip test-package-examples: runs-on: macos-13 name: Test examples @@ -380,7 +314,7 @@ jobs: mkdir -p build unzip realm-${{ matrix.platform }}-${{ env.TEST_VERSION }}.zip -d build - name: Run installation test - run: | + run: | echo "REALM_TEST_BRANCH=${{ github.ref_name }}" >> $GITHUB_OUTPUT cd examples/installation ./build.rb ${{ matrix.platform }} ${{ matrix.installation }} ${{ matrix.linkage }} @@ -413,4 +347,4 @@ jobs: echo "REALM_TEST_BRANCH=${{ github.ref_name }}" >> $GITHUB_OUTPUT cd examples/installation ./build.rb osx xcframework dynamic - \ No newline at end of file + diff --git a/build.sh b/build.sh index ffb231ca55..f363d17165 100755 --- a/build.sh +++ b/build.sh @@ -88,7 +88,7 @@ command: release-package-docs: build release package the docs release-package-*: build release package for the given platform, configuration and target (this is executed in XCode Cloud) release-create-xcframework_[xcode-version] [platform]: creates an xcframework from the framework build by the previous step - release-package: creates the final packages + release-package: creates the final packages release-package-test-examples: test a built examples release package test-package-release: locally build a complete release package for all platforms @@ -264,7 +264,7 @@ build_platform() { if [[ "$platform" = *"simulator" ]]; then xc -destination "$destination Simulator" "${build_args[@]}" - else + else xc -destination "$destination" "${build_args[@]}" fi @@ -282,63 +282,14 @@ build_platform() { create_xcframework() { local product="$1" - local platform="$2" - local config="$3" - local xcode_version="$4" - - config_name="$(tr [A-Z] [a-z] <<< "$config")" - - local destination build_args config_suffix simulator_suffix - case "$platform" in - osx) - config_suffix= - ;; - ios) - config_suffix=-iphoneos - simulator_suffix=iphonesimulator - ;; - watchos) - config_suffix=-watchos - simulator_suffix=watchsimulator - ;; - tvos) - config_suffix=-appletvos - simulator_suffix=appletvsimulator - ;; - visionos) - config_suffix=-xros - simulator_suffix=xrsimulator - ;; - catalyst) - config_suffix=-maccatalyst - ;; - esac - - product_name="$product.framework" - out_path="$ROOT_WORKSPACE/$config/$platform" - xcframework_path="$out_path/$product.xcframework" - os_path="$ROOT_WORKSPACE/product-$platform-$xcode_version-$product-$config_name/$config${config_suffix}/$product_name" - simulator_path="$ROOT_WORKSPACE/product-${platform}simulator-$xcode_version-$product-$config_name/$config-$simulator_suffix/$product_name" - - simulator_framework=() - if [[ -n "$simulator_suffix" ]]; then - simulator_framework+=(-framework "$simulator_path") - fi - - echo "Creating xcframework from paths $os_path, $simulator_path" - xcodebuild -create-xcframework -allow-internal-distribution -output "$xcframework_path" \ - -framework "$os_path" "${simulator_framework[@]}" -} - -unzip_product() { - file_name="$1" - new_file_name="$2" - - unzip "$file_name.zip" -d $file_name - find product -maxdepth 1 -type d -name "RealmSwift Build*" -exec mv {} $new_file_name \; - - rm $file_name.zip - rm -rf $file_name + local config="$2" + local platform="$3" + + local out_path="$ROOT_WORKSPACE/$config/$platform/$product.xcframework" + # find "$ROOT_WORKSPACE" -maxdepth 5 + find "$ROOT_WORKSPACE" -path "*/$config*/$product.framework" \ + | sed 's/.*/-framework &/' \ + | xargs xcodebuild -create-xcframework -allow-internal-distribution -output "$out_path" } # Artifacts are zipped by the artifacts store so they're endup nested zipped, so we need to unzip this zip. @@ -804,7 +755,7 @@ case "$COMMAND" in REALM_TEST_BRANCH="$sha" ./build.rb "$PLATFORM" cocoapods "$LINKAGE" ;; - "verify-docs") + "verify-docs") sh build.sh docs for lang in swift objc; do undocumented="docs/${lang}_output/undocumented.json" @@ -1130,21 +1081,26 @@ case "$COMMAND" in zip -r docs/realm-docs.zip docs/objc_output docs/swift_output ;; - "release-package-product") - unzip_product product product-package - ;; - - (release-create-xcframework_*) + release-create-xcframework-*) platform="$2" - xcode_version=$(echo "$COMMAND" | cut -d_ -f2 ) + xcode_version=$(echo "$COMMAND" | cut -d- -f4 ) + + # Artifacts are nested zips so need to be extracted twice + find . -name 'build-*.zip' -exec unzip {} \; + find . -name 'xcode-cloud-build-*.zip' -exec unzip {} \; + + # Spaces with xargs are complicated so get rid of them + for dir in "RealmSwift Build "*; do + mv "$dir" build-$(echo "$dir" | cut -d' ' -f3) + done - create_xcframework Realm "$platform" Release "$xcode_version" - create_xcframework RealmSwift "$platform" Release "$xcode_version" + create_xcframework Realm Release "$platform" + create_xcframework RealmSwift Release "$platform" - if [ "$platform" = "ios" ] ; then - create_xcframework Realm "$platform" Static "$xcode_version" + if [ "$platform" = "ios" ]; then + create_xcframework Realm Static "$platform" else - mkdir -p "Static" + mkdir -p "Static/$platform" fi zip --symlinks -r "realm-$platform-$xcode_version.zip" "Release/$platform" "Static/$platform" @@ -1167,7 +1123,7 @@ case "$COMMAND" in cp "$0" "${filename}" cp -r "${source_root}/scripts" "${filename}" cp "dependencies.list" "${filename}" - + cd "${filename}" sh build.sh examples-ios sh build.sh examples-tvos @@ -1187,10 +1143,10 @@ case "$COMMAND" in # Should select xcode version `xcode-select` first. # Pass xcode version as argument # This simulates what is done in XCode Cloud - ("test-create-frameworks") + "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") @@ -1202,7 +1158,7 @@ case "$COMMAND" in ./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 + # 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" @@ -1212,7 +1168,7 @@ case "$COMMAND" in done ;; - ("test-build-product-workflow-xcode-cloud") + "test-build-product-workflow-xcode-cloud") issuer_id="" key_id="" pk_path="" @@ -1220,7 +1176,7 @@ case "$COMMAND" in 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 + # Test parameters platform="ios" target="RealmSwift" xcode_version="15.2" @@ -1252,9 +1208,9 @@ case "$COMMAND" in # Pass xcode version as argument # For this to work, product builds should be located in the root of the project - ("test-create-platform-xcframeworks") + "test-create-platform-xcframeworks") xcode_version="$2" - + platforms=("ios" "osx" "tvos" "watchos" "catalyst") if [ "$xcode_version" == "15.1" ]; then platforms+=("visionos") @@ -1268,7 +1224,7 @@ case "$COMMAND" in done ;; - ("test-package-examples") + "test-package-examples") VERSION="$(sed -n 's/^VERSION=\(.*\)$/\1/p' "${source_root}/dependencies.list")" dir="realm-swift-${VERSION}" @@ -1285,7 +1241,7 @@ case "$COMMAND" in cp -r "${ROOT_WORKSPACE}/dependencies.list" "${dir}" cd "${dir}" - # Test Examples + # Test Examples sh build.sh examples-ios sh build.sh examples-tvos sh build.sh examples-osx @@ -1294,7 +1250,7 @@ case "$COMMAND" in ;; # This is used for test or if we want to use Github Actions to build each framework - (release-package-build_*) + release-package-build_*) filename="Configuration/Release.xcconfig" sed -i '' "s/REALM_HIDE_SYMBOLS = NO;/REALM_HIDE_SYMBOLS = YES;/" "$filename" @@ -1327,11 +1283,11 @@ case "$COMMAND" in "publish-docs") sha="$2" - + ./scripts/github_release.rb download-artifacts realm-docs "${sha}" unzip_artifact realm-docs.zip unzip realm-docs.zip - + VERSION="$(sed -n 's/^VERSION=\(.*\)$/\1/p' "${source_root}/dependencies.list")" PRERELEASE_REGEX='alpha|beta|rc|preview' if [[ $VERSION =~ $PRERELEASE_REGEX ]]; then diff --git a/scripts/xcode_cloud_helper.rb b/scripts/xcode_cloud_helper.rb index 10a3cd506a..064c36a85b 100755 --- a/scripts/xcode_cloud_helper.rb +++ b/scripts/xcode_cloud_helper.rb @@ -132,7 +132,7 @@ 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 @@ -341,9 +341,9 @@ 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| + artifacts.each { |artifact| artifact_info = get_artifact_info(artifact[:id]) - if artifact_info["data"]["attributes"]["fileName"].include? 'Logs' + if artifact_info["data"]["attributes"]["fileName"].include? 'Logs' artifact_url = artifact_info["data"]["attributes"]["downloadUrl"] end } @@ -352,26 +352,26 @@ def get_logs_for_build(build_run) def print_logs(url) sh 'curl', '--output', 'logs.zip', "#{url}" - sh 'unzip', "logs.zip" + sh 'unzip', '-o', 'logs.zip' log_files = Dir["RealmSwift*/*.log"] - log_files.each { |log_file| + 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 - } + 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 } + branch_reference = references["data"].find { |reference| reference["attributes"]["kind"] == "BRANCH" && reference["attributes"]["name"] == branch } end return branch_reference["id"] end @@ -380,21 +380,21 @@ 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| + artifacts.each { |artifact| artifact_info = get_artifact_info(artifact[:id]) - if artifact_info["data"]["attributes"]["fileName"].include? 'Products' + if artifact_info["data"]["attributes"]["fileName"].include? 'Products' artifact_url = artifact_info["data"]["attributes"]["downloadUrl"] end } - sh 'curl', '--output', "product.zip", "#{artifact_url}" + 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 + end } workflows_to_remove.each { |w| delete_workflow(w[:id]) @@ -585,4 +585,4 @@ def usage() get_logs_for_build(build_id) when 'get-token' puts JWT_TOKEN -end \ No newline at end of file +end