From a597673472b6c8264de721c8a6d3a6f79894d8ed Mon Sep 17 00:00:00 2001 From: tianma-if Date: Sun, 20 Sep 2026 22:36:15 +0800 Subject: [PATCH] fix(release): accept Xcode Cloud builds whose iOS tree matches the tag Manual Archive workflows build the default branch, which can move after the Release commit. Compare apps/ios and packages/shared instead of requiring an exact SHA. --- .github/workflows/store-delivery.yml | 12 ++++++++++-- docs/ios-xcode-cloud.md | 8 ++++---- docs/store-delivery.md | 4 ++-- docs/store-delivery.zh-CN.md | 2 +- scripts/store-delivery.test.mjs | 3 ++- scripts/xcode-cloud-control.test.mjs | 2 +- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/.github/workflows/store-delivery.yml b/.github/workflows/store-delivery.yml index 1ba8b1c9..08e53468 100644 --- a/.github/workflows/store-delivery.yml +++ b/.github/workflows/store-delivery.yml @@ -311,15 +311,23 @@ jobs: log_file="$RUNNER_TEMP/xcode-cloud-control.log" # Manual Xcode Cloud workflows reject tags that are not in the start # condition. Start the Archive workflow on its configured default - # (main) and require the immutable Release commit. + # (main) and require the iOS runtime tree to match this Release. python3 .edgeever-ci/scripts/xcode-cloud-control.py start \ - --require-sha "$(git rev-parse HEAD)" \ --wait \ --wait-valid | tee "$log_file" grep -E '^(build_number|app_store_build_id|build_run_id|source_sha|processing_state)=' \ "$log_file" >> "$GITHUB_OUTPUT" test -n "$(grep -E '^build_number=' "$log_file")" + source_sha="$(grep -E '^source_sha=' "$log_file" | tail -1 | cut -d= -f2)" + test -n "$source_sha" + git fetch --no-tags origin "$source_sha" + changed="$(git diff --name-only "$source_sha" HEAD -- apps/ios packages/shared)" + if [[ -n "$changed" ]]; then + echo "Xcode Cloud source $source_sha differs from Release $(git rev-parse HEAD) in iOS runtime files:" >&2 + echo "$changed" >&2 + exit 1 + fi - name: Load App Store release notes id: notes diff --git a/docs/ios-xcode-cloud.md b/docs/ios-xcode-cloud.md index 378418e7..b099e036 100644 --- a/docs/ios-xcode-cloud.md +++ b/docs/ios-xcode-cloud.md @@ -92,10 +92,10 @@ Rules: Formal Releases do this automatically when `apps/ios` or the shared editor runtime changed: `bun run release` bumps `MARKETING_VERSION`, starts the Manual -Xcode Cloud Archive workflow, requires the source commit to match the Release -tag, waits until the build is **Valid**, and submits App Review. The Cloud -workflow stays Manual, so Apple rejects starting it on a tag that is not in -the start condition. +Xcode Cloud Archive workflow, requires the Cloud source to match the Release +tag's iOS runtime tree, waits until the build is **Valid**, and submits App +Review. The Cloud workflow stays Manual, so Apple rejects starting it on a +tag that is not in the start condition. To retry or ship iOS without a new GitHub Release: diff --git a/docs/store-delivery.md b/docs/store-delivery.md index 1673a66e..fd19b327 100644 --- a/docs/store-delivery.md +++ b/docs/store-delivery.md @@ -140,8 +140,8 @@ Native iOS store binaries come from **`apps/ios`** (SwiftUI), not Expo EAS. On macOS beta hosts, archives must go through **Xcode Cloud** so `BuildMachineOSBuild` is a release OS image — see [iOS Xcode Cloud](ios-xcode-cloud.md). The store-delivery workflow starts that -Manual Archive workflow on its configured default branch, requires the source -commit to match the Release tag, waits until App Store Connect marks the +Manual Archive workflow on its configured default branch, requires the Cloud +source to match the Release tag's iOS runtime tree, waits until App Store Connect marks the build Valid, then Fastlane (`apps/ios` `submit_review`) submits App Review and configures automatic release after approval. Pass `--ios-build-number` only to reuse an already uploaded build. Missing metadata, agreements, review diff --git a/docs/store-delivery.zh-CN.md b/docs/store-delivery.zh-CN.md index 39585674..c7a417ae 100644 --- a/docs/store-delivery.zh-CN.md +++ b/docs/store-delivery.zh-CN.md @@ -125,7 +125,7 @@ Release。默认命令直接使用 Production;只有明确要求测试交付 在 macOS beta 本机上,Archive 必须通过 **Xcode Cloud**,保证 `BuildMachineOSBuild` 来自正式系统镜像——见 [iOS Xcode Cloud](ios-xcode-cloud.md)。商店交付工作流会按 Archive 工作流配置的 -默认分支启动这次手动构建,并要求源提交与 Release tag 一致,等到 App Store +默认分支启动这次手动构建,并要求 Cloud 源码与 Release tag 的 iOS 运行时一致,等到 App Store Connect 将构建标为 Valid,再用 Fastlane(`apps/ios` 的 `submit_review`)提交 App Review,并设置为审核通过后自动发布。只有复用已经上传的构建时才传入 `--ios-build-number`。元数据、协议、审核信息或凭据不完整时 diff --git a/scripts/store-delivery.test.mjs b/scripts/store-delivery.test.mjs index 4cb49c60..5f93baea 100644 --- a/scripts/store-delivery.test.mjs +++ b/scripts/store-delivery.test.mjs @@ -76,8 +76,9 @@ describe("store delivery command", () => { ); expect(workflow).toContain(".edgeever-ci/scripts/xcode-cloud-control.py"); expect(workflow).toContain("--wait-valid"); - expect(workflow).toContain("--require-sha"); + expect(workflow).not.toContain("--require-sha"); expect(workflow).not.toContain("--git-ref"); + expect(workflow).toContain("git diff --name-only \"$source_sha\" HEAD -- apps/ios packages/shared"); expect(workflow).toContain("grep -E '^(build_number|app_store_build_id|build_run_id|source_sha|processing_state)='"); expect(workflow).toContain('refs/tags/${RELEASE_TAG}'); expect(workflow).toContain( diff --git a/scripts/xcode-cloud-control.test.mjs b/scripts/xcode-cloud-control.test.mjs index 76bc6ef8..0c959834 100644 --- a/scripts/xcode-cloud-control.test.mjs +++ b/scripts/xcode-cloud-control.test.mjs @@ -27,7 +27,7 @@ describe("Xcode Cloud control", () => { expect(workflow).toContain(".edgeever-ci/scripts/xcode-cloud-control.py"); expect(workflow).toContain("--wait-valid"); - expect(workflow).toContain("--require-sha"); + expect(workflow).toContain("git diff --name-only"); expect(cloudWorkflow).toContain("scripts/xcode-cloud-control.py"); expect(cloudWorkflow).not.toContain("submit-review");