Files
Dante d23cee4c11 fix(hermes): read live WSL databases inside their distribution (#8254)
Windows SQLite cannot reliably read a live Hermes WAL database through a WSL UNC path. For wsl.localhost / wsl$ Hermes paths only, read the database inside the owning distribution via wsl.exe and Python SQLite (mode=ro, query_only, one short read transaction), streaming the result back in bounded JSON frames into the existing session projection. Non-WSL paths and macOS/Linux are unchanged. Requires python3 (3.7+) and timeout inside the distribution. Fixes #8205.
2026-10-17 21:37:51 +08:00

301 lines
11 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
# 每周一次全量:push 到 main 也按路径过滤后,靠它在缓存被淘汰后重新建起来
schedule:
- cron: "41 19 * * 0" # 周一 03:41(北京时间)
workflow_dispatch:
concurrency:
# 带上事件名:定时全量和 push 到 main 都在 refs/heads/main 上,别互相取消
group: ci-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
name: Detect changed areas
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
# 定时 / 手动运行不过滤(过滤步骤被跳过、输出为空),一律当作两边都有改动
frontend: ${{ steps.filter.outputs.frontend || 'true' }}
backend: ${{ steps.filter.outputs.backend || 'true' }}
steps:
# On pull_request the filter reads changed files via the API (no checkout);
# on push it needs a local git history to diff against.
- name: Checkout
if: github.event_name == 'push'
uses: actions/checkout@v6
- name: Detect changed paths
id: filter
if: github.event_name == 'pull_request' || github.event_name == 'push'
uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
with:
filters: |
frontend:
- "src/**"
- "tests/**"
- "index.html"
- "package.json"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "tsconfig.json"
- "tsconfig.node.json"
- "vite.config.ts"
- "vitest.config.ts"
- "tailwind.config.cjs"
- "postcss.config.cjs"
- "components.json"
- ".github/workflows/**"
backend:
- "src-tauri/**"
- "rust-toolchain.toml"
- ".github/workflows/**"
frontend:
name: Frontend Checks
runs-on: ubuntu-latest
needs: changes
# PR 和 push 到 main 都按路径过滤。缓存 key 精确命中时不会重存,main 全量跑并不能
# 预热什么;缓存被淘汰后由每周的定时全量重建。
if: needs.changes.outputs.frontend == 'true'
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "20"
- name: Setup pnpm
env:
COREPACK_ENABLE_DOWNLOAD_PROMPT: "0"
run: |
corepack enable
corepack install
pnpm --version
- name: Get pnpm store directory
id: pnpm-store
shell: bash
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- name: Cache pnpm store
uses: actions/cache@v5
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: ${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: TypeScript type check
run: pnpm typecheck
- name: Check formatting
run: pnpm format:check
- name: Unit tests
run: pnpm test:unit
- name: Build frontend
run: pnpm build:renderer
backend:
name: Backend Checks
runs-on: ${{ matrix.os }}
needs: changes
if: needs.changes.outputs.backend == 'true'
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, windows-latest, macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v6
# rust-toolchain.toml 是编译器版本的唯一来源:直接装它,免得先装 stable 再被 rustup 换掉
- name: Read pinned Rust toolchain
id: rust-toolchain
shell: bash
run: |
channel=$(sed -nE 's/^channel *= *"([^"]+)".*/\1/p' rust-toolchain.toml)
test -n "$channel"
echo "channel=$channel" >> "$GITHUB_OUTPUT"
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ steps.rust-toolchain.outputs.channel }}
components: rustfmt, clippy
- name: Install Linux system deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential pkg-config libssl-dev \
libgtk-3-dev librsvg2-dev libayatana-appindicator3-dev
sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev \
|| sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.0-dev
sudo apt-get install -y --no-install-recommends libsoup-3.0-dev \
|| sudo apt-get install -y --no-install-recommends libsoup2.4-dev
# 只缓存依赖:本仓库的 crate 每次都要重编,缓存它只会让缓存变大、恢复变慢。
# key 自带 OS、rustc 版本和 Cargo.lock;shared-key 让 WSL2 job 能读到 Windows 这份。
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: src-tauri -> target
shared-key: backend
- name: Install cargo-nextest
uses: taiki-e/install-action@e407f7bafb71fd004bc5c2da3032e5470cbb6ef0 # v2.87.24
with:
tool: cargo-nextest
- name: Create frontend dist placeholder
shell: bash
run: mkdir -p dist
- name: Check Rust formatting
run: cargo fmt --check --manifest-path src-tauri/Cargo.toml
- name: Clippy
run: cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warnings
# 每个测试一个进程,单测超时见 src-tauri/.config/nextest.toml。doctest 目前只有两个
# ignored,nextest 不跑 doctest 也不漏。
- name: Run tests
run: cargo nextest run --manifest-path src-tauri/Cargo.toml --profile ci
backend-windows-wsl2:
name: Backend Checks (Windows + WSL2 home)
runs-on: windows-2025
timeout-minutes: 45
needs: changes
if: needs.changes.outputs.backend == 'true'
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Read pinned Rust toolchain
id: rust-toolchain
shell: bash
run: |
channel=$(sed -nE 's/^channel *= *"([^"]+)".*/\1/p' rust-toolchain.toml)
test -n "$channel"
echo "channel=$channel" >> "$GITHUB_OUTPUT"
- name: Setup Rust
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
toolchain: ${{ steps.rust-toolchain.outputs.channel }}
- name: Setup WSL2
uses: Vampire/setup-wsl@d1da7f2c0322a5ee4f24975344f67fc0f5baf364 # v7
with:
distribution: Ubuntu-24.04
wsl-version: 2
additional-packages: python3
# 只恢复不保存:这里只编 lib 测试,若由它先存,同 key 的 Windows 缓存就只剩一小半。
# 完整缓存由 backend 矩阵的 Windows job 保存(同一个 shared-key)。
- name: Restore Rust dependencies
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: src-tauri -> target
shared-key: backend
save-if: false
- name: Create frontend dist placeholder
shell: bash
run: mkdir -p dist
- name: Prepare WSL2-backed test environment
shell: pwsh
run: |
wsl.exe -d Ubuntu-24.04 -- bash -lc "rm -rf /tmp/cc-switch-windows-test-root && mkdir -p /tmp/cc-switch-windows-test-root/{home,temp} && chmod -R 0777 /tmp/cc-switch-windows-test-root"
$testRoot = "\\wsl.localhost\Ubuntu-24.04\tmp\cc-switch-windows-test-root"
$testHome = Join-Path $testRoot "home"
$testTemp = Join-Path $testRoot "temp"
foreach ($path in @($testRoot, $testHome, $testTemp)) {
if (-not (Test-Path -LiteralPath $path)) {
throw "WSL2-backed test path is unavailable: $path"
}
}
"CC_SWITCH_TEST_HOME=$testHome" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"CC_SWITCH_WSL_TEST_DIR=$testRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"CC_SWITCH_WSL_TEST_TEMP=$testTemp" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Compile backend tests with native temp
# link.exe/mt.exe cannot create manifests when TEMP points at a WSL UNC path.
# Record the built test binary path so the run step below can execute
# it directly instead of re-invoking cargo with TEMP on \\wsl.localhost.
env:
TEMP: ${{ runner.temp }}
TMP: ${{ runner.temp }}
shell: pwsh
run: |
$testBinary = cargo test --lib --manifest-path src-tauri/Cargo.toml --no-run --message-format=json |
ForEach-Object {
if ($_ -match '"reason":"compiler-artifact"') {
$artifact = $_ | ConvertFrom-Json
if ($artifact.executable -and $artifact.profile.test -and $artifact.target.name -eq 'cc_switch_lib') {
$artifact.executable
}
}
} | Select-Object -First 1 -Wait
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
if (-not $testBinary) {
throw "cc_switch_lib test binary not found in cargo compiler artifacts"
}
"CC_SWITCH_TEST_EXE=$testBinary" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Run Windows-to-WSL2 filesystem contract
# Run the test binary built in the previous step directly. Invoking cargo
# here with TEMP pointing at a WSL UNC path can re-link the crate, and
# link.exe/mt.exe cannot create manifest temp files on \\wsl.localhost.
shell: pwsh
run: |
$env:TEMP = $env:CC_SWITCH_WSL_TEST_TEMP
$env:TMP = $env:CC_SWITCH_WSL_TEST_TEMP
$testName = "config::tests::atomic_write_replaces_existing_wsl_unc_file"
$testList = & $env:CC_SWITCH_TEST_EXE --list --ignored
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
$expected = "${testName}: test"
if ($testList -notcontains $expected) {
throw "Expected ignored test was not discovered: $testName"
}
& $env:CC_SWITCH_TEST_EXE $testName --ignored --exact --nocapture
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
- name: Run Hermes live WAL reads inside WSL2
env:
CC_SWITCH_WSL_DISTRO: Ubuntu-24.04
shell: pwsh
run: |
$testName = "session_manager::providers::hermes::tests::wsl2_live_wal_readonly_reference"
$testList = & $env:CC_SWITCH_TEST_EXE --list --ignored
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
if ($testList -notcontains "${testName}: test") { throw "Hermes WSL test not discovered" }
& $env:CC_SWITCH_TEST_EXE $testName --ignored --exact --nocapture
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }