Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,45 @@ jobs:
# 散文改动跳过整条 Linux 构建与打包链;输出缺失/未知时退回 full。
scope: ${{ needs.changes.outputs.linux == 'false' && 'none' || 'full' }}

native-capsule:
# The capsule crates compile into the desktop shells, so a break there would
# otherwise only surface inside the long Tauri matrix. They are checked on
# both desktop platforms inside this workflow rather than in a second
# workflow: one run per pull request, one `Changed areas` gate, one cache
# policy.
needs: [changes]
if: needs.changes.outputs.tauri != 'false'
name: Native capsule (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 25
defaults:
run:
working-directory: openless-all/app
steps:
- uses: actions/checkout@v4
with:
submodules: false
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
with:
# Stable prefix per platform instead of the job name, so renaming or
# splitting the job keeps the tree.
shared-key: native-capsule
workspaces: openless-all/app -> target
# Pull requests restore the beta tree and never write their own copy:
# `refs/pull/<n>/merge` scopes are never restored again and only evict
# the branch caches (see docs/ci-trigger-and-cache-policy.md).
save-if: ${{ github.ref == 'refs/heads/beta' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
- run: cargo check --locked -p openless-native-capsule
- run: cargo test --locked -p openless-capsule --features ui,host
- run: cargo clippy --locked -p openless-native-capsule -p openless-capsule --features openless-capsule/ui,openless-capsule/host -- -D warnings

cross-platform:
needs: [changes]
# 失败即运行:只有判定脚本明确说“够不到”才跳过。
Expand Down
24 changes: 0 additions & 24 deletions .github/workflows/native-capsule.yml

This file was deleted.

1 change: 1 addition & 0 deletions docs/ci-trigger-and-cache-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ GitHub 每仓库保留 10 GB 缓存,超出按 LRU 静默淘汰;淘汰后 job
- `build-linux-egui` 保留 PR 内自写并开 `cache-on-failure: true`:失败的运行也会把依赖缓存存下来,下一次迭代仍然热;同时关掉 dev/test debug info,缓存更小、链接更快。
- key 结构为 `v0-rust-<job>-<os>-<环境哈希>-<lockfile哈希>`:环境哈希含工具链与 `CARGO_PROFILE_*`,所以 stable / MSRV / release 天然分开,不要用跨平台 `shared-key` 混合。
- `Cargo.lock` 变化时精确键失效,但 `restore-keys` 前缀回退会拿到同前缀的旧缓存,所以“锁变了”不等于“全冷”——前提是那份没被淘汰,这正是要守预算的原因。
- 原生胶囊(`native-capsule` job)原本是一个**独立的** `pull_request`-only workflow:它写的缓存落在 `refs/pull/<n>/merge`,而那是一个**此后再也不会被恢复**的作用域,等于每个 PR 白写一份依赖树;同时 beta 上没有任何 job 产出同 key 的树,所以 PR 永远冷启动。现在它已并入 `ci.yml`(同一个 `Changed areas` 门禁、同一次运行),用 `shared-key: native-capsule` 做稳定前缀、`save-if` 只在 beta 写,PR 只读。

## 4. 维护

Expand Down
26 changes: 25 additions & 1 deletion openless-all/app/scripts/ci-cache-sharing.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// Runs without `npm ci` (the Linux contract job has no node_modules), so the
// workflows are read as text.
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { existsSync, readFileSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

Expand All @@ -22,6 +22,7 @@ const release = read('release-tauri.yml');
const androidApk = read('android-apk.yml');
const linux = read('check-linux-egui.yml');
const linuxRelease = read('release-linux-egui.yml');
const releaseHarmony = read('release-harmony.yml');

const sharedKeys = (yaml) =>
[...yaml.matchAll(/shared-key:\s*([^\s#]+)/g)].map((match) => match[1].trim());
Expand Down Expand Up @@ -61,3 +62,26 @@ assert.match(linuxRelease, /release_tag: \$\{\{ inputs\.tag \}\}/);
assert.match(linuxRelease, /checkout_ref: \$\{\{ inputs\.tag \}\}/);

console.log('ci-cache-sharing contract test passed');

// `native-capsule` used to be a separate pull-request-only workflow: it wrote a
// dependency tree under `refs/pull/<n>/merge` (never restored again) while beta
// produced nothing to restore. It now lives in this workflow, gated by the same
// `Changed areas` verdict, and saves only from beta.
{
const capsuleJob = ci.match(/\n native-capsule:[\s\S]*?(?=\n [a-z-]+:\n)/)?.[0] ?? '';
assert.ok(capsuleJob, 'ci.yml must run the capsule crates as the native-capsule job');
assert.match(
capsuleJob,
/shared-key: native-capsule/,
'the native-capsule job must use a stable shared-key instead of the job name',
);
assert.match(
capsuleJob,
/save-if: \$\{\{ github\.ref == 'refs\/heads\/beta'/,
'the native-capsule job must only save its cache from beta',
);
assert.ok(
!existsSync(join(root, '.github/workflows/native-capsule.yml')),
'native-capsule.yml must stay merged into ci.yml',
);
}
Loading