Skip to content

Merge pull request #293 from send/fix/snippet-enter-leak #642

Merge pull request #293 from send/fix/snippet-enter-leak

Merge pull request #293 from send/fix/snippet-enter-leak #642

Workflow file for this run

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