Files
sap-cli-skill/openspec/spec-coverage-report.md
吴让宇 c5905a5b1e refactor: 本仓升为唯一源(原 sap-cli 源码仓归档)
方向反转:此前 SKILL.md 是「模板渲染产物」、sap-cli 是源;现 sap-cli 归档,
sap-cli-skill 承接开发与分发,SKILL.md 回归手工维护的正本。

迁移(来自 sap-cli,共 104 文件):
- tests/           692 例测试(15 个文件的内联 sys.path 改指 assets/)
- openspec/        SDD 规格与归档变更(42 文件)
- docs/            开发文档与 ADT 原理(含 dev/CLAUDE.md、AGENTS.md)
- .claude/         rules 副本 + settings.json(供 Claude Code)
- .github/ .hermes/ .pre-commit-config.yaml .editorconfig CLAUDE.md
- scripts/ 保持仅 setup.py(pack_skill.py 已随旧仓归档,不迁)

修复(迁移暴露的真实缺陷):
- assets/pyproject.toml 的 build-backend 写作 `setuptools.backends._legacy:_Backend`,
  该模块在 setuptools 中不存在 → `pip install -e` 从来装不上。改为 build_meta。
  实测:临时 venv 安装成功,sap-cli --help 正常列出 31 个命令
- pyproject readme 指向不存在的 assets/README.md(editable 安装会失败)→ 改内联文本
- pyproject urls 改指 sap-cli-skill

机制调整:
- .github/workflows/ci.yml 适配 assets/ 布局;顶部注明该工作流仅 GitHub 执行,
  本仓在 Gitee 不会自动跑
- pre-commit 增本地测试门禁(Gitee 上真正生效的那道)
- .gitignore 合并旧仓完整规则(保留 log/ 下 md 知识库入库,只忽略运行日志)
- 大文件上限 100KB→1MB(架构图 512KB)

守卫测试 tests/unit/test_repo_guards.py(10 → 18 例):
- SKILL.md 须记录 parser 全部 CLI 命令 / 铁律 1-5 须为真实小节标题 / 示例不得违反铁律 5
- references/ 规则齐备;.claude/rules 与 references 必须一致(实测抓到一次真实漂移)
- VERSION == sapcli.__version__ == README 版本
- 仓内不得再出现 pack_skill.py / skill-src(防废弃流程回潮)

698 tests OK;editable 安装与 CLI 入口经临时 venv 实测通过。
docs/RELEASING.md 重写为单源开发流程。
2026-09-11 00:40:15 +08:00

15 KiB
Raw Permalink Blame History

Spec-to-Code 需求覆盖验证报告

生成时间: 2026-06-09 对照 openspec/specs/ 下 7 个 spec 文件 vs sapcli/ 源码


1. Connection (connection/spec.md)

# Scenario 状态 说明
1.1 Successful login 已实现 client.py:login() 使用 HTTP Basic Authapp.py:101-102 打印"登录成功"
1.2 Login failure 已实现 client.py:62 raise LoginErrorapp.py:144-146 捕获 SapCliError 以非零退出码退出
1.3 Config not found 已实现 config.py:25-29 SAPConfig.__post_init__ 检查缺失字段抛 ConfigErrorapp.py:91-95 打印缺失提示和环境变量名称
1.4 Load from config file 已实现 config.py:32-49 搜索并读取 config.ini
1.5 Environment variable override 已实现 config.py:53-57 os.environ.get("SAP_XXX", sap.get(...)) 环境变量优先
1.6 Profile selection (--profile) 未实现 parser.py:69 定义了 --profile 参数,但 config.py:51 硬编码 cfg["SAP"],未使用 args.profile
1.7 Client number default "100" 已实现 config.py:55 sap.get("client", "100")
1.8 Custom config path (--config) 已实现 parser.py:67 + app.py:88 传入 args.config
1.9 No command specified 已实现 app.py:77-79 检测 not args.command 打印帮助并以 exit(1) 退出

小计: 8/9 , 1


2. Object Lifecycle (object-lifecycle/spec.md)

