mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* fix(mobile): break the transport and terminal-document import cycles and gate them after mobile's install client-context re-exported the host-client hooks, which import client-context back: the re-export barrel is gone and importers (and their test mocks) name host-client-hooks directly. In the terminal document, the cell-metric getters move to a leaf cell-metrics module and select-mode entry/exit to selection-mode, so fit, transform, overlay and range no longer import each other. pr.yml lints imports before mobile's install, when mobile's tsconfig can't load, so Mobile verify now runs the same import rules over mobile after its install with zero warnings allowed. * fix(mobile): the browser-pane render harness imports useHostClient from host-client-hooks Its route source is a template string, so no typecheck saw the removed client-context re-export; the mobile web bundle check did. * fix(ci): the e2e typecheck ratchet counts the same with or without mobile's install Specs reach mobile/src/transport, whose expo-crypto and async-storage imports resolve only after mobile's install and then load React Native's globals (numeric timers, a required NODE_ENV), adding errors in unrelated specs. An empty stub pins both, so the static job reads 232 either way.
308 lines
12 KiB
YAML
308 lines
12 KiB
YAML
name: Mobile Checks
|
|
|
|
on:
|
|
pull_request:
|
|
types:
|
|
- opened
|
|
- synchronize
|
|
- reopened
|
|
- ready_for_review
|
|
- converted_to_draft
|
|
paths:
|
|
- 'mobile/**'
|
|
# Why all of src/shared: mobile imports hundreds of its modules, directly and through the RPC
|
|
# recordings and the host params check, so any shared edit can move a golden or break mobile's
|
|
# typecheck. Why the root lockfile: those modules resolve their packages from the root install.
|
|
- 'src/shared/**'
|
|
# Mobile's Node RPC recording tools import this package.
|
|
- 'src/packages/process-host/**'
|
|
- 'pnpm-lock.yaml'
|
|
# Mobile launch contracts exercise the real host dispatcher and durable receipt store.
|
|
- 'src/main/agent-launch/**'
|
|
- 'src/main/runtime/rpc/**'
|
|
- 'src/main/runtime/runtime-rpc/**'
|
|
- 'src/main/runtime/runtime-rpc.ts'
|
|
- 'src/main/runtime/device-registry.ts'
|
|
- 'src/main/runtime/orca-runtime.ts'
|
|
- 'src/main/runtime/agent-session-*.ts'
|
|
- 'src/main/native-chat/agent-session-wire/**'
|
|
- 'src/main/runtime/structured-attention-original-delivery.test-fixture.ts'
|
|
# Why: this job holds the only checks that load the Fastfile, so edits to
|
|
# it or to the release workflow it guards must re-run them.
|
|
- '.github/workflows/mobile.yml'
|
|
- 'config/mobile-ci.vitest.config.mjs'
|
|
- 'config/scripts/run-mobile-ci-tests.mjs'
|
|
- 'config/oxlint-code-quality-native-plugins.json'
|
|
- 'config/.bun-version'
|
|
- '.github/actions/install-node-dependencies/**'
|
|
- '.github/actions/restore-pnpm-verification/**'
|
|
- '.github/workflows/mobile-ios-release.yml'
|
|
- 'config/scripts/mobile-release-check-scope*'
|
|
- 'config/scripts/mobile-test-change-scope*'
|
|
- 'config/scripts/pr-code-change-scope.mjs'
|
|
- 'config/scripts/pr-package-test-paths.mjs'
|
|
- 'config/scripts/pr-layout-oracle-route.mjs'
|
|
# Desktop suites do not feed mobile; keep fixtures and test/toolchain config inputs.
|
|
- '!src/shared/**/*.test.[jt]s'
|
|
- '!src/shared/**/*.test.[jt]sx'
|
|
- '!src/shared/**/*.test.[cm][jt]s'
|
|
- '!src/packages/process-host/**/*.test.[jt]s'
|
|
- '!src/packages/process-host/**/*.test.[jt]sx'
|
|
- '!src/packages/process-host/**/*.test.[cm][jt]s'
|
|
- '!src/main/**/*.test.[jt]s'
|
|
- '!src/main/**/*.test.[jt]sx'
|
|
- '!src/main/**/*.test.[cm][jt]s'
|
|
# Why main too: two pull requests can each pass against their own base and disagree once both
|
|
# land, and `verify` never runs on main. The same source paths as above, less the CI inputs only
|
|
# `verify` reads.
|
|
push:
|
|
branches:
|
|
- main
|
|
paths:
|
|
- 'mobile/**'
|
|
- 'src/shared/**'
|
|
- 'src/packages/process-host/**'
|
|
- 'pnpm-lock.yaml'
|
|
- 'src/main/agent-launch/**'
|
|
- 'src/main/runtime/rpc/**'
|
|
- 'src/main/runtime/runtime-rpc/**'
|
|
- 'src/main/runtime/runtime-rpc.ts'
|
|
- 'src/main/runtime/device-registry.ts'
|
|
- 'src/main/runtime/orca-runtime.ts'
|
|
- 'src/main/runtime/agent-session-*.ts'
|
|
- 'src/main/native-chat/agent-session-wire/**'
|
|
- 'src/main/runtime/structured-attention-original-delivery.test-fixture.ts'
|
|
- '.github/workflows/mobile.yml'
|
|
- 'config/mobile-ci.vitest.config.mjs'
|
|
- 'config/scripts/run-mobile-ci-tests.mjs'
|
|
- 'config/.bun-version'
|
|
# Desktop suites do not feed mobile; keep fixtures and test/toolchain config inputs.
|
|
- '!src/shared/**/*.test.[jt]s'
|
|
- '!src/shared/**/*.test.[jt]sx'
|
|
- '!src/shared/**/*.test.[cm][jt]s'
|
|
- '!src/packages/process-host/**/*.test.[jt]s'
|
|
- '!src/packages/process-host/**/*.test.[jt]sx'
|
|
- '!src/packages/process-host/**/*.test.[cm][jt]s'
|
|
- '!src/main/**/*.test.[jt]s'
|
|
- '!src/main/**/*.test.[jt]sx'
|
|
- '!src/main/**/*.test.[cm][jt]s'
|
|
|
|
concurrency:
|
|
# Per commit on main, not per branch. GitHub cancels any PENDING run in a group when a new one
|
|
# queues, whatever `cancel-in-progress` says, so one shared main group drops the middle merge of
|
|
# three -- and a merge that breaks main there is exactly what `main-tests` checks for.
|
|
group: mobile-${{ github.event.pull_request.number || github.sha }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
verify:
|
|
name: Mobile verify
|
|
if: github.event_name == 'pull_request' && github.event.pull_request.draft != true
|
|
# Why ARM: 209s of this job is Vitest and nothing here needs x86: no Android SDK, emulator, gradle,
|
|
# Hermes or Watchman, no docker, and no artifacts. The Gemfile.lock lists the generic `ruby`
|
|
# platform, so frozen bundler installs without an aarch64-linux entry.
|
|
runs-on: ubuntu-24.04-arm
|
|
|
|
env:
|
|
# Why: an unfrozen bundler silently re-resolves when Gemfile.lock drifts
|
|
# from the Gemfile, which is how the release jobs could land on different
|
|
# fastlane versions in the first place. Fail here instead.
|
|
BUNDLE_FROZEN: 'true'
|
|
ORCA_MOBILE_TYPECHECK_COMPILER: 'native'
|
|
|
|
defaults:
|
|
run:
|
|
working-directory: mobile
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 2
|
|
|
|
- uses: ./.github/actions/install-node-dependencies
|
|
with:
|
|
cache-pnpm-store: 'false'
|
|
cache-dependency-path: |
|
|
pnpm-lock.yaml
|
|
mobile/pnpm-lock.yaml
|
|
|
|
- name: Detect Ruby release inputs
|
|
id: ruby-scope
|
|
shell: bash
|
|
working-directory: .
|
|
run: |
|
|
# Keep deletions when release files move into an application directory.
|
|
if ! git diff --name-only --no-renames -z HEAD^1 HEAD > "$RUNNER_TEMP/mobile-release-changes"; then
|
|
echo 'should_run=true' >> "$GITHUB_OUTPUT"
|
|
elif ! node config/scripts/mobile-release-check-scope.mjs "$RUNNER_TEMP/mobile-release-changes"; then
|
|
echo 'should_run=true' >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
# bundler-cache installs mobile/Gemfile.lock, so this job is also what
|
|
# proves the pinned fastlane the release workflow depends on still
|
|
# resolves — before a release run finds out.
|
|
- name: Setup Ruby and fastlane
|
|
id: ruby-tools
|
|
background: true
|
|
if: steps.ruby-scope.outputs.should_run != 'false'
|
|
uses: ruby/setup-ruby@v1
|
|
with:
|
|
ruby-version: '3.3'
|
|
bundler-cache: true
|
|
working-directory: mobile
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
# Why here: pr.yml runs these import rules before mobile's install, when mobile's tsconfig
|
|
# (which extends expo's) can't load, so its import cycles were never seen. Zero tolerance.
|
|
- name: Lint mobile imports with mobile dependencies installed
|
|
working-directory: .
|
|
run: node node_modules/oxlint/bin/oxlint --config config/oxlint-code-quality-native-plugins.json mobile --deny-warnings
|
|
|
|
# Call installed tools so pnpm's dependency refresh cannot race between checks.
|
|
- name: Typecheck
|
|
id: production-types
|
|
background: true
|
|
env:
|
|
GOMAXPROCS: '2'
|
|
run: node scripts/typecheck-mobile.mjs
|
|
|
|
# Why a ratchet and not the raw typecheck: mobile/tsconfig.json excludes test files, so until
|
|
# tsconfig.test.json existed nothing checked them, and at introduction 127 of the 632 had
|
|
# drifted. This fails when a test file that checks today stops checking, when a test leaves
|
|
# the program, and on @ts-nocheck; the baseline may only shrink.
|
|
- name: Typecheck tests (ratchet)
|
|
id: test-types
|
|
background: true
|
|
env:
|
|
GOMAXPROCS: '2'
|
|
run: node scripts/check-tests-typecheck-ratchet.mjs
|
|
|
|
# This includes the bridged replay of the whole recording corpus, which used to be a second
|
|
# step of its own behind RPC_FOUNDATION_BRIDGE=1. A gate nobody can forget to set is the point:
|
|
# it fails when a divergence class grows, when a divergence lands in no class at all, or when
|
|
# one of the 103 goldens inside the C1 page closure changes the verdict it is pinned to. It is
|
|
# ~3 min of test time on its own, and Vitest runs it on a worker beside the rest of the suite,
|
|
# so folding it in costs a fraction of that in wall time and one step less to skip.
|
|
- name: Detect mobile test inputs
|
|
id: test-scope
|
|
shell: bash
|
|
working-directory: .
|
|
run: |
|
|
if ! git diff --name-only --no-renames -z HEAD^1 HEAD > "$RUNNER_TEMP/mobile-test-changes"; then
|
|
echo 'should_run=true' >> "$GITHUB_OUTPUT"
|
|
elif ! node config/scripts/mobile-test-change-scope.mjs "$RUNNER_TEMP/mobile-test-changes"; then
|
|
echo 'should_run=true' >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Setup Bun for tests
|
|
if: steps.test-scope.outputs.should_run != 'false'
|
|
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
|
with:
|
|
bun-version-file: config/.bun-version
|
|
|
|
- name: Test
|
|
if: steps.test-scope.outputs.should_run != 'false'
|
|
env:
|
|
ORCA_BACKGROUND_LAUNCH: '1'
|
|
run: node ../config/scripts/run-mobile-ci-tests.mjs
|
|
|
|
# All checks read the completed install; compilers need not hold up test workers.
|
|
- wait: [production-types, test-types, ruby-tools]
|
|
|
|
# Reports, never gates: the goldens are content-addressed JSON, so their raw diff is hashes.
|
|
# This decodes which recorded behaviour the pull request moves into the job summary, and runs
|
|
# after a red Test too, when a reviewer most wants it.
|
|
- name: Summarize RPC recording changes
|
|
if: ${{ !cancelled() }}
|
|
continue-on-error: true
|
|
run: pnpm run rpc:diff HEAD^1 --summary "$GITHUB_STEP_SUMMARY"
|
|
|
|
- name: Test iOS release version resolution
|
|
if: steps.ruby-scope.outputs.should_run != 'false'
|
|
run: ruby fastlane/ios_release_version_test.rb
|
|
|
|
- name: Test TestFlight lane arguments
|
|
if: steps.ruby-scope.outputs.should_run != 'false'
|
|
run: ruby fastlane/fastfile_testflight_arguments_test.rb
|
|
|
|
# Why: nothing else in CI loads the Fastfile, so a syntax error, a broken
|
|
# require, or an undefined constant only surfaces mid-release — the
|
|
# ios-distribute job failed every run for six days that way. `lanes` just
|
|
# loads and lists, so it needs no App Store Connect credentials and makes
|
|
# no network calls to Apple.
|
|
- name: Smoke-check the Fastfile
|
|
if: steps.ruby-scope.outputs.should_run != 'false'
|
|
env:
|
|
FASTLANE_SKIP_UPDATE_CHECK: '1'
|
|
FASTLANE_OPT_OUT_USAGE: '1'
|
|
run: bundle exec fastlane lanes
|
|
|
|
- name: Smoke-check CocoaPods
|
|
if: steps.ruby-scope.outputs.should_run != 'false'
|
|
run: bundle exec pod --version
|
|
|
|
- name: Lint
|
|
run: pnpm lint
|
|
|
|
- name: Check formatting
|
|
run: pnpm format:check
|
|
|
|
main-tests:
|
|
name: Mobile tests on main
|
|
env:
|
|
ORCA_MOBILE_TYPECHECK_COMPILER: 'native'
|
|
if: github.event_name == 'push'
|
|
# Why ARM: the same pure-Node Vitest run `verify` makes on a pull request.
|
|
runs-on: ubuntu-24.04-arm
|
|
|
|
defaults:
|
|
run:
|
|
working-directory: mobile
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: ./.github/actions/install-node-dependencies
|
|
with:
|
|
cache-dependency-path: |
|
|
pnpm-lock.yaml
|
|
mobile/pnpm-lock.yaml
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Typecheck
|
|
id: production-types
|
|
background: true
|
|
env:
|
|
GOMAXPROCS: '2'
|
|
run: node scripts/typecheck-mobile.mjs
|
|
|
|
- name: Typecheck tests (ratchet)
|
|
id: test-types
|
|
background: true
|
|
env:
|
|
GOMAXPROCS: '2'
|
|
run: node scripts/check-tests-typecheck-ratchet.mjs
|
|
|
|
# The whole suite, not only the recordings: the mutant and page-bridge suites read the goldens
|
|
# too. A red run here names each golden and the `rpc:record` command; the author of the merge
|
|
# that turned it red re-records in a follow-up.
|
|
- name: Setup Bun for tests
|
|
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
|
with:
|
|
bun-version-file: config/.bun-version
|
|
|
|
- name: Test
|
|
env:
|
|
ORCA_BACKGROUND_LAUNCH: '1'
|
|
run: node ../config/scripts/run-mobile-ci-tests.mjs
|
|
|
|
- wait: [production-types, test-types]
|