diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..721486d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +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) + # 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. 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) + 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@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') }} + 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 0000000..f6ed82e --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,50 @@ +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@v5 + with: + path: | + build/deps + build/dictionary-sources + 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 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 diff --git a/Core/scripts/check-boundaries.sh b/Core/scripts/check-boundaries.sh index a4fc3e5..16164ab 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 dbe7ede..58894cd 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.