# Scenario 状态 说明
2.1 Create with default template ⚠️部分实现 crud.py:31-58 仅有 report/class/function/interface 四种模板,其他 12 种类型无默认模板
2.2 Create with custom source file 已实现 crud.py:690-695 --source 参数读取文件
2.3 Create DDIC with --definition 已实现 crud.py:771-876 domain/dataelement/table/structure/tabletype 有 JSON→XML 转换
2.4 Create message class 未实现 types.py 未注册 messageclass 对象类型,无法 create/download/info/delete
2.5 Create database view 未实现 types.py 未注册 view 对象类型
2.6 Create search help 未实现 types.py 未注册 searchhelp 对象类型
2.7 Create lock object 未实现 types.py 未注册 lockobject 对象类型
2.8 Create already existing object 已实现 crud.py:642-644 检测 object_exists 后抛 ObjectAlreadyExistsError
2.9 Create with --corr_nr 已实现 parser.py:110 + crud.py:652-655 传入传输请求号
2.10 Download existing object 已实现 crud.py:73-122 完整实现,文件名小写+.abap
2.11 Download non-existent object 已实现 crud.py:95-98 检测不存在抛 ObjectNotFoundError
2.12 Download function type (group/module) 已实现 types.py:152-167 解析 组名/模块名 格式
2.13 Download type without source 已实现 crud.py:82-85 检测 src_uri is None 报错
2.14 Download view DDL source 未实现 view 类型未在 types.py 注册
2.15 Full sync success (lock→write→unlock→check→activate) 已实现 crud.py:226-317 完整五步流程,每步报告进度
2.16 Auto-create on sync 已实现 crud.py:213-224 检测不存在则自动创建空对象
2.17 Syntax check failure 已实现 crud.py:277-287 报告行号和错误描述
2.18 Activation failure 已实现 crud.py:308-317 报告激活错误详情
2.19 Sync with --corr_nr 已实现 crud.py:230-231 贯穿整个流程
2.20 Query existing object info 已实现 crud.py:371-449 显示名称/类型/描述/状态/负责人等元数据
2.21 Query non-existent object 已实现 crud.py:406-408 404 检测
2.22 Query message class info 未实现 messageclass 未注册
2.23 Query view info 未实现 view 未注册
2.24 Delete with confirmation 已实现 crud.py:483-486 input("yes") 确认
2.25 Delete cancelled 已实现 crud.py:484-486 非确认则取消
2.26 Delete non-existent object 已实现 crud.py:474-477 检测不存在抛 ObjectNotFoundError
2.27 Delete message class 未实现 messageclass 未注册
2.28 Delete lock object 未实现 lockobject 未注册

小计: 16/28 , 7 , 1 ⚠️

缺失对象类型汇总

以下 5 种对象类型在 spec 中列出但未在 types.py 中注册:

  • messageclass — 无 ObjectTypeConfig、无 URI 模板、无 create/download/info/delete
  • view — 无 ObjectTypeConfig、无 URI 模板
  • searchhelp — 无 ObjectTypeConfig、无 URI 模板
  • lockobject — 无 ObjectTypeConfig、无 URI 模板
  • include — 无 ObjectTypeConfig(仅在 scanner.py 的 DIRECTORY_TYPE_MAP 中映射,但 parse_object_name 会报错)
  • cdsview — 无 ObjectTypeConfigCDS 通过独立命令 cds 子系统处理,不走通用 CRUD 流程)

3. Batch Operations (batch-ops/spec.md)

# Scenario 状态 说明
3.1 Init new project 已实现 batch.py:19-96 扫描→查询→生成 manifest.json
3.2 Manifest tracks objects 已实现 manifest.py 完整 CRUD + to_dict/from_dict 持久化
3.3 Query pending objects 已实现 manifest.py:139-146 pending_objects() 方法
3.4 Scan standard directories 已实现 scanner.py:13-29 14 种目录映射 + _scan_flat_directory
3.5 Function directory structure 已实现 scanner.py:91-121 子目录=组名,文件名=模块名
3.6 Skip hidden files 已实现 scanner.py:77 filename.startswith(".") 跳过
3.7 Sort by dependency 已实现 sorter.py:40-109 Kahn 算法拓扑排序 + TYPE_PRIORITY
3.8 Detect cyclic dependency 已实现 sorter.py:100-105CyclicDependencyError 并显示循环链
3.9 Ignore external dependencies 已实现 sorter.py:63-65 dep not in names 时忽略
3.10 Sync all objects (--all) 已实现 batch.py:164-328 完整批量同步
3.11 Dry run mode (--dry-run) 已实现 batch.py:172,224-241 仅显示计划不执行
3.12 Fail fast mode (--fail-fast) 已实现 batch.py:173,287-289 失败立即 break
3.13 Refresh object status 已实现 batch.py:99-161 逐个查询 SAP 状态更新清单

