Merge pull request #293 from send/fix/snippet-enter-leak #642
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| permissions: | |
| contents: read | |
| jobs: | |
| changes: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| core: ${{ steps.filter.outputs.core }} | |
| session: ${{ steps.filter.outputs.session }} | |
| ffi: ${{ steps.filter.outputs.ffi }} | |
| cli: ${{ steps.filter.outputs.cli }} | |
| corpus: ${{ steps.filter.outputs.corpus }} | |
| swift: ${{ steps.filter.outputs.swift }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| filters: | | |
| core: | |
| - 'engine/crates/lex-core/**' | |
| - 'engine/Cargo.toml' | |
| - 'engine/Cargo.lock' | |
| - 'engine/deny.toml' | |
| - 'engine/quarantine-allowlist.toml' | |
| - 'engine/build-script-baseline.txt' | |
| - 'scripts/check-quarantine.sh' | |
| - 'scripts/check-build-scripts.sh' | |
| - 'engine/supply-chain/**' | |
| - '.github/workflows/ci.yml' | |
| session: | |
| - 'engine/crates/lex-session/**' | |
| ffi: | |
| - 'engine/src/**' | |
| cli: | |
| - 'engine/crates/lex-cli/**' | |
| corpus: | |
| - 'engine/testcorpus/**' | |
| - 'engine/data/mozc-pin.txt' | |
| - 'mise.toml' | |
| swift: | |
| - 'Sources/**' | |
| - 'Tests/**' | |
| - 'Info.plist' | |
| # Supply-chain screening. Runs the quarantine / build.rs baseline checks | |
| # BEFORE any job that invokes cargo on the PR's dependency graph: cargo | |
| # compiles and executes dependency build scripts, so every cargo-invoking | |
| # job below `needs: screen` (test-* inherit it through lint). Unconditional | |
| # (no `if`) on purpose — a path-filtered screen would have to hand-maintain | |
| # the union of all dependents' conditions, and a skipped needs-job skips its | |
| # dependents. | |
| screen: | |
| needs: changes | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # needed for quarantine diff against main | |
| - uses: dtolnay/rust-toolchain@stable | |
| # Deliberately NO rust-cache here: Swatinem/rust-cache runs an unlocked | |
| # `cargo metadata` for its cache key, which would silently repair an | |
| # out-of-sync Cargo.lock before the --locked screen below could reject | |
| # it. This job only runs metadata (no build), so the cache buys little. | |
| - name: Quarantine check (7-day) | |
| run: bash scripts/check-quarantine.sh | |
| - name: build.rs baseline check | |
| run: bash scripts/check-build-scripts.sh | |
| lint: | |
| needs: [changes, screen] | |
| if: >- | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.session == 'true' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.cli == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy, rustfmt | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: engine | |
| - run: cd engine && cargo fmt --all --check | |
| - run: cd engine && cargo clippy --workspace --all-features -- -D warnings | |
| msrv: | |
| needs: [changes, screen] | |
| if: >- | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.session == 'true' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.cli == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Enforce the declared MSRV. Keep this version in sync with | |
| # `rust-version` in engine/Cargo.toml ([workspace.package]): a dependency | |
| # bump or code change that needs a newer Rust fails here even though every | |
| # other job builds on stable. Default features only — the optional | |
| # `neural` feature pulls candle, whose MSRV is tracked separately. | |
| - uses: dtolnay/rust-toolchain@1.88.0 | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: msrv | |
| - run: cd engine && cargo check --workspace --locked | |
| test-core: | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.core == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: engine | |
| - run: cd engine && cargo test -p lex-core --features trace,neural | |
| test-session: | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.core == 'true' || needs.changes.outputs.session == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: engine | |
| - run: cd engine && cargo test -p lex-session --features trace | |
| test-engine: | |
| needs: [changes, lint] | |
| if: >- | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.session == 'true' || | |
| needs.changes.outputs.ffi == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: engine | |
| - run: cd engine && cargo test -p lex_engine --features trace | |
| test-cli: | |
| needs: [changes, lint] | |
| if: needs.changes.outputs.core == 'true' || needs.changes.outputs.cli == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: engine | |
| - run: cd engine && cargo test -p lex-cli | |
| # Conversion accuracy gate: builds the full dictionary (Mozc snapshot + | |
| # bundled symbols/extras) and runs both accuracy corpora. The Mozc snapshot | |
| # is pinned to the commit in engine/data/mozc-pin.txt (the corpus filter | |
| # includes the pin file, so a pin bump re-runs this gate), which keeps the | |
| # gate deterministic — upstream Mozc moving can never turn main red, and | |
| # local `mise run accuracy` measures against the identical snapshot. The | |
| # raw snapshot (~90MB of TSVs) is kept in the actions cache; the dictool | |
| # fetch stamp (commit SHA + manifest, PR #266) decides on every run whether | |
| # the cached snapshot matches the pin, repairs it, or transactionally | |
| # re-downloads it — so a stale cache entry can never poison the dict. | |
| # No `lint` dependency: a corpus-only change must not be skipped just | |
| # because the Rust lint job didn't run. `screen` IS required — this job | |
| # builds dictool, which executes dependency build scripts. | |
| accuracy: | |
| needs: [changes, screen] | |
| if: >- | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.cli == 'true' || | |
| needs.changes.outputs.corpus == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| # Separate shared-key: this job builds the release profile (dictool / | |
| # lextool), which the debug-profile `engine` cache never contains. | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: accuracy | |
| - uses: jdx/mise-action@v2 | |
| with: | |
| install: false | |
| # Restore/save split keyed on the pinned SHA itself (not a hash of the | |
| # whole pin file, so comment-only edits don't churn cache entries): | |
| # exactly one cache entry per pinned Mozc snapshot. On an exact hit, dictool's | |
| # stamp check confirms the restored snapshot matches the pin without a | |
| # single network call. On a pin bump the exact key misses and | |
| # restore-keys falls back to the newest previous snapshot, which | |
| # dictool then transactionally replaces with the newly pinned one — | |
| # the stamp mechanism (PR #266) makes any stale restore safe. The save | |
| # step below only fires on that exact-key miss (first run, or the pin | |
| # changed). | |
| - name: Read pinned Mozc SHA | |
| id: mozc-pin | |
| run: | | |
| # Lowercase to match dictool's pin normalization — a case-variant | |
| # pin line must map to the same cache key. | |
| sha=$(grep -oE -m1 '^[[:space:]]*[0-9a-fA-F]{40}[[:space:]]*$' engine/data/mozc-pin.txt | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' || true) | |
| if [ -z "$sha" ]; then | |
| echo "::error file=engine/data/mozc-pin.txt::no 40-hex SHA line found in the pin file" >&2 | |
| exit 1 | |
| fi | |
| echo "sha=$sha" >> "$GITHUB_OUTPUT" | |
| - name: Restore Mozc dictionary snapshot | |
| id: mozc-restore | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: engine/data/mozc-raw | |
| key: mozc-raw-${{ steps.mozc-pin.outputs.sha }} | |
| restore-keys: | | |
| mozc-raw- | |
| # GITHUB_TOKEN: Actions runners share the anonymous GitHub API quota | |
| # (60 req/h per IP), which is effectively always exhausted. dictool | |
| # attaches the token to api.github.com requests when set. With the pin, | |
| # the API is only consulted at all when the restored snapshot doesn't | |
| # match the pin (Contents API listing for the re-download). | |
| - name: Run accuracy corpus | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: mise run accuracy | |
| - name: Run accuracy-history corpus | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: mise run accuracy-history | |
| - name: Save Mozc dictionary snapshot | |
| if: steps.mozc-restore.outputs.cache-hit != 'true' | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: engine/data/mozc-raw | |
| key: mozc-raw-${{ steps.mozc-pin.outputs.sha }} | |
| audit: | |
| needs: [changes, screen] | |
| if: needs.changes.outputs.core == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: engine | |
| - name: Install audit tools | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-deny,cargo-vet,cargo-machete | |
| # Screening (quarantine / build.rs baseline) lives in the `screen` job, | |
| # which gates this and every other cargo-invoking job. | |
| - name: Verify Cargo.lock is in sync | |
| run: cd engine && cargo check --locked | |
| - name: cargo deny (advisories, licenses, sources, bans) | |
| run: cd engine && cargo deny check | |
| - name: cargo vet (audit tracking) | |
| run: cd engine && cargo vet check | |
| - name: Unused dependencies | |
| run: cd engine && cargo machete | |
| swift: | |
| needs: [changes, screen] | |
| if: >- | |
| needs.changes.outputs.core == 'true' || | |
| needs.changes.outputs.session == 'true' || | |
| needs.changes.outputs.ffi == 'true' || | |
| needs.changes.outputs.swift == 'true' | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-apple-darwin, aarch64-apple-darwin | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: engine -> target | |
| shared-key: engine | |
| - uses: jdx/mise-action@v2 | |
| with: | |
| install: false | |
| - run: mise run test-swift |