From 796841cfed9270e0becb270d8a264d232013e98d Mon Sep 17 00:00:00 2001 From: Xiaoyu Guan Date: Thu, 8 Oct 2026 11:57:12 +0800 Subject: [PATCH 1/3] ci: add minimal GitHub Actions for PRs and main Ubuntu jobs run the standalone shared-core boundary check, evaluate the root manifest, run the portable cargo test and the remote-runner tests. A macos-26 job runs test.sh quick and skips docs-only changes. check-boundaries.sh falls back to swift when xcrun is absent. Refs #52 Co-Authored-By: Claude Fable 5.1 --- .github/workflows/ci.yml | 61 ++++++++++++++++++++++++++++++++ .github/workflows/macos.yml | 43 ++++++++++++++++++++++ Core/scripts/check-boundaries.sh | 5 +-- macOS/TESTING.md | 2 ++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/macos.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..13c654f6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + boundaries: + name: Shared-core boundaries + runs-on: ubuntu-24.04 + container: swift:6.2-noble + timeout-minutes: 15 + steps: + - uses: actions/checkout@v5 + - name: Install python3 + run: command -v python3 || (apt-get update && apt-get install -y --no-install-recommends python3) + - name: Check shared-core boundaries + run: bash Core/scripts/check-boundaries.sh --standalone + # `swift build` of the root package needs macOS: InkFlowDomain imports CryptoKit, + # the app targets import AppKit/InputMethodKit, Sparkle ships as an xcframework and + # librime is a macOS dylib, so no root target compiles on Linux. This step only + # evaluates the root manifest; the macOS workflow compiles the root products that + # `test.sh quick` needs. + - name: Evaluate the root manifest + run: swift package dump-package > /dev/null + + portable: + name: Portable runtime (cargo test) + runs-on: ubuntu-24.04 + timeout-minutes: 45 + steps: + - uses: actions/checkout@v5 + # Same CMake/Ninja releases as the Mac runner (Core/Portable/README.md). + - name: Install CMake and Ninja + run: pipx install cmake==3.31.6 && pipx install ninja==1.11.1.4 + - name: Cache the native runtime build + uses: actions/cache@v4 + with: + path: build/portable + key: portable-${{ runner.os }}-${{ hashFiles('Core/Portable/native-sources.lock.json', 'Core/Portable/build-native.py', 'Core/Portable/native/**', 'Core/Portable/Cargo.lock', 'rust-toolchain.toml') }} + restore-keys: portable-${{ runner.os }}- + # rustup picks the pinned toolchain from rust-toolchain.toml. + - name: Build the native runtime and run cargo test + run: bash Core/Portable/test.sh + + scripts: + name: Remote runner tests + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v5 + - name: Test scripts/mac-remote.py + run: python3 -B scripts/tests/test_mac_remote.py diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml new file mode 100644 index 00000000..2f4ab061 --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,43 @@ +name: macOS + +# Docs-only changes must not spend macOS minutes. +on: + push: + branches: [main] + paths-ignore: ['**.md', 'docs/**'] + pull_request: + paths-ignore: ['**.md', 'docs/**'] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + quick: + # Only the quick group. `test.sh all` stays a manual release step. + name: test.sh quick + runs-on: macos-26 + timeout-minutes: 60 + steps: + - uses: actions/checkout@v5 + # dependencies.sh verifies every archive by SHA-256, so a stale cache only + # costs a re-download. rime-cache is keyed by prepare-rime.sh's own input digest. + - name: Cache librime, dictionaries and prepared Rime data + uses: actions/cache@v4 + with: + path: | + build/deps + build/dictionary-sources + build/rime-cache + key: macos-inputs-${{ hashFiles('macOS/scripts/dependencies.sh', 'Core/**', 'schemas/**') }} + restore-keys: macos-inputs- + - name: Run the quick units + run: | + set -o pipefail + bash macOS/scripts/test.sh quick 2>&1 | tee build/test-quick.log + - name: Name the failed unit + if: failure() + run: grep -E '^FAIL ' build/test-quick.log | sed 's/^/::error title=test.sh quick::/' || true diff --git a/Core/scripts/check-boundaries.sh b/Core/scripts/check-boundaries.sh index a4fc3e5d..16164abe 100755 --- a/Core/scripts/check-boundaries.sh +++ b/Core/scripts/check-boundaries.sh @@ -3,17 +3,18 @@ set -euo pipefail cd "$(dirname "$0")/../.." scratch=$(mktemp -d "${TMPDIR:-/tmp}/inkflow-core-boundaries.XXXXXX") trap 'rm -rf "$scratch"' EXIT +swift=(swift); ! command -v xcrun >/dev/null || swift=(xcrun swift) export CLANG_MODULE_CACHE_PATH="$PWD/build/core-swiftpm/module-cache" export SWIFTPM_MODULECACHE_OVERRIDE="$CLANG_MODULE_CACHE_PATH" args=(--disable-sandbox --scratch-path "$PWD/build/core-boundary-swiftpm" --cache-path "$PWD/build/core-swiftpm/cache" --config-path "$PWD/build/core-swiftpm/config" --security-path "$PWD/build/core-swiftpm/security") # dump-package evaluates declarations only; it does not resolve the root's external dependencies. if [[ "${1:-}" != --standalone ]]; then - xcrun swift package "${args[@]}" dump-package > "$scratch/root.json" + "${swift[@]}" package "${args[@]}" dump-package > "$scratch/root.json" else printf 'null\n' > "$scratch/root.json" fi -xcrun swift package --package-path Core "${args[@]}" dump-package > "$scratch/core.json" +"${swift[@]}" package --package-path Core "${args[@]}" dump-package > "$scratch/core.json" python3 - "$PWD" "$scratch/root.json" "$scratch/core.json" <<'PY' import json from pathlib import Path diff --git a/macOS/TESTING.md b/macOS/TESTING.md index dbe7ede0..58894cd4 100644 --- a/macOS/TESTING.md +++ b/macOS/TESTING.md @@ -20,6 +20,8 @@ bash Core/scripts/test.sh # standalone Core package, no app build `dictionary-worker`, `dictionary-activation`, `personal-data` and `termination` need a current `build.sh` app. The runner stops at the first failing unit; fix it and rerun that unit. +GitHub Actions runs `test.sh quick` on a `macos-26` runner for every pull request and push to `main` (docs-only changes skip it). The ubuntu jobs run the shared-core boundary check, the portable `cargo test` and the remote-runner tests. + ## What the units cover - `engine-*`: editing, candidate indexes, exact-once commit, English admission/ranking, context reranking, input options, custom phrases. From 7743b58a8bf0ec1c5558f9b2a6c65c9ef7bdb5a7 Mon Sep 17 00:00:00 2001 From: Xiaoyu Guan Date: Thu, 8 Oct 2026 12:00:51 +0800 Subject: [PATCH 2/3] ci: run the full boundary check and create build/ before tee Refs #52 Co-Authored-By: Claude Fable 5.1 --- .github/workflows/ci.yml | 13 ++++++------- .github/workflows/macos.yml | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13c654f6..9c00d2f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,15 +22,14 @@ jobs: - uses: actions/checkout@v5 - name: Install python3 run: command -v python3 || (apt-get update && apt-get install -y --no-install-recommends python3) - - name: Check shared-core boundaries - run: bash Core/scripts/check-boundaries.sh --standalone + # The full check also dumps the root manifest and asserts root/core parity; the + # dump evaluates declarations only, so Sparkle is never resolved here. # `swift build` of the root package needs macOS: InkFlowDomain imports CryptoKit, # the app targets import AppKit/InputMethodKit, Sparkle ships as an xcframework and - # librime is a macOS dylib, so no root target compiles on Linux. This step only - # evaluates the root manifest; the macOS workflow compiles the root products that - # `test.sh quick` needs. - - name: Evaluate the root manifest - run: swift package dump-package > /dev/null + # librime is a macOS dylib, so no root target compiles on Linux. The macOS + # workflow compiles the root products that `test.sh quick` needs. + - name: Check shared-core boundaries and root/core parity + run: bash Core/scripts/check-boundaries.sh portable: name: Portable runtime (cargo test) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 2f4ab061..98fc5542 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -37,6 +37,7 @@ jobs: - name: Run the quick units run: | set -o pipefail + mkdir -p build bash macOS/scripts/test.sh quick 2>&1 | tee build/test-quick.log - name: Name the failed unit if: failure() From 5dc545cfd6be6e943cd13ca68c7e84330a775b8d Mon Sep 17 00:00:00 2001 From: Xiaoyu Guan Date: Thu, 8 Oct 2026 12:08:16 +0800 Subject: [PATCH 3/3] ci: skip ai-runtime on the macOS runner and record unit timings AIRuntimeTests checks 500 ms debounce deadlines at 540 ms; shared macOS runners miss that margin. The job summary now lists END/FAIL lines. Refs #52 Co-Authored-By: Claude Fable 5.1 --- .github/workflows/ci.yml | 2 +- .github/workflows/macos.yml | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c00d2f7..721486dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: - name: Install CMake and Ninja run: pipx install cmake==3.31.6 && pipx install ninja==1.11.1.4 - name: Cache the native runtime build - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/portable key: portable-${{ runner.os }}-${{ hashFiles('Core/Portable/native-sources.lock.json', 'Core/Portable/build-native.py', 'Core/Portable/native/**', 'Core/Portable/Cargo.lock', 'rust-toolchain.toml') }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 98fc5542..f6ed82ea 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -26,7 +26,7 @@ jobs: # dependencies.sh verifies every archive by SHA-256, so a stale cache only # costs a re-download. rime-cache is keyed by prepare-rime.sh's own input digest. - name: Cache librime, dictionaries and prepared Rime data - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | build/deps @@ -34,11 +34,17 @@ jobs: build/rime-cache key: macos-inputs-${{ hashFiles('macOS/scripts/dependencies.sh', 'Core/**', 'schemas/**') }} restore-keys: macos-inputs- + # The `quick` group minus `ai-runtime`: AIRuntimeTests asserts debounce deadlines + # with 40 ms margins (500 ms sleep, checked at 540 ms), which shared macOS runners + # do not hold. Keep this list in step with `quick` in macOS/scripts/test.sh. - name: Run the quick units run: | set -o pipefail mkdir -p build - bash macOS/scripts/test.sh quick 2>&1 | tee build/test-quick.log - - name: Name the failed unit - if: failure() - run: grep -E '^FAIL ' build/test-quick.log | sed 's/^/::error title=test.sh quick::/' || true + bash macOS/scripts/test.sh engine-basic engine-options engine-english engine-context controller settings quality-store 2>&1 | tee build/test-quick.log + - name: Record unit timings and name the failed unit + if: always() + run: | + [[ -f build/test-quick.log ]] || exit 0 + { echo '```'; grep -E '^(END|FAIL) ' build/test-quick.log; echo '```'; } >> "$GITHUB_STEP_SUMMARY" + grep -E '^FAIL ' build/test-quick.log | sed 's/^/::error title=test.sh quick::/' || true