小计: 13/13


4. Search and Browse (search-browse/spec.md)

# Scenario 状态 说明
4.1 List by type with prefix ⚠️部分实现 search.py:31-71 命令层已实现,但调用 client.list_objects()client.py 中缺少该方法定义
4.2 List without filter ⚠️部分实现 同上,命令层有,client 层缺失
4.3 Find references (whereused) ⚠️部分实现 search.py:74-109 命令层已实现,但调用 client.where_used()client.py 中缺少该方法定义
4.4 No references found ⚠️部分实现 search.py:97-98 显示无引用信息,但依赖缺失的 client 方法
4.5 Search by keyword ⚠️部分实现 search.py:112-147 命令层已实现,但调用 client.search_code()client.py 中缺少该方法定义
4.6 Search no results ⚠️部分实现 search.py:136-137 显示无结果信息,但依赖缺失的 client 方法
4.7 Diff with differences ⚠️部分实现 diff_cmd.py:16-90 命令层完整,但调用 client.read_source_for_diff()client.py 中缺少该方法定义
4.8 Diff identical ⚠️部分实现 diff_cmd.py:70-72 检测无差异,但依赖缺失的 client 方法
4.9 Download CDS view ⚠️部分实现 cds.py:31-61 命令层完整,但调用 client.get_cds_source()client.py 中缺少该方法定义
4.10 Create CDS view ⚠️部分实现 cds.py:130-171 命令层完整,但调用 client.create_cds()client.py 中缺少该方法定义
4.11 Query package info ⚠️部分实现 package_cmd.py:56-77 命令层完整,但调用 client.get_package_info()client.py 中缺少该方法定义
4.12 Create package ⚠️部分实现 package_cmd.py:29-53 命令层完整,但调用 client.create_package()client.py 中缺少该方法定义

小计: 0/12 , 12 ⚠️ (命令层均已完成,但 ADTClient 缺少对应的 API 方法)

client.py 缺失的方法清单

以下方法被 commands/ 调用但未在 client.py 中定义:

  1. list_objects(obj_type, package, prefix) — 被 search.py, package_cmd.py 调用
  2. where_used(name, obj_uri, adt_type) — 被 search.py 调用
  3. search_code(query, obj_type) — 被 search.py 调用
  4. read_source_for_diff(name, obj_type) — 被 diff_cmd.py 调用
  5. get_cds_source(name) — 被 cds.py 调用
  6. create_cds(name, description, ddl_source) — 被 cds.py 调用
  7. create_package(name, description, superpackage) — 被 package_cmd.py 调用
  8. get_package_info(name) — 被 package_cmd.py 调用

5. Transport Management (transport/spec.md)

# Scenario 状态 说明
5.1 List transport requests 已实现 transport.py:32-56 + client.py:249-280 list_transport_requests()
5.2 Query transport info ⚠️部分实现 transport.py:59-79 命令层已实现,但调用 client.transport_info()client.py 中缺少该方法定义
5.3 Release transport request ⚠️部分实现 transport.py:82-107 命令层已实现,但调用 client.transport_release()client.py 中缺少该方法定义
5.4 List objects in transport ⚠️部分实现 transport.py:110-136 命令层已实现,但调用 client.transport_objects()client.py 中缺少该方法定义

小计: 1/4 , 3 ⚠️

