- Makefile:新增 验收数据库(生成→检查→库层全量,前置校验隔离库连接串)、数据库分片、浏览器测试三个入口; 格式写入 末尾就地重新生成;数据库测试 与 验收数据库 统一排除 浏览器/网络;快检 不再静默跳过类型门; 前端旅程 预检补齐四个必需变量;pytest 目标改用仓内解释器(uv run 在嵌套检出会解析到外层环境)。 - 工具/验证锁.py:验证会话持共享锁,写入口用 --执行 在独占锁内落盘,生成/格式写入/索引生成走同一闸门。 - 工具/并行数据库测试.py:按文件分片并行,缺连接串在采集前拒绝。 - 工具/构建编排.py、环境预检.py、构建资源包.py、维护索引.py 与上述口径对齐。 - .gitignore / CI / README / AGENTS:忽略构建产物、CI 与 Makefile 单一口径、README 按实际实现陈述、AGENTS 补日常入口与验证纪律。
128 lines
7.9 KiB
Makefile
128 lines
7.9 KiB
Makefile
export PYTHONPATH := $(CURDIR)/src:$(CURDIR)/工具
|
||
|
||
# 用例与库层直接用仓内解释器:uv run 在嵌套检出里会解析到外层 agent-example/.venv,
|
||
# 那个环境没有 psycopg_pool,库层会以导入失败告终。工具链目标仍走 uv run。
|
||
仓内解释器 := $(CURDIR)/.venv/bin/python
|
||
|
||
# Muse 安装、生成、检查、测试和构建入口。
|
||
# 每个声明命令都必须真实可执行(见 .agent/rules/文档与资源生成.md)。
|
||
|
||
.PHONY: 迁移 前端旅程 快检 索引生成 包验收 安装 格式 格式写入 类型 模块边界 检查 测试 数据库测试 数据库分片 验收数据库 浏览器测试 宿主测试 真实模型测试 前端安装 前端检查 前端测试 生成 构建 资源核对
|
||
|
||
# 安装:建立并锁定 Python 依赖环境
|
||
安装:
|
||
uv sync --group dev
|
||
|
||
前端安装:
|
||
pnpm --dir web install --frozen-lockfile
|
||
|
||
前端检查:
|
||
pnpm --dir web run lint
|
||
pnpm --dir web run typecheck
|
||
pnpm --dir web exec tsc --noEmit --module esnext --moduleResolution bundler --target es2022 --skipLibCheck --typeRoots node_modules/@types --types node ../src/muse/基础设施/宿主/Pi工具桥.ts
|
||
|
||
前端测试:
|
||
pnpm --dir web run test
|
||
|
||
# 浏览器旅程需调用者明确选择真实后端与浏览器;不属于默认离线层。
|
||
前端旅程:
|
||
@test -n "$$MUSE_WORKBENCH_URL" -a -n "$$MUSE_BROWSER_EXECUTABLE" || { echo "缺少明确的 MUSE_WORKBENCH_URL / MUSE_BROWSER_EXECUTABLE" >&2; exit 1; }
|
||
@test -x "$$MUSE_BROWSER_EXECUTABLE" || { echo "MUSE_BROWSER_EXECUTABLE 不是可执行浏览器路径" >&2; exit 1; }
|
||
@test "$$MUSE_ISOLATED_TEST_ENVIRONMENT" = "1" || { echo "缺 MUSE_ISOLATED_TEST_ENVIRONMENT=1(旅程环境在配置加载期强校验)" >&2; exit 1; }
|
||
@test -n "$$MUSE_AUTHOR_PASSWORD_FILE" -a -f "$$MUSE_AUTHOR_PASSWORD_FILE" || { echo "MUSE_AUTHOR_PASSWORD_FILE 必须是可读的绝对路径" >&2; exit 1; }
|
||
pnpm --dir web run test:journey $(参数)
|
||
|
||
# 格式:静态检查(ruff lint + 格式校验;只覆盖新版测试与工具目录)
|
||
新测试目录 := $(shell for d in tests/单元 tests/契约 tests/集成 tests/架构 tests/迁移 tests/端到端 tests/真实调用; do [ -d "$$d" ] && printf '%s ' "$$d"; done)
|
||
新工具目录 := 工具 $(wildcard 数据库/旧库迁移)
|
||
格式:
|
||
uv run --no-sync ruff check src $(新测试目录) tests/conftest.py $(新工具目录)
|
||
uv run --no-sync ruff format --check src $(新测试目录) tests/conftest.py $(新工具目录)
|
||
|
||
# 格式写入:按项目规则实际格式化;格式化同样改源码,就地重新生成,避免之后整层报身份不符
|
||
# 每步用 --执行 在独占锁内完成:检查通过后到写入前不再有可被验证会话插入的窗口。
|
||
格式写入:
|
||
uv run --no-sync python 工具/验证锁.py --执行 uv run --no-sync ruff check --fix src $(新测试目录) tests/conftest.py $(新工具目录)
|
||
uv run --no-sync python 工具/验证锁.py --执行 uv run --no-sync ruff format src $(新测试目录) tests/conftest.py $(新工具目录)
|
||
$(MAKE) 生成
|
||
|
||
# 类型:pyright 类型检查
|
||
类型:
|
||
uv run --no-sync pyright
|
||
|
||
# 模块边界:固定执行架构门禁,不继承调用者的 pytest 筛选条件。
|
||
模块边界:
|
||
PYTEST_ADDOPTS= $(仓内解释器) -m pytest tests/架构/test_模块依赖.py -m "not 安装包" -q
|
||
|
||
# 检查:格式 + 类型 + 模块边界 + 索引核对的统一入口
|
||
检查: 格式 类型 模块边界
|
||
uv run --no-sync python 工具/维护索引.py --检查
|
||
|
||
# 测试:默认离线(按标记剔除外部环境用例;未标记用例在 socket 防护下运行)
|
||
# 用法:make 测试 全部离线用例
|
||
# make 测试 用例=TC-a5c7d4adafe3 按稳定用例 ID 选择
|
||
测试:
|
||
$(仓内解释器) -m pytest -m "not 数据库 and not 网络 and not 真实模型 and not 浏览器 and not 宿主 and not 安装包" $(范围) $(if $(用例),--case $(用例),)
|
||
|
||
# 验收数据库:改完源码后唯一该跑的全量入口。先生成、再门禁、最后跑库,
|
||
# 顺序由目标固定,避免“改了 src 没重新生成”这类整轮作废。
|
||
验收数据库:
|
||
@test -n "$$MUSE_TEST_DATABASE_URL" || { echo "缺少 MUSE_TEST_DATABASE_URL(隔离库连接串);拒绝先付生成与门禁成本再失败" >&2; exit 1; }
|
||
$(MAKE) 生成
|
||
$(MAKE) 检查
|
||
$(仓内解释器) -m pytest --外部环境 -m "数据库 and not 宿主 and not 真实模型 and not 浏览器 and not 网络" $(范围)
|
||
|
||
# 数据库分片:发现与修复期用分片并行,全量只跑一次做最终判定
|
||
数据库分片:
|
||
$(仓内解释器) 工具/并行数据库测试.py --片数 $(if $(片数),$(片数),3) $(范围)
|
||
|
||
# 数据库测试:需要 MUSE_TEST_DATABASE_URL;缺失即失败,不静默跳过。
|
||
# 与 验收数据库 同口径排除 浏览器/网络:浏览器用例另有 浏览器测试 入口,不该在这里被静默 skip。
|
||
数据库测试:
|
||
@test -n "$$MUSE_TEST_DATABASE_URL" || { echo "缺少 MUSE_TEST_DATABASE_URL(隔离库连接串);拒绝静默跳过" >&2; exit 1; }
|
||
$(仓内解释器) -m pytest --外部环境 -m "数据库 and not 宿主 and not 真实模型 and not 浏览器 and not 网络" $(范围) $(if $(用例),--case $(用例),)
|
||
|
||
# 浏览器测试:需要隔离库与显式浏览器路径;11 个 数据库+浏览器 用例的唯一入口。
|
||
# MUSE_ISOLATED_TEST_ENVIRONMENT 由本目标声明:Playwright 配置加载期就要求它,缺了连 spec 都跑不到。
|
||
浏览器测试:
|
||
@test -n "$$MUSE_TEST_DATABASE_URL" -a -n "$$MUSE_BROWSER_EXECUTABLE" || { echo "缺少隔离库或 MUSE_BROWSER_EXECUTABLE" >&2; exit 1; }
|
||
MUSE_RUN_BROWSER=1 MUSE_ISOLATED_TEST_ENVIRONMENT=1 $(仓内解释器) -m pytest --外部环境 -m "浏览器 and not 宿主 and not 真实模型" $(范围)
|
||
|
||
真实模型测试:
|
||
@test -n "$$MUSE_TEST_DATABASE_URL" -a -n "$$MUSE_REAL_MODEL_URL" -a -n "$$MUSE_REAL_MODEL_KEY_FILE" || { echo "缺少隔离库或真实模型地址/凭据文件"; exit 1; }
|
||
$(仓内解释器) -m pytest --外部环境 -m 真实模型 --timeout=300
|
||
|
||
宿主测试:
|
||
@test -n "$$MUSE_TEST_DATABASE_URL" -a -n "$$MUSE_PI_NODE" -a -n "$$MUSE_PI_PACKAGE" || { echo "缺少隔离库或固定Pi/Node路径"; exit 1; }
|
||
$(仓内解释器) -m pytest --外部环境 -m 宿主
|
||
|
||
# 迁移:对配置指向的目标库执行显式迁移(维护命令,不在启动时自动执行)
|
||
迁移:
|
||
uv run --no-sync python -m muse 迁移 $(配置)
|
||
|
||
# 快检只检查指定Python源码/测试;不构建资源或前端。
|
||
# 范围写成具体路径(如 `范围=src/muse/元数据`、`范围=tests/单元`):
|
||
# 含非测试路径就跑类型门,含测试路径才跑用例门;范围缺省时按源码 + 单元/契约用例。
|
||
快检:
|
||
uv run --no-sync ruff check $(if $(范围),$(范围),src tests 工具)
|
||
uv run --no-sync ruff format --check $(if $(范围),$(范围),src tests 工具)
|
||
$(if $(范围),$(if $(filter-out tests/%,$(范围)),uv run --no-sync pyright,:),uv run --no-sync pyright)
|
||
$(if $(filter tests/%,$(范围)),$(仓内解释器) -m pytest -m "not 数据库 and not 网络 and not 真实模型 and not 浏览器 and not 宿主 and not 安装包" $(filter tests/%,$(范围)) $(if $(用例),--case $(用例),),$(if $(范围),:,$(仓内解释器) -m pytest -m "not 数据库 and not 网络 and not 真实模型 and not 浏览器 and not 宿主 and not 安装包" tests/单元 tests/契约 $(if $(用例),--case $(用例),)))
|
||
|
||
索引生成:
|
||
uv run --no-sync python 工具/验证锁.py --执行 uv run --no-sync python 工具/维护索引.py --写入
|
||
|
||
# 聚合入口按内容哈希增量执行;wheel必须与同次资源输入绑定。
|
||
生成:
|
||
uv run --no-sync python 工具/验证锁.py --执行 uv run --no-sync python 工具/构建编排.py
|
||
|
||
构建:
|
||
uv run --no-sync python 工具/构建编排.py --wheel
|
||
|
||
包验收:
|
||
uv run --no-sync python 工具/验收安装包.py $(包)
|
||
|
||
# 资源核对:安装包内资源与清单哈希一致
|
||
资源核对:
|
||
uv run --no-sync python -c "from muse.资源加载 import 核对资源; m = 核对资源(); print('资源清单发布身份:', m['发布身份'], '条目数:', len(m['资源']))"
|