From 31a93c6842f8784fbeaa6b73a184c952d639244e Mon Sep 17 00:00:00 2001 From: kdletters Date: Tue, 21 Jul 2026 18:12:43 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E9=BD=90Gitea=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E9=97=A8=E7=A6=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 拆分前端后端与原生壳测试任务 接入server-rs正式workspace全量测试 修正过期Rust断言和Vitest遗漏路径 将AI游戏创作分支纳入CI触发范围 --- .gitea/workflows/project-ci.yml | 36 +++++++++++++++---- .../shared-memory/development-workflow.md | 8 ++--- ...发运维】本地开发验证与生产运维-2026-05-15.md | 13 +++---- .../src/external_generation_worker.rs | 4 +-- .../crates/api-server/src/runtime_profile.rs | 4 +-- .../tests/generated_asset_sheets.rs | 6 ++-- vitest.config.ts | 2 ++ 7 files changed, 49 insertions(+), 24 deletions(-) diff --git a/.gitea/workflows/project-ci.yml b/.gitea/workflows/project-ci.yml index a6844ad08..d519e74b8 100644 --- a/.gitea/workflows/project-ci.yml +++ b/.gitea/workflows/project-ci.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - codex/ai-game-creator-app pull_request: workflow_dispatch: @@ -97,9 +98,6 @@ jobs: - name: Run repository lint gates run: npm run lint - - name: Run frontend and script tests - run: npm run test - - name: Build web applications run: npm run build @@ -115,8 +113,28 @@ jobs: git cat-file -e "${base_ref}^{commit}" git diff --check "${base_ref}"...HEAD - backend-checks: - name: Backend checks + frontend-tests: + name: Frontend tests + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + persist-credentials: false + + - name: Set up Node.js 22 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: '22' + + - name: Install npm dependencies + run: npm ci + + - name: Run frontend and script tests + run: npm run test + + backend-tests: + name: Backend tests runs-on: ubuntu-latest steps: - name: Checkout full history @@ -144,6 +162,7 @@ jobs: clang \ cmake \ curl \ + ffmpeg \ libclang-dev \ libcurl4-openssl-dev \ libssl-dev \ @@ -202,14 +221,17 @@ jobs: - name: Check server-rs boundaries run: npm run check:server-rs-ddd + - name: Run server-rs workspace tests + run: cargo test --locked --workspace --no-fail-fast --manifest-path server-rs/Cargo.toml + - name: Check api-server targets run: cargo check --locked -p api-server --all-targets --manifest-path server-rs/Cargo.toml - name: Check SpacetimeDB module run: cargo check --locked -p spacetime-module --manifest-path server-rs/Cargo.toml - native-shell-checks: - name: Native shell checks + native-shell-tests: + name: Native shell tests runs-on: ubuntu-latest steps: - name: Checkout full history diff --git a/docs/project-memory/shared-memory/development-workflow.md b/docs/project-memory/shared-memory/development-workflow.md index 535861061..dc8ea1061 100644 --- a/docs/project-memory/shared-memory/development-workflow.md +++ b/docs/project-memory/shared-memory/development-workflow.md @@ -264,12 +264,12 @@ npm run check:server-rs-ddd ## Gitea CI 与 PR 检查 -- 仓库 CI 入口是 `.gitea/workflows/project-ci.yml`,向 `master` 推送和所有 PR 创建、更新时必须运行,也允许手工触发。 -- CI 固定拆分为 `Repository checks`、`Backend checks`、`Native shell checks` 三个 required job;对应 PR context 完整名称是 `Project CI / Repository checks (pull_request)`、`Project CI / Backend checks (pull_request)`、`Project CI / Native shell checks (pull_request)`,首次运行后仍须从 Gitea 最近一周 context 表复核。前两项覆盖仓库/Web 与后端边界/编译,原生壳验收单独运行以便定位重型构建失败。 -- 三个 job 共同覆盖 `npm run check`,并追加 `npm run check:server-rs-ddd`、`cargo check -p api-server --all-targets --manifest-path server-rs/Cargo.toml` 和 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`。 +- 仓库 CI 入口是 `.gitea/workflows/project-ci.yml`,向 `master`、`codex/ai-game-creator-app` 推送和所有 PR 创建、更新时必须运行,也允许手工触发。 +- CI 固定拆分为 `Repository checks`、`Frontend tests`、`Backend tests`、`Native shell tests` 四个 required job;对应 PR context 完整名称是 `Project CI / Repository checks (pull_request)`、`Project CI / Frontend tests (pull_request)`、`Project CI / Backend tests (pull_request)`、`Project CI / Native shell tests (pull_request)`,首次运行后仍须从 Gitea 最近一周 context 表复核。测试使用独立 job,不能只藏在综合检查 step 中;原生壳验收单独运行以便定位重型构建失败。 +- 四个 job 共同覆盖 `npm run check`,并追加 `npm run check:server-rs-ddd`、`cargo test --locked --workspace --no-fail-fast --manifest-path server-rs/Cargo.toml`、`cargo check -p api-server --all-targets --manifest-path server-rs/Cargo.toml` 和 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`。后端 runner 安装 `ffmpeg`,避免视频抽帧测试因工具缺失提前返回。`codex/ai-game-creator-app` 分支的原生壳入口还必须覆盖 `npm run ai-game-creator-shell:check` 和 release build smoke。 - checkout 必须使用完整历史。PR 将 base SHA 写入 `SPACETIME_SCHEMA_BASE_REF`,直接推送 `master` 使用 before SHA;事件基线不可解析时直接失败。Gitea 检查的是 PR head 而非预合并 commit,workflow 必须拒绝不包含最新 base commit 的过期 PR,分支保护同时保持“PR 过期禁止合并”。 - 普通 PR job 不读取业务 secret,不运行真实 API/SpacetimeDB/OSS/支付/生成/live smoke,也不执行会修改外部状态的维护、迁移、发布或备份命令。 -- Gitea 至少升级到 `1.26.4` 后才能注册执行 PR job 的 runner;`ubuntu-latest` 标签只映射到固定 digest 的 Ubuntu 24.04 级 Docker/临时隔离镜像,不使用浮动镜像 tag,不映射 host,不向 job 暴露 Docker socket、业务 secret 或不必要内网。runner 能访问 Gitea、GitHub Actions 与 `actions/node-versions`、nodejs.org、npm、Rust 分发和 crates.io;workflow 的官方 action 固定完整 commit,若内网禁用 GitHub,先在当前 Gitea 镜像对应 commit 并改用绝对 URL。受控镜像优先预装 rustup。Gitea 1.26 的任务超时由 runner 全局配置控制;首次运行成功后,`master` 分支保护必须要求上述三个 job 全部成功。 +- Gitea 至少升级到 `1.26.4` 后才能注册执行 PR job 的 runner;`ubuntu-latest` 标签只映射到固定 digest 的 Ubuntu 24.04 级 Docker/临时隔离镜像,不使用浮动镜像 tag,不映射 host,不向 job 暴露 Docker socket、业务 secret 或不必要内网。runner 能访问 Gitea、GitHub Actions 与 `actions/node-versions`、nodejs.org、npm、Rust 分发和 crates.io;workflow 的官方 action 固定完整 commit,若内网禁用 GitHub,先在当前 Gitea 镜像对应 commit 并改用绝对 URL。受控镜像优先预装 rustup。Gitea 1.26 的任务超时由 runner 全局配置控制;首次运行成功后,`master` 分支保护必须要求上述四个 job 全部成功。 ## 后端相关默认验证 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index 4b9cf53cd..18c85ddcb 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -200,19 +200,20 @@ npm run check ### Gitea Actions PR 门禁 -仓库级 Gitea Actions 工作流固定为 `.gitea/workflows/project-ci.yml`,在向 `master` 推送、创建或更新 PR,以及手工触发时运行。工作流拆成三个必须通过的 job: +仓库级 Gitea Actions 工作流固定为 `.gitea/workflows/project-ci.yml`,在向 `master` 或 `codex/ai-game-creator-app` 推送、创建或更新 PR,以及手工触发时运行。工作流拆成四个必须通过的 job: -- `Repository checks`:执行 `npm run lint`、完整 Vitest、主站与后台生产构建、内容数据检查和提交差异空白检查。 -- `Backend checks`:执行 `npm run check:server-rs-ddd`、`api-server --all-targets` 编译和 `spacetime-module` 编译。 -- `Native shell checks`:独立执行 `npm run check:native-shells`,覆盖微信壳、Expo 和 Tauri 的完整验收,并确认 Tauri `Cargo.lock` 没有被构建过程改写,避免把重型原生壳或依赖锁漂移隐藏在基础检查末尾。 +- `Repository checks`:执行 `npm run lint`、主站与后台生产构建、内容数据检查和提交差异空白检查。 +- `Frontend tests`:独立执行根 `npm run test`,让 Vitest 文件数和测试数在 Gitea job 列表中明确可见。 +- `Backend tests`:执行 `npm run check:server-rs-ddd`、`cargo test --locked --workspace --no-fail-fast`、`api-server --all-targets` 编译和 `spacetime-module` 编译;runner 安装 `ffmpeg`,避免视频抽帧测试因工具缺失提前返回。依赖真实服务或密钥的测试必须显式 `ignored`,不能让普通 PR job访问现场环境。 +- `Native shell tests`:独立执行 `npm run check:native-shells`,覆盖微信壳、Expo 和 Tauri 的完整验收,并确认 Tauri `Cargo.lock` 没有被构建过程改写,避免把重型原生壳或依赖锁漂移隐藏在基础检查末尾。`codex/ai-game-creator-app` 分支的同名脚本还会执行 `npm run ai-game-creator-shell:check` 和 AI 游戏创作壳 release build smoke。 -三个 job 合起来覆盖根 `npm run check`,并补齐根检查没有包含的 server-rs DDD 与现役后端编译门禁。普通 PR CI 不注入业务密钥,不启动真实 API、SpacetimeDB、OSS、支付、图片生成或生产 live smoke;需要现场环境、可变外部状态、Docker 编排或发布凭据的 `check:*` 继续按对应专题和 Jenkins 发布流程执行,不能遍历所有同名前缀脚本冒充 PR 门禁。 +四个 job 合起来覆盖根 `npm run check`,并补齐根检查没有包含的 server-rs DDD、正式 workspace Rust 测试与现役后端编译门禁。普通 PR CI 不注入业务密钥,不启动真实 API、SpacetimeDB、OSS、支付、图片生成或生产 live smoke;需要现场环境、可变外部状态、Docker 编排或发布凭据的 `check:*` 继续按对应专题和 Jenkins 发布流程执行,不能遍历所有同名前缀脚本冒充 PR 门禁。 PR checkout 必须保留完整 Git 历史,并把 PR base SHA 传给 `SPACETIME_SCHEMA_BASE_REF`。`check:spacetime-schema` 依赖该基线识别已有表字段删除、改名、重排和改类型;事件给出的基线缺失或本地不可解析时必须直接失败,不能退化为空差异检查。Gitea 的 PR checkout 是 PR head,不是与目标分支的预合并 commit,因此 workflow 还会验证 PR head 包含事件中的最新 base commit;分支保护必须继续开启“PR 过期禁止合并”,过期分支先更新再重跑。向 `master` 直接推送时使用 push before SHA,手工触发时回退到 `origin/master`。 启用或注册执行 PR job 的 runner 前,Gitea 服务端必须至少升级到 `1.26.4`;不得在 `1.26.2` 上执行不受信任 PR 代码。runner 必须提供 `ubuntu-latest` 标签,并将其映射到经验证且固定 digest 的 Ubuntu 24.04 级 Docker/临时隔离镜像;禁止使用浮动镜像 tag,禁止将该标签映射到 host 执行器,禁止向 job 暴露 Docker socket、业务环境变量、业务密钥或不必要的内网。workflow 会安装 Node 22、仓库 `rust-toolchain.toml` 固定的 Rust 1.96.0,以及 clang/lld 和 Tauri Linux 依赖;受控 runner 镜像应预装 rustup,fallback 下载只用于首次引导。runner 仍需能访问 Gitea、GitHub Actions 与 `actions/node-versions`、nodejs.org、npm registry、Rust 分发和 crates.io。workflow 中的 `actions/checkout` / `actions/setup-node` 固定到完整 commit;内网 runner 不允许访问 GitHub 时,先把对应 commit 镜像到当前 Gitea 并把 workflow 改为绝对 action URL。首版不使用 Actions cache,避免未配置 runner cache 网络时把缓存恢复错误变成 PR 失败。Gitea 1.26 不执行 workflow 的 `timeout-minutes`,任务最长运行时间在 runner 全局配置收口,不能只在 YAML 写一个不会生效的超时值。 -workflow 首次成功运行后,在 Gitea `master` 分支保护中把 `Project CI / Repository checks (pull_request)`、`Project CI / Backend checks (pull_request)`、`Project CI / Native shell checks (pull_request)` 三个完整 context 都设为合并必需检查,并从最近一周已上报 context 表复核名称后再保存。不能只填裸 job 名,否则无法匹配 Gitea 实际上报的 ` / ()`。只提交 workflow 文件不会自动创建 runner,也不会自动修改分支保护;如果 Actions 长时间停留在等待状态,先到仓库或组织的 Actions runner 页面确认存在在线、带 `ubuntu-latest` 标签的 runner。 +workflow 首次成功运行后,在 Gitea `master` 分支保护中把 `Project CI / Repository checks (pull_request)`、`Project CI / Frontend tests (pull_request)`、`Project CI / Backend tests (pull_request)`、`Project CI / Native shell tests (pull_request)` 四个完整 context 都设为合并必需检查,并从最近一周已上报 context 表复核名称后再保存。不能只填裸 job 名,否则无法匹配 Gitea 实际上报的 ` / ()`。只提交 workflow 文件不会自动创建 runner,也不会自动修改分支保护;如果 Actions 长时间停留在等待状态,先到仓库或组织的 Actions runner 页面确认存在在线、带 `ubuntu-latest` 标签的 runner。 视觉小说负向扫描与验收门禁: diff --git a/server-rs/crates/api-server/src/external_generation_worker.rs b/server-rs/crates/api-server/src/external_generation_worker.rs index ea682e4a1..4280c81ae 100644 --- a/server-rs/crates/api-server/src/external_generation_worker.rs +++ b/server-rs/crates/api-server/src/external_generation_worker.rs @@ -1702,8 +1702,8 @@ mod tests { serde_json::from_str(&editor_generation_result_payload_json(&job, &response)) .expect("worker 结果应是合法 JSON"); - assert_eq!(payload["sourceModule"], json!("puzzle")); - assert_eq!(payload["sourceEntityId"], json!("session-1:puzzle-level-1")); + assert_eq!(payload["sourceModule"], json!("editor")); + assert_eq!(payload["sourceEntityId"], json!("project-1")); assert_eq!( payload["warning"], json!({ diff --git a/server-rs/crates/api-server/src/runtime_profile.rs b/server-rs/crates/api-server/src/runtime_profile.rs index c25ba1f81..58bbdcfe8 100644 --- a/server-rs/crates/api-server/src/runtime_profile.rs +++ b/server-rs/crates/api-server/src/runtime_profile.rs @@ -2682,7 +2682,7 @@ mod tests { } #[tokio::test] - async fn profile_play_stats_requires_authentication() { + async fn retired_profile_play_stats_route_is_not_mounted() { let app = build_router(AppState::new(AppConfig::default()).expect("state should build")); let response = app @@ -2696,7 +2696,7 @@ mod tests { .await .expect("request should succeed"); - assert_eq!(response.status(), StatusCode::UNAUTHORIZED); + assert_eq!(response.status(), StatusCode::NOT_FOUND); } #[tokio::test] diff --git a/server-rs/crates/platform-image/tests/generated_asset_sheets.rs b/server-rs/crates/platform-image/tests/generated_asset_sheets.rs index 83f5edc31..d3bc61705 100644 --- a/server-rs/crates/platform-image/tests/generated_asset_sheets.rs +++ b/server-rs/crates/platform-image/tests/generated_asset_sheets.rs @@ -198,7 +198,7 @@ fn generated_asset_sheet_muted_green_alpha_requires_explicit_option() { } #[test] -fn generated_asset_sheet_magenta_key_preserves_green_white_and_disconnected_key_subject() { +fn generated_asset_sheet_magenta_key_preserves_subject_and_removes_internal_hole() { let mut sheet = RgbaImage::from_pixel(28, 28, Rgba([255, 0, 255, 255])); for y in 6..22 { for x in 6..14 { @@ -227,8 +227,8 @@ fn generated_asset_sheet_magenta_key_preserves_green_white_and_disconnected_key_ assert_eq!(cleaned.get_pixel(18, 8).0[3], 255); assert_eq!( cleaned.get_pixel(13, 13).0[3], - 255, - "非边缘连通的 key 色像素不应被当成背景清掉" + 0, + "达到阈值的主体内部 key 色镂空区域应被清理" ); } diff --git a/vitest.config.ts b/vitest.config.ts index e9eeeb49d..b3035b116 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -20,6 +20,7 @@ export default defineConfig({ 'src/services/activeAppTitle.test.ts', 'src/services/authService.test.ts', 'src/services/apiClient.test.ts', + 'src/services/clipboard.test.ts', 'src/services/host-bridge/**/*.test.ts', 'src/services/image-editor/**/*.test.ts', 'src/services/external-generation/**/*.test.ts', @@ -43,6 +44,7 @@ export default defineConfig({ 'src/components/platform-entry/PlatformProfileWalletLedgerModal.test.tsx', 'src/components/platform-entry/platformProfile*.test.ts', 'src/components/platform-entry/usePlatformProfileCenterController.test.tsx', + 'src/hooks/useHostNavigationCanGoBack.test.tsx', 'apps/admin-web/src/**/*.test.ts', 'apps/admin-web/src/**/*.test.tsx', 'miniprogram/**/*.test.js',