client.py 缺失的方法(Transport

  1. transport_info(corr_nr) — 传输请求详情查询
  2. transport_release(corr_nr) — 释放传输请求
  3. transport_objects(corr_nr) — 传输请求中的对象列表

6. Code Quality (quality/spec.md)

# Scenario 状态 说明
6.1 Check with findings ⚠️部分实现 quality.py:14-61 命令层完整,但调用 client.atc_check()client.py 中缺少该方法定义
6.2 Check clean ⚠️部分实现 quality.py:38-39 显示通过信息,但依赖缺失的 client 方法
6.3 Format source code ⚠️部分实现 quality.py:64-132 命令层完整,但调用 client.pretty_print()client.py 中缺少该方法定义
6.4 Analyze project dependencies 已实现 analyze.py:39-126 本地源码解析,正则匹配 TYPE REF TO / CALL FUNCTION 等模式
6.5 Scaffold from template 已实现 scaffold.py:198-239 4 种模板(alv-report/bapi-wrapper/interface-class/data-model
6.6 List available templates 未实现 spec 要求不指定模板时列出可用模板,但 parser.py:207 --templaterequired=True,无法不指定

小计: 2/6 , 3 ⚠️, 1

client.py 缺失的方法(Quality

  1. atc_check(name, obj_uri, variant) — ATC 代码检查
  2. pretty_print(source) — ABAP Pretty Printer

7. Configuration Management (config/spec.md)

# Scenario 状态 说明
7.1 Show current config 已实现 config_cmd.py:20-40 显示主机/客户端/用户名,密码掩码显示
7.2 Set config value 未实现 parser.py:123-126 未定义 config set 子命令,config_cmd.py 无 set 逻辑
7.3 List profiles 已实现 config_cmd.py:43-66 list-profiles 子命令
7.4 Use specific profile 未实现 --profile 参数已定义但 config.py 硬编码使用 [SAP] section
7.5 Save password to keyring ⚠️部分实现 auth.pyset_password()cmd_auth_login(),但 auth 模块未集成到 app.py 命令路由parser.py 也未注册 auth 子命令
7.6 Load password from keyring ⚠️部分实现 auth.py:resolve_password() 存在,但 未被 config.py 或 app.py 调用

小计: 2/6 , 2 , 2 ⚠️


汇总统计

Spec 领域 总需求 已实现 未实现 ⚠️部分实现 覆盖率
Connection 9 8 1 0 88.9%
Object Lifecycle 28 16 7 1 57.1%
Batch Operations 13 13 0 0 100%
Search & Browse 12 0 0 12 0% (命令层100%API层0%)
Transport 4 1 0 3 25%
Code Quality 6 2 1 3 33.3%
Config Management 6 2 2 2 33.3%
总计 78 42 11 21 53.8%

关键缺失点总结

A. client.py 缺失的 13 个 ADT API 方法

这些方法被 commands/ 层调用但未实现,是最关键的缺口:

方法 调用者 涉及 Spec
list_objects(obj_type, package, prefix) search.py, package_cmd.py search-browse
where_used(name, obj_uri, adt_type) search.py search-browse
search_code(query, obj_type) search.py search-browse
read_source_for_diff(name, obj_type) diff_cmd.py search-browse
get_cds_source(name) cds.py search-browse
create_cds(name, description, ddl_source) cds.py search-browse
create_package(name, description, superpackage) package_cmd.py search-browse
get_package_info(name) package_cmd.py search-browse
transport_info(corr_nr) transport.py transport
transport_release(corr_nr) transport.py transport
transport_objects(corr_nr) transport.py transport
atc_check(name, obj_uri, variant) quality.py quality
pretty_print(source) quality.py quality

B. types.py 缺失的 5 个对象类型注册

类型 Spec 要求 当前状态
messageclass create/download/info/delete 未注册,无 URI
view create/download/info 未注册,无 URI
searchhelp create 未注册,无 URI
lockobject create/delete 未注册,无 URI
include (扫描可用) scanner.py 映射了目录但 types.py 未注册

C. 配置/认证缺口

缺失项 详情
--profile 不可用 parser.py 定义了参数但 config.py 忽略,始终读 [SAP] section
config set 子命令 spec 要求通过命令行设置配置项,parser.py 未注册,无实现
keyring 集成 auth.py 模块完整但未被 app.py/config.py 引入调用链
scaffold 无模板列表 --template 为 required,无法不指定来列出模板