跳到主要内容

自动 CI 测试

CI 由 .github/workflows/ci.yml.github/workflows/ci-branch-push.yml.github/workflows/reusable-command.yml 和配套容器镜像共同组成,覆盖测试矩阵、缓存策略和 self-hosted runner 调度。

TGOSKits 将大部分构建与运行依赖收敛到统一的 container 镜像,由 GitHub Actions 和本地开发流程共同消费。需要物理设备、虚拟化能力或专用机器环境的任务则运行在 self-hosted runner 上。

三层架构

层级作用主要入口
Container 镜像固化工具链、QEMU、交叉编译器container/Dockerfilecontainer/Dockerfile.axvisor-lvz
可复用工作流统一在 host 或 container 中执行命令.github/workflows/reusable-command.yml
CI 编排选择测试矩阵、决定何时发布镜像,并路由非主线分支 push.github/workflows/ci.yml.github/workflows/ci-branch-push.yml.github/workflows/container-publish.yml

触发条件

事件说明
pushmain / dev排除纯文档变更(*.mddocs/** 等),其余路径直接触发完整 CI
push 到其他分支先进入 ci-branch-push.yml。若该分支已有 open PR,则 router 成功结束;否则由 router 触发完整 CI
pull_request纯 Markdown 不触发主 CI;其余变更由 planner 按 crate、OS 和 arch 生成增量矩阵
workflow_dispatch默认用于发布容器镜像(base / axvisor-lvz / both);router 也会用 run_target=ci 调度非 PR 分支的完整 CI

dev 分支的 push 和手动触发使用 concurrency.queue: max 串行排队运行,避免多个 dev CI 同时占用 runner。其他分支、main 分支、PR 以及非 dev 手动触发不会进入 dev 队列;新 run 会在最早的 cancel_stale_runs 阶段取消同一分支或同一 PR 上仍在 queued/running 的旧 CI run。

main / dev 分支的 push 由轻量 router 先检查是否已有同仓库、同名分支的 open PR。已有 PR 时不会调度 .github/workflows/ci.yml,router 会输出跳过原因并以成功状态结束,PR 的 pull_request CI 负责验证同一提交。没有 open PR 时,router 使用 workflow_dispatch(run_target=ci) 调度完整 CI,并把 push 事件的 before SHA 传给差异检查。

PR 增量矩阵

只有 pull_request 使用增量矩阵。planner 以 PR base SHA 做三点 diff,忽略 .mdapps/**,并将其余路径映射到最深层 workspace package。随后分别为 aarch64、x86_64、riscv64 和 loongarch64 运行带 --all-features --filter-platform 的 Cargo metadata,通过反向依赖确定 ArceOS、StarryOS 和 AxVisor 的受影响架构。workspace axtest package 还会按其声明的 target 选择承载该测试的 ArceOS job。

非 crate 的已知 OS 配置和 test-suit 文件按目录及配置名映射;只能确定 OS 时运行该 OS 的全部架构。package 删除、未知源码路径、Cargo/toolchain、CI planner/workflow/check manifest、.cargo/** 或任意 xtask 实现变更,以及 diff/metadata 失败,都会回退到当前完整矩阵。回退不会静默缩小覆盖。

每个被选中的 OS/arch 仍执行该矩阵项原有的全部 QEMU、KVM 和板卡命令。apps/** 本身不选择 OS/arch 或 app 运行测试;混合 PR 中的其他改动仍按正常规则选择。static checks 始终保留,workspace Clippy 继续使用 --since,std whitelist 在增量 PR 中使用 cargo xtask test --since <base>pushworkflow_dispatch 不使用该影响分析,保持完整矩阵。

planner 将 changed paths、忽略的 Markdown/apps、changed/affected packages、选中的 OS/arch、选中/跳过的 checks 和全量回退原因写入 Actions job summary。

执行流水线

cancel_stale_runs
|
`-- detect_changes
|
+-- [ci_checks == true]
| `-- static_checks (fmt/publish-dry-run || sync-lint || lock-lint) fail-fast: true
| `-- test_checks (所有测试并发) fail-fast: true
|
`-- [push/dispatch 到 main/dev]
+-- publish_base_container
`-- publish_axvisor_lvz_container 依赖 base 成功后才运行

main / dev 分支 push 会先经过 .github/workflows/ci-branch-push.yml

branch push router
|
+-- [branch has open PR] success summary only
|
`-- [no open PR] workflow_dispatch(run_target=ci) -> ci.yml

static_checks 作为测试矩阵的前置门禁:格式检查、workspace 发布 dry-run、sync-lint 或 lock-lint 不通过时,后续测试不会启动。static_checkstest_checks 都启用 fail-fast: true,任意矩阵项失败会取消同矩阵内其他任务,减少 runner 占用。

变更检测

detect_changes 使用 dorny/paths-filter@v4 判断后续任务是否需要运行:

检测路径触发任务
.cargo/.github/workflows/{ci,ci-branch-push,reusable-command,container-publish}.ymlCargo.tomlCargo.lockrust-toolchain.tomlbootloader/axloader/components/drivers/memory/net/os/platforms/scripts/test-suit/virtualization/xtask/CI 检查
container/Dockerfilerust-toolchain.toml发布基础容器镜像
container/Dockerfile.axvisor-lvzrust-toolchain.toml发布 LVZ 扩展镜像

push 到 main / dev 时强制运行 CI 检查。非 main / dev 分支没有 open PR 时由 router 调度完整 CI;已有 open PR 时只保留一个成功的 router 检查,由 pull request CI 覆盖同一提交。

detect_changes 内部还负责输出跳过原因:

  • Summarize skipped CI checks:说明 CI 检查为什么被跳过。
  • Summarize manual container branch restriction:说明手动容器发布为什么因分支限制被跳过。

Static Checks

static_checks 是并行矩阵,全部通过后才进入 test_checks

Job 名称Runner使用容器Cache Key功能说明
Check formattingself-hosted linux qcs(非 rcore-os 回退到 ubuntu-latest + base 容器)通常否cargo fmt --all -- --checkcargo publish --workspace --dry-run --no-verify
Run sync-lintubuntu-latest是(basecargo xtask sync-lint --since <base>;需要完整 git 历史,并上传编译好的 tg-xtask 供后续容器 job 复用
Run lock-lintubuntu-latest是(basecargo xtask lock-lint,校验统一锁依赖、OS facade 和 runtime provider 约束

Test Checks

test_checks 依赖 static_checks 全部通过后并发执行。

Job 名称Runner使用容器Cache Key功能说明
Run clippyself-hosted linux qcscargo xtask clippy --since <base>;需要完整 git 历史;fork PR 回退到 ubuntu-latest + base 容器
Test with stdself-hosted linux qcs非 PR 或全量回退运行 cargo xtask test;增量 PR 运行 cargo xtask test --since <base>,只保留 affected package 与 scripts/test/std_crates.csv 的交集;fork PR 回退到 ubuntu-latest + base 容器
Test axvisor aarch64 qemuself-hosted linux qcscargo xtask axvisor test qemu --arch aarch64rcore-os 仓库使用 self-hosted,fork PR 回退到 ubuntu-latest + base 容器
Test axvisor riscv64 qemuself-hosted linux qcscargo xtask axvisor test qemu --arch riscv64rcore-os 仓库使用 self-hosted,fork PR 回退到 ubuntu-latest + base 容器
Test axvisor loongarch64 qemuubuntu-latest是(axvisor-lvztest-axvisor-loongarch64cargo xtask axvisor test qemu --arch loongarch64,使用带 LVZ 支持的镜像
Test starry riscv64 qemuubuntu-latest是(basetest-starry-riscv64cargo xtask starry test qemu --arch riscv64
Test starry aarch64 qemuubuntu-latest是(basetest-starry-aarch64cargo xtask starry test qemu --arch aarch64
Test starry loongarch64 qemuubuntu-latest是(basetest-starry-loongarch64cargo xtask starry test qemu --arch loongarch64
Test starry x86_64 qemuubuntu-latest是(basetest-starry-x86_64cargo xtask starry test qemu --arch x86_64
Test arceos x86_64 qemuself-hosted linux qcs先运行 ArceOS Rust/C suite,再以一次 cargo xtask ktest qemu --workspace ... --arch x86_64 串行运行同架构 axtest;仅 rcore-os 仓库触发
Test arceos riscv64 qemuself-hosted linux qcs先运行 ArceOS suite/任务 IPI,再以一次 ktest qemu --arch riscv64 串行运行同架构 axtest;仅 rcore-os 仓库触发
Test arceos aarch64 qemuself-hosted linux qcs先运行 GICv2 SMP4 boot 与 ArceOS suite,再以一次 ktest qemu --arch aarch64 串行运行同架构 axtest;仅 rcore-os 仓库触发
Test arceos loongarch64 qemuself-hosted linux qcs先运行 ArceOS suite,再以一次 ktest qemu --arch loongarch64 串行运行同架构 axtest;仅 rcore-os 仓库触发
Test axvisor self-hosted x86_64(svm)self-hosted linux amd kvmcargo xtask axvisor test qemu --arch x86_64 --test-case smoke-svm;验证 SVM 宿主启动及宿主 NVMe 根文件系统写入/回读,仅 rcore-os 仓库触发
Test axvisor self-hosted x86_64(vmx)self-hosted linux intel kvmcargo xtask axvisor test qemu --arch x86_64 --test-case smoke-vmx;验证 VMX 宿主启动及宿主 NVMe 根文件系统写入/回读,仅 rcore-os 仓库触发
Test axloader HTTP smokeself-hosted linux intel kvm安装 x86_64-unknown-uefi target,通过 Ostool 获取并校验 OVMF,运行 cargo xtask axloader test qemu --target x86_64-unknown-uefi;仅 rcore-os 仓库触发
Test axvisor self-hosted board orangepi-5-plus-linuxself-hosted linux boardcargo xtask axvisor test board --board orangepi-5-plus-linux;物理板卡;仅 rcore-os 仓库触发
Test axvisor self-hosted board orangepi-5-plus-starryself-hosted linux boardcargo xtask axvisor test board --board orangepi-5-plus-starry;物理板卡;仅 rcore-os 仓库触发
Test axvisor self-hosted board roc-rk3568-pc-linuxself-hosted linux boardcargo xtask axvisor test board --board roc-rk3568-pc-linux;物理板卡;仅 rcore-os 仓库触发
Test axvisor self-hosted board phytiumpi-linuxself-hosted linux boardcargo xtask axvisor test board --board phytiumpi-linux;物理板卡;仅 rcore-os 仓库触发
Test starry self-hosted board orangepi-5-plusself-hosted linux boardcargo xtask starry test board --board orangepi-5-plus;物理板卡;仅 rcore-os 仓库触发
Test starry self-hosted board aka-00-sg2002self-hosted linux boardcargo xtask starry test board --board aka-00-sg2002;物理板卡;仅 rcore-os 仓库触发
Test starry self-hosted board visionfive2self-hosted linux boardcargo xtask starry test board --board visionfive2;物理板卡;仅 rcore-os 仓库触发

StarryOS stress 测试条目保留在 workflow 中,但当前处于注释状态。启用后仅用于 target 为 main 的 PR。

Self-Hosted Runner 约定

self-hosted runner 任务优先在 rcore-os 仓库内运行。带 self_hosted_owner 的任务在 fork PR 或非 rcore-os 仓库中会回退到 ubuntu-latest + 对应容器,避免没有对应 runner 时长时间排队。迁移到 self-hosted 的任务直接在原生 runner 环境中运行,不再套 Docker container。

现有 label 约定:

Label用途
self-hosted, linux, qcsclippy、std 测试、ArceOS QEMU 测试、Axvisor aarch64/riscv64 QEMU
self-hosted, linux, intel, kvmAxvisor x86_64 KVM 测试
self-hosted, linux, board物理板卡测试

Cache 策略

Cache Key使用 Job保存时机说明
test-axvisor-loongarch64Test axvisor loongarch64 QEMUpush 事件Axvisor loongarch64 编译产物
test-starry-riscv64/aarch64/loongarch64/x86_64Test starry riscv64/aarch64/loongarch64/x86_64 QEMUpush 事件StarryOS QEMU 编译产物
无(cache_key: ""static checks、self-hosted x86_64/board 类 job-不启用 Swatinem/rust-cache;self-hosted 任务依赖 runner 本地磁盘缓存

self-hosted runner 不设置 cache_key,避免 Swatinem/rust-cache@v2 的 post-job 清理影响 runner 上跨次运行自然积累的共享缓存。

容器镜像

CI 使用两个容器镜像:

镜像Dockerfile用途
basecontainer/Dockerfilesync-lint、StarryOS QEMU,以及 clippy、std、self-hosted QEMU 测试在 fork PR 或非 rcore-os 仓库中的回退环境
axvisor-lvzcontainer/Dockerfile.axvisor-lvzAxvisor loongarch64 QEMU,额外包含 LVZ 支持

基础镜像以 ubuntu:24.04 为底,内置 Rust 工具链、QEMU、musl cross-toolchain、libav、libudev 等依赖。容器内的 musl cross-toolchain 已通过 PATH 配置好,reusable-command.yml 会在 container job 启动时验证 QEMU user emulators 和 musl compiler 是否存在,不再在运行时动态下载。

容器发布

Job 名称Runner触发条件功能说明
Publish base containerubuntu-latestpush 到 main / dev 且基础镜像相关路径变更,或手动选择发布 base / both构建并推送 ghcr.io/<repo>-container:latest
Publish axvisor-lvz containerubuntu-latestpush 到 main / dev 且 LVZ 镜像相关路径变更,或手动选择发布 axvisor-lvz / both构建并推送 ghcr.io/<repo>-container-axvisor-lvz:latest

axvisor-lvz 镜像依赖基础镜像。若同一次运行需要发布基础镜像,LVZ 镜像会等待基础镜像发布成功后再构建。

本地使用预构建镜像

开发者可以直接拉取 CI 使用的预构建镜像:

docker pull ghcr.io/rcore-os/tgoskits-container:latest

docker run -it --rm \
-v "$(pwd)":/workspace \
-w /workspace \
ghcr.io/rcore-os/tgoskits-container:latest

reusable-command.yml

所有 static_checkstest_checks 中的 job 均通过 .github/workflows/reusable-command.yml 执行。该 workflow 根据 inputs.use_container 在两个互斥 job 中选择一个:

Job说明
run_host不使用容器,直接在 runner 原生环境中执行命令
run_container使用指定镜像执行命令,并在启动时验证 QEMU user emulator 和 musl cross-toolchain

runs_on 使用 JSON 字符串输入并通过 fromJson(inputs.runs_on) 转为 GitHub Actions runner label 数组。Rust 编译缓存仅在 cache_key != "" 时启用,push 事件保存,PR 事件只读取不保存。

命名规则

文件类型格式示例
QEMU 配置qemu-{arch}.tomlqemu-aarch64.tomlqemu-x86_64.toml
板级配置board-{board_name}.tomlboard-orangepi-5-plus.toml
构建配置build-{target}.tomlbuild-x86_64-unknown-none.toml
架构缩写完整 Target
x86_64x86_64-unknown-none
aarch64aarch64-unknown-none-softfloat
riscv64riscv64gc-unknown-none-elf
loongarch64loongarch64-unknown-none-softfloat