diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e45a570..2a62a15 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,13 @@ on: branches: - main pull_request: + workflow_dispatch: + inputs: + include_ipad: + description: Run the milestone iPad UI suites as well + required: true + default: false + type: boolean permissions: contents: read @@ -348,23 +355,43 @@ jobs: include: - suite: external-consumer label: External consumer + ipad: false - suite: quick-start-iphone label: Quick Start iPhone + ipad: false - suite: quick-start-ipad label: Quick Start iPad + ipad: true - suite: host-iphone label: Host App iPhone + ipad: false - suite: host-ipad label: Host App iPad + ipad: true steps: - name: Check out repository + if: >- + ${{ + !matrix.ipad || + (github.event_name == 'workflow_dispatch' && inputs.include_ipad) + }} uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up minimum Xcode 16 environment + if: >- + ${{ + !matrix.ipad || + (github.event_name == 'workflow_dispatch' && inputs.include_ipad) + }} uses: ./.github/actions/setup-minimum-xcode-16 - name: Run ${{ matrix.label }} UI smoke with Xcode 16.0 + if: >- + ${{ + !matrix.ipad || + (github.event_name == 'workflow_dispatch' && inputs.include_ipad) + }} env: POCKETROOT_UI_SUITE: ${{ matrix.suite }} POCKETROOT_UI_FAILURE_ROOT: >- @@ -408,7 +435,12 @@ jobs: esac - name: Upload UI failure diagnostics - if: failure() + if: >- + ${{ + failure() && + (!matrix.ipad || + (github.event_name == 'workflow_dispatch' && inputs.include_ipad)) + }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: pocketroot-ui-failure-${{ matrix.suite }}-${{ github.run_id }}-${{ github.run_attempt }} diff --git a/CHANGELOG.en.md b/CHANGELOG.en.md index a4771e7..39eb545 100644 --- a/CHANGELOG.en.md +++ b/CHANGELOG.en.md @@ -8,6 +8,13 @@ All notable PocketRoot changes are recorded here. Semantic Versioning begins wit ### Changed +- Tiered the CI UI matrix by platform: ordinary PRs and default manual runs + execute the external consumer, Quick Start iPhone, and Host App iPhone; + `main` pushes keep the same routine iPhone baseline. After several larger + feature blocks, or for a release candidate, explicitly add iPad on the target + branch with `workflow_dispatch`/`include_ipad=true`. Small development steps + use targeted tests, so the full platform matrix no longer repeats on every + merge. - Host App Files UI smoke now waits for the expected rename, delete, or share action to enter the accessibility tree after pressing a file or directory. If the first synthesized press does not open the menu, it retries once with diff --git a/CHANGELOG.md b/CHANGELOG.md index 567032a..2aa5d6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ PocketRoot 的重要变化记录在这里,并从首个公开版本开始遵循 ### Changed +- CI UI matrix 改为平台分层:普通 PR 与默认手动运行只执行外部消费者、Quick Start + iPhone 和 Host App iPhone;`main` push 也保持 iPhone 日常基线。完成几个较大功能块 + 或进入发布候选时,通过 `workflow_dispatch` 的 `include_ipad=true` 对目标分支显式补跑 + iPad。开发期小步修改只需定向测试,完整平台矩阵不再随每次合并重复执行。 - Host App 文件 UI smoke 现在会在长按文件或目录后,有界等待预期的重命名、删除或 分享菜单动作进入 accessibility tree;若首次合成长按未打开菜单,会使用重新校验的 App/条目 frame 再试一次,仍失败则带 frame 证据 fail-closed,避免直接点击尚不存在 diff --git a/Docs/Testing.md b/Docs/Testing.md index 528fced..feb2bb5 100644 --- a/Docs/Testing.md +++ b/Docs/Testing.md @@ -568,6 +568,17 @@ RootFS、安装同一 XcodeGen,并取得同一 iOS 18.0 Simulator runtime;jo Simulator/device final-link 并执行 17 项原生 smoke。UI matrix 设置 `fail-fast: false`,分别运行公开 SHA 外部消费者、iPhone/iPad Quick Start 和 iPhone/iPad Host App,因此单路失败不会取消其他证据;每路使用不冲突的失败制品名。 + +CI 按平台分层。普通 `pull_request` 与默认 `workflow_dispatch` 运行公开 SHA 外部消费者、 +Quick Start iPhone 和 Host App iPhone,不为每个日常 UI 改动重复启动 iPad。`main` +分支的 `push` 也保持这三路 iPhone 日常基线。完成几个较大功能块、需要验证里程碑分支, +或进入最终发布候选时,从 Actions 对目标分支手动运行 `CI`,并设置 +`include_ipad=true`,再执行全部五路 UI。开发中的小步修改先运行受影响的定向测试; +完整平台矩阵不再随每次合并重复执行。这一分层只减少重复验证,不降低 iPhone、native、 +构建或发行门禁。 +PR 中仍保留两路 iPad check 名称以兼容既有分支保护,但门控会在 checkout、Xcode/Simulator +安装和 UI smoke 前跳过所有实际步骤。 + 这些 UI job 在 iPhone 16 与 iPad(第 10 代)Simulator 运行最小 Quick Start 的 Files/Terminal 冷启动与 PTY-to-Files 文件闭环,以及 Host App 的 PTY、Files、 Workspace、系统 document picker 导入、share sheet 保存、guest 删除后再次导入并 @@ -614,9 +625,9 @@ runtime 与 device type 重建该临时 Simulator。这些基础设施恢复合 | Package.swift 或 native dependency | `swift test` + Demo build + 两个 arm64 final-link + native smoke | | `Examples/PocketRootDemo/project.yml` 或 Demo | regenerate + Demo build | | smoke App/runner | shell syntax + Simulator smoke + 可用时 signed device smoke | -| Quick Start 入口或示例 | strict iOS build + iPhone/iPad Quick Start UI smoke | +| Quick Start 入口或示例 | strict iOS build + iPhone Quick Start UI smoke;里程碑/发布候选补跑 iPad | | terminal/file browser | terminal tests(含二进制 stdin、原子导入、导出上限)+ strict iOS build + Demo build | -| PTY/SwiftTerm | session/runtime unit + final-link + Host App UI smoke + signed iPhone/iPad lifecycle | +| PTY/SwiftTerm | session/runtime unit + final-link + Host App iPhone UI smoke;里程碑/发布候选补跑 iPad,真机可用时执行 signed lifecycle | | 文档 | `./Scripts/check-docs.sh` | | 发行组成或合规证据 | 生成器测试 + `--check` + 固定 SPDX schema 校验 | | 制品扫描器或 CI 扫描门禁 | Ruby fixture 安全/漂移测试 + 真实 unsigned device App 生成/复验 + 固定 SPDX schema 校验 | diff --git a/Docs/en/Testing.md b/Docs/en/Testing.md index 1025965..eca89cf 100644 --- a/Docs/en/Testing.md +++ b/Docs/en/Testing.md @@ -517,7 +517,23 @@ share-sheet save, guest deletion, re-import, and content-verification UI closure on iPhone 16 and iPad (10th generation) Simulators. The fixture is written to the standalone Host App example's Documents only under the explicit `-PocketRootUITesting` launch argument, without relying on user iCloud or Files -data. Set +data. + +CI is tiered by platform. Ordinary `pull_request` runs and default +`workflow_dispatch` runs execute the public-SHA external consumer, Quick Start +iPhone, and Host App iPhone without starting iPad for every routine UI change. +A `push` to `main` keeps the same three-suite routine iPhone baseline. After +several larger feature blocks, when validating a milestone branch, or for a +final release candidate, manually run `CI` for the target branch in Actions +with `include_ipad=true` to execute all five UI suites. During development, run +only the targeted tests affected by the small change; the full platform matrix +no longer repeats on every merge. This tiering removes duplicate validation +without weakening iPhone, native, build, or release gates. +The two iPad check names remain present on PRs for existing branch-protection +compatibility, but their gate skips every real step before checkout, +Xcode/Simulator installation, or UI smoke. + +Set `POCKETROOT_HOST_UI_DEVICE_TYPE` and `POCKETROOT_HOST_UI_DEVICE_NAME` to select the Simulator created by the runner. Use `POCKETROOT_QUICK_START_UI_DEVICE_TYPE` and @@ -569,8 +585,8 @@ XCFramework, or binary SDK. | Package/native dependency | Package + Demo + both final links + smoke | | `Examples/PocketRootDemo/project.yml` or Demo | Regenerate + Demo build | | smoke | Shell syntax + Simulator smoke + signed-device smoke when available | -| Quick Start entry/example | Strict iOS build + iPhone/iPad Quick Start UI smoke | -| terminal/files UI | Terminal tests + strict iOS build + Host App UI smoke | +| Quick Start entry/example | Strict iOS build + iPhone Quick Start UI smoke; add iPad for milestones/release candidates | +| terminal/files UI | Terminal tests + strict iOS build + Host App iPhone UI smoke; add iPad for milestones/release candidates | | docs | Documentation check | | release composition/compliance evidence | Generator tests + `--check` + pinned SPDX schema validation | | artifact scanner or CI scan gate | Ruby fixture security/drift tests + real unsigned-device App materialize/verify + pinned SPDX schema validation | diff --git a/Tests/Scripts/ReleaseComplianceTests.rb b/Tests/Scripts/ReleaseComplianceTests.rb index 6aacd3c..0a672cd 100644 --- a/Tests/Scripts/ReleaseComplianceTests.rb +++ b/Tests/Scripts/ReleaseComplianceTests.rb @@ -1047,6 +1047,17 @@ def test_minimum_xcode_ci_parallelizes_native_and_ui_coverage .first assert_includes ui_job_header, "timeout-minutes: 60" assert_includes workflow, "fail-fast: false" + assert_includes workflow, "workflow_dispatch:" + assert_includes workflow, "include_ipad:" + assert_includes workflow, "Run the milestone iPad UI suites as well" + assert_equal 4, workflow.scan("!matrix.ipad ||").length + refute_includes workflow, "github.event_name == 'push' ||" + assert_includes( + workflow, + "github.event_name == 'workflow_dispatch' && inputs.include_ipad" + ) + assert_equal 3, workflow.scan("ipad: false").length + assert_equal 2, workflow.scan("ipad: true").length assert_equal( 2, workflow.scan("uses: ./.github/actions/setup-minimum-xcode-16").length