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 重写为单源开发流程。
This commit is contained in:
吴让宇
2026-09-11 00:40:15 +08:00
parent e786742bcb
commit c5905a5b1e
104 changed files with 20744 additions and 10 deletions
+120
View File
@@ -0,0 +1,120 @@
# ABAP 编码规则(质检标准)
> 维护者:Rangyu | 版本:v1.0 | 2026-08-05
>
> 本规则文档由 **Rangyu(老板)维护**,质检员在代码审计时以此文档为唯一标准。
> 质检结果分为:✅合规 / ❌违规(必须修复) / ⚠️建议(推荐修复)
---
## 1. 安全规则(Security
| ID | 规则 | 判定 | 示例 |
|----|------|------|------|
| S01 | 生产代码中**禁止硬断点**BREAK-POINT | ❌违反 | `BREAK-POINT.` → 删除 |
| S02 | 关键数据访问前**必须 AUTHORITY-CHECK** | ❌违反 | 聊天记录读取、配置维护、表维护 |
| S03 | SQL 注入防护:**所有变量必须用 @ 转义** | ✅合规 | `WHERE field = @lv_var` |
| S04 | 敏感数据(聊天内容、用户信息)需脱敏或审计 | ⚠️建议 | `zidt_chatlog` message_body 字段 |
| S05 | | | |
| S06 | | | |
| S07 | | | |
*(Rangyu 补充更多安全规则...)*
---
## 2. 性能规则(Performance
| ID | 规则 | 判定 | 示例 |
|----|------|------|------|
| P01 | 禁止 `SELECT *`,仅查询所需字段 | ⚠️建议 | `SELECT field1, field2 FROM ...` |
| P02 | 禁止无 WHERE 条件的全表扫描(小配置表除外) | ⚠️建议 | `SELECT ... FROM ztable WHERE ...` |
| P03 | 大表查询必须有索引支撑 | ⚠️建议 | SE11 检查索引 |
| P04 | 循环内禁止 SQL 查询 | ❌违反 | LOOP 内 SELECT |
| P05 | 循环字符串拼接用 `CONCATENATE` 单次操作 | ⚠️建议 | 避免 LOOP 内 `&&` |
| P06 | | | |
| P07 | | | |
*(Rangyu 补充更多性能规则...)*
---
## 3. 可维护性规则(Maintainability
| ID | 规则 | 判定 | 示例 |
|----|------|------|------|
| M01 | 重复代码超过 80% 相似 → 提取公共方法/FORM | ❌违反 | 3处 AI 调用重复约 90% |
| M02 | 每个 FORM/方法不超过 200 行 | ⚠️建议 | |
| M03 | 禁止**裸硬编码字符串**(模型名、GUI状态、事务码) | ⚠️建议 | 用常量 `CONSTANTS c_model TYPE ... VALUE 'qwq-32b'` |
| M04 | 关键逻辑必须有注释 | ⚠️建议 | |
| M05 | 无用变量/死代码必须清理 | ⚠️建议 | `gs_tool-END` 赋值未消费 |
| M06 | | | |
| M07 | | | |
*(Rangyu 补充更多可维护性规则...)*
---
## 4. 错误处理规则(Error Handling
| ID | 规则 | 判定 | 示例 |
|----|------|------|------|
| E01 | `sy-subrc <> 0` 后**不能静默处理** | ❌违反 | `IF sy-subrc <> 0. " 错误处理 ENDIF.` → 必须 MESSAGE/EXIT |
| E02 | API 调用必须有异常保护(CATCH) | ⚠️建议 | HTTP 调用、RFC 调用 |
| E03 | 数据库操作必须有错误处理 | ⚠️建议 | COMMIT/ROLLBACK |
| E04 | **CALL FUNCTION 前必须核实被调对象真实存在**:ADT 通道无法校验被调函数与引用结构是否存在(syntax-check 只覆盖当前对象自身),凡调用 `CALL FUNCTION 'Z...'` 或引用 `Z...` 结构/表类型,必须先用 sap-cli(`info`/`download`/`read-table DD02L` 任一)确认对象存在且名称逐字符一致,再落代码 | ❌违反 | 凭记忆写 `CALL FUNCTION 'ZMM_BIP_CREATE'`(实际对象是 `ZMM_BIP_VENDOR_CREATE`)→ 编译期不报错、运行期 CALL_FUNCTION_NOT_FOUND 转储。正确:先 `sap-cli info --name 组名/函数名 --type function` 查实,再写调用 |
| E05 | **CALL FUNCTION 的参数结构必须与被调函数真实签名一致**IMPORTING/EXPORTING/CHANGING/TABLES 各参数名、类型、顺序以核实到的函数签名为准(info 输出或 download 函数源码的 Interface 节),不得按猜测拼参数;引用的 DDIC 结构(如 `TYPE zmm_bip_001_in`)须同批核实结构存在且组件名/类型一致 | ❌违反 | `CALL FUNCTION 'X' EXPORTING iv_a = lv` 但实际签名参数是 `IS_IMPORT` → 运行期 PARAMETER_NOT_FOUND/类型不匹配转储。正确:以 `download` 拿到函数头 `"*" Local Interface: 注释节为准逐参数比对,结构组件以 DD02L/DD03L 实查为准 |
*(Rangyu 补充更多错误处理规则...)*
> **E04/E05 背景(2026-09-10 老板指令)**:远程语法检查不校验被调函数的存在性与签名匹配——本地语法全绿 ≠ 运行期不转储。开发报表/程序中所有 `CALL FUNCTION`(尤其调用本组外/客户化 Z 对象)一律先核实后调用,核实记录(对象存在性 + 签名比对)纳入交付物。
---
## 5. NW 7.40 兼容规则(7.40 Compatibility
| ID | 规则 | 判定 | 示例 |
|----|------|------|------|
| C01 | **禁止 `DATA(...)` inline 声明** | ❌违反 | `DATA(lv_x) = ...` → `DATA lv_x TYPE ...` |
| C02 | Open SQL `@` 转义**全局一致** | ❌违反 | 不能混用 `@lv` 和 `lv` |
| C03 | 禁止字符串模板 `\|...\|` | ❌违反 | 用 `CONCATENATE` 代替 |
| C04 | 禁止 `WITH EMPTY KEY` | ❌违反 | 用 `WITH DEFAULT KEY` |
| C05 | LOOP AT SCREEN 逻辑避免重复 | ⚠️建议 | 提取公共 FORM |
| C06 | | | |
| C07 | | | |
*Rangyu 补充更多 7.40 兼容规则...*
---
## 6. 代码风格规则(Style
| ID | 规则 | 判定 | 示例 |
|----|------|------|------|
| T01 | 命名遵循 SAP 规范(Z开头自定义) | ✅合规 | `ZIDTR_AI_ASSISTANT` |
| T02 | 变量命名语义化 | ⚠️建议 | `lv_date` 优于 `lv_d` |
| T03 | 注释语言统一(中/英) | ⚠️建议 | |
| T04 | | | |
| T05 | | | |
*(Rangyu 补充更多风格规则...*
---
## 附录:今天质检发现的典型违规
| 程序 | 问题 | 规则ID | 行号 |
|------|------|--------|------|
| ZIDTR_AI_ASSISTANT | 生产代码 BREAK-POINT | S01 | L44 |
| ZIDTR_AI_ASSISTANT | 权限检查缺失 | S02 | 全文 |
| ZIDTR_AI_ASSISTANT | 3处代码重复~90% | M01 | L464-667 |
| ZIDTR_AI_ASSISTANT | 硬编码模型名 | M03 | L207 |
| ZIDTR_AI_ASSISTANT | F4错误静默处理 | E01 | L170-172 |
| ZIDTR_AI_ASSISTANT | DATA(...) inline | C01 | L152等6处 |
| ZIDTR_AI_ASSISTANT | @转义混用 | C02 | L154/259 |
---
> **使用方式**:质检员读取本文件 → 逐条对照代码 → 输出 `✅/❌/⚠️` 审计报告。
>
> **维护方式**:Rangyu 随时增删规则,更新后通知小迅同步到质检员的审查标准。
+121
View File
@@ -0,0 +1,121 @@
# 错误处理流程
sap-cli 命令失败时的标准处理流程。严格按顺序执行。
## 通用流程
```
命令失败
1. 诊断根因(使用方式错误 or 代码/环境问题?)
2. 使用方式错误 → 修正参数后重试
3. sap-cli 限制 → 报告失败,不绕过
4. SAP 系统限制 → 穷尽自动化方案
5. 确认无法自动化 → 请求用户 SAP GUI 操作
```
## 步骤 1:诊断根因
检查以下项目:
| 检查项 | 方法 |
|--------|------|
| 命令参数是否正确 | 对照 `python main.py --help` 和 SKILL.md 验证参数 |
| 文件是否存在、内容是否为空 | `cat``ls` 检查 |
| 传输请求号是否正确 | `python main.py transport info --corr_nr DEVK901XXX` |
| 网络连接是否正常 | `python main.py config show` 验证配置 |
| 对象是否存在于 SAP | `python main.py info --name XXX --type class` |
## 步骤 2:使用方式错误
修正后重试。常见修正:
- 缺少 `--corr_nr` → 加上传输请求号
- 对象名大小写错误 → sap-cli 会自动处理,但路径要注意
- 文件路径错误 → 检查相对/绝对路径
- 对象类型不匹配 → 用 `python main.py --help` 确认支持的类型
## 步骤 3sap-cli 限制
如果确认不是使用方式问题,**如实报告错误信息**,不要尝试绕过 sap-cli:
```
❌ 错误做法:写 Python requests 脚本绕过
❌ 错误做法:用 curl 直接调 ADT 端点
❌ 错误做法:导入 ADTClient 调内部方法
✅ 正确做法:报告失败,说明原因
```
## 步骤 4:穷尽自动化方案(SAP 系统限制时)
遇到 SAP 系统限制时,按以下顺序穷尽自动化方案:
### 方案 A:调整 sap-cli 参数重试
- 尝试不同的 `--corr_nr`
- 尝试 `--dry-run` 预览后执行
- 检查是否有残留锁(`show-table` 查看 SM12 相关信息)
### 方案 BABAP 报表 workaround
通过 `run-program` 执行辅助报表:
```bash
# 清除残留锁
python main.py sync --type report --name ZSAPILOT_CLEAR_LOCKS --path <file> --corr_nr DEVK901XXX
python main.py run-program --name ZSAPILOT_CLEAR_LOCKS
```
### 方案 Cdelete + recreate
如果对象需要完全重写:
```bash
python main.py delete --name ZMY_CLASS --type class
python main.py sync --name ZMY_CLASS --type class --path <file> --corr_nr DEVK901XXX
```
注意:delete 可能因传输请求绑定而失败(HTTP 423),此时需要用户在 SE09 操作。
### 方案 Dactivate 单独重试
```bash
python main.py activate --name ZMY_CLASS --type class --corr_nr DEVK901XXX
```
NW 7.40 的 double-activate 已内置在 sap-cli 中。如果 activate 仍然失败,**不要再尝试其他激活策略**,直接报告给用户。
## 步骤 5:请求用户 SAP GUI 操作
**只在确认所有自动化方案穷尽后**才请求用户操作。
### 必须一次性给出完整操作清单
当需要用户在 SAP GUI 操作时,**绝不能渐进式发现问题**:
- ❌ 错误:先让用户加字段 A,测试后发现缺字段 B,又让用户加字段 B
- ✅ 正确:先做全面对比分析(`show-table` vs 代码中的字段引用),一次性给出完整变更清单
### 系统表操作的 4 步授权流程
如果需要操作系统表(唯一的例外情况):
1. **解释原因** — 为什么需要操作系统表
2. **列出具体操作** — 表名 + 操作类型(如 `DELETE FROM SEOCLASS WHERE ...`
3. **说明风险和替代方案** — 可能的副作用、有没有不操作系统表的替代方案
4. **等待用户确认** — 得到明确授权后才执行
## 常见失败场景速查
| 错误 | 常见原因 | 处理方式 |
|------|----------|----------|
| HTTP 406 (Lock DDIC) | NW 7.40 不支持 DDIC 对象 ADT Lock | 报告用户,SE09 处理 |
| HTTP 403 (Locked) | 残留 enqueue lock | 先尝试 `run-program` 清锁报表,不行才 SM12 |
| HTTP 400 (SaveFailure) | 类 DEFINITION 与 SAP 不一致 | 检查本地 vs SAP 的 DEFINITION 差异 |
| HTTP 423 (Transport lock) | 对象绑定在传输请求中 | 报告用户,SE09 处理 |
| 激活失败仍 inactive | NW 7.40 ADT 限制 | sap-cli 已内置 double-activate,仍失败则报告用户去 SE09 |
| `WITH EMPTY KEY` 运行 dump | NW 7.40 不支持 | 修改为 `WITH NON-UNIQUE KEY``WITH DEFAULT KEY` |
+135
View File
@@ -0,0 +1,135 @@
# sap-cli 使用约束
本文件定义使用 sap-cli 操作 SAP 系统时的 **硬性约束**。违反任何一条都会被 Hooks 拦截。
## 🚫 规则 1:只使用 sap-cli 命令操作 SAP 系统
操作 SAP 系统时,**必须且只能**使用 `python main.py <命令>` 的形式。
**严禁以下行为**
| 禁止操作 | 原因 |
|----------|------|
| 用 Python `requests` / `urllib` 直接调 ADT REST 端点 | 必须通过 sap-cli 命令 |
| 用 curl 直接调 ADT 端点(`/sap/bc/adt/*` | 必须通过 sap-cli 命令 |
| 用 curl 调 SOAP RFC`/sap/bc/soap/rfc` | 必须通过 sap-cli 的 `read-table` 命令 |
| 编写 Python 脚本导入 `sapcli.client.ADTClient` 后直接调内部方法 | sap-cli 的内部 API 不是公开接口 |
| 在 Python 脚本中手动构造 ADT XML body | 必须通过 sap-cli 命令处理 |
| 用 `python -c` 内联调用 requests 访问 SAP | 同上 |
**唯一合法的 SAP 交互方式**
```bash
cd D:/Gitee/sap-cli-skill/assets && python main.py <command> [options]
```
> 本机唯一源目录为 `D:/Gitee/sap-cli-skill`,工具在其 `assets/` 下(原 `D:/Gitee/sap-cli` 已归档,勿再用)。通过 `--profile <名>` 切换目标系统,连接配置在 `assets/config.ini`。
### 例外(仅在以下情况下允许)
- `run-program` 执行自定义 ABAP 报表 — 这是 sap-cli 的内置功能
- 用户**明确要求**使用其他方式(如"请用 curl 测试这个端点"
- **开发 sap-cli 本身**(作为项目开发而非使用工具时)
## 🚫 规则 2:禁止修改 SAP 标准开发对象
SAP 系统中的标准交付对象(`CL_*``CX_*``IF_*``SAPL*` 等)**严禁修改**。
| 禁止 | 说明 |
|------|------|
| `download` 标准对象后修改再 `sync` 回去 | 破坏 SAP 系统一致性 |
| 对标准对象执行 `delete` | 不可逆操作 |
| `run-program` 修改标准对象源码 | 同上 |
**允许**(只读):
-`download` / `info` / `list` / `search` / `whereused`
-`show-table` / `read-table` — 查看结构和数据
-`diff` — 对比分析
**判定标准**:对象 original system 不是用户自己的开发系统,或对象名以 SAP 标准命名空间开头。**不确定时先问用户**。
## 🚫 规则 3:禁止操作系统表数据
SAP 系统表(存储元数据、运行时状态、内部配置的表)**严禁直接操作**。
| 禁止 | 典型表 |
|------|--------|
| INSERT / UPDATE / DELETE / MODIFY 系统表 | TADIR, E071, SEOCLASS, REPOSRC, D010SINF, T000, TDEVC, TSTC |
**允许**(只读):
-`read-table` / `show-table` 查看(SELECT)系统表数据用于诊断
-`run-program` 报表中 SELECT 读取系统表
**唯一例外**:用户**明确授权**后才能操作系统表,且必须遵循 4 步授权流程(见 error-handling.md)。
## 🚫 规则 4sync 命令必须带 --corr_nr
```bash
# ✅ 正确
python main.py sync --name ZMY_CLASS --type class --path ./src/zmy.abap --corr_nr DEVK901362
# ❌ 错误(缺少 --corr_nr,会触发交互式传输请求选择)
python main.py sync --name ZMY_CLASS --type class --path ./src/zmy.abap
```
## 🚫 规则 5DDIC 对象的 NW 7.40 限制
在 NW 7.40 上,DDIC 对象(domain、dataelement、table)的 ADT Lock 返回 HTTP 406。
- 这是 **SAP 系统限制**,不是 sap-cli 的 bug
- sync DDIC 失败时,不要反复重试 — 报告给用户,让用户通过 SAP GUI SE09 处理
- 新建的 DDIC 对象(不存在于 SAP)可通过 `create --definition` 创建
## 🚫 规则 6:查表数据用 read-table,查表结构用 show-table
sap-cli 已内置这些命令,不要自己写 HTTP 调用。
```bash
# 查看表结构
python main.py show-table --name ZSAPILOT_OBJ
# 查看表数据
python main.py read-table --name ZSAPILOT_OBJ --max-rows 50
```
## 🚫 规则 7:DDIC 未完成禁止开发引用它的代码(依赖顺序)
代码引用的每个 DDIC 对象(域/数据元素/表/结构/表类型)必须先完成「上传 → 语法检查通过 → 激活成功」三关,才能开始写引用它的代码。
- 落地顺序:`domain → dataelement → table/structure → tabletype → interface → class → function → report`
- 是否完成**以实测为准**:结构查 `DD02L``AS4LOCAL = 'A'`)、表类型查 `DD40L`、其余查 `info` / `TADIR`**不采信会话自述**
- 违反后果:后续每个引用对象语法检查报「类型/结构 XXX 未知」,整批返工
## 🚫 规则 8:强制开发闭环(不得跳步)
```
1. 本地编写/修改源码 → 2. 同步 SAP(upload/sync) → 3. 语法检查(syntax-check)
↑ │
└──────────────── 有错则回到第 1 步 ←───────────────────┘
4. 语法检查 0 错误 → 激活(activate) → 5. 激活成功后才允许执行测试(run-program/unit-test)
└── 测试不过 → 回到第 1 步
```
禁止:
- ❌ 跳过语法检查直接 activate
- ❌ 未激活就 run-program / unit-test(跑旧版本或报对象不存在)
- ❌ 把「语法检查通过」当「功能正常」—— syntax-check 不校验被调对象存在性与签名(见 `abap-coding-rules.md` E04/E05
- ❌ 把「S4T 演示机通过」表述为「CEM/生产验证通过」
- ❌ 多会话并发操作同一批对象(派下一会话前先确认前一个已退出)
## 自检清单
每次执行 SAP 操作前,确认:
1. ✅ 我在用 `python main.py <命令>` 吗?
2. ✅ 我没有直接调 ADT/SOAP/RFC 端点吗?
3. ✅ 我操作的是 Z* 开头的自定义对象吗?
4. ✅ 我没有 INSERT/UPDATE/DELETE 系统表吗?
5. ✅ sync 命令带了 `--corr_nr` 吗?
6. ✅ 我引用的 DDIC 对象都已激活(实测确认)了吗?
7. ✅ 我按「本地改 → 同步 → 语法检查 → 循环至 0 错误 → 激活 → 测试」执行了吗?
8. ✅ 我核实过被调函数/结构的存在性与签名了吗(E04/E05)?
9. ✅ 同一任务只有一个开发者会话在跑吗?