新增能力: - remote-enable 子命令:设置函数模块处理类型为远程启用(bgRFC/RFC 执行体必需)。 实现要点均按实机验证:PUT fmodule:processingType="rfc"(枚举值仅小写 rfc 有效, remoteEnabled/remote/RFC 等均 400);lockHandle 走 query 参数(放 header 报 ParameterNotFound);PUT 后 GET 复核回显;DDIC 结构参数才可远程启用(类本地类型 报"针对 RFC 不允许使用类或接口的类型")。 - create --type functiongroup 透传 --package / --corr_nr(此前 package 被静默写成 $TMP, 导致函数组无法归目标包)。 修复: - activate 请求体补重复引用:ADT CLAS 激活端点对 objectReferences 只有 1 个引用时 返回 HTTP 200 + 空 body 且不执行激活;引用数 ≥2 才真正激活(同对象重复亦可)。 - scanner 剥离 ADT 文件后缀(xxx.clas.abap 解析错误)。 守卫测试: - tests/unit/test_bgrfc_support.py(17 例):函数组 package 透传、processingType 助手、 remote-enable 命令(含 lockHandle 走 query/小写 rfc/错误透传/复核失配判失败)、 函数 URI 组装不得用组名冒充模块名。 - test_activate.py 增加激活请求体引用数守卫;test_repo_guards.py 增加后缀剥离守卫。 测试:tests/unit 676 + tests/test_sapcli.py 69 = 745 全绿 (PYTHONPATH=assets python -m unittest discover -s tests/unit -t tests)
380 lines
25 KiB
Markdown
380 lines
25 KiB
Markdown
---
|
||
name: sap-cli
|
||
description: "Use when you need to operate SAP ABAP development objects — syncing code, querying metadata, managing transports, reading tables, or any task involving SAP ADT REST API. Trigger on: ABAP objects, SAP development, transport requests, DDIC types, SE11/SE16N/SE38/SE80 equivalents, 'sync to SAP', 'download from SAP', 'activate ABAP', 'read SAP table'. NOT for developing sap-cli itself."
|
||
version: "2.5.1"
|
||
author: WuRangyu
|
||
license: MIT
|
||
triggers:
|
||
- "ABAP development"
|
||
- "sync to SAP"
|
||
- "download from SAP"
|
||
- "SAP transport request"
|
||
- "DDIC/SE11/SE16N/SE38/SE80"
|
||
- "SAP ADT REST API"
|
||
---
|
||
|
||
# sap-cli — SAP ABAP Development Object Management
|
||
|
||
Python CLI wrapping the SAP ADT REST API. Manages the full lifecycle of ABAP development objects from the terminal. Core loop: **download → local edit → sync back to SAP**.
|
||
|
||
## 调用方式
|
||
|
||
```bash
|
||
cd <SKILL_DIR>/assets && python main.py <command> [options]
|
||
```
|
||
|
||
全局参数(置于命令之前):
|
||
|
||
| 参数 | 说明 |
|
||
|------|------|
|
||
| `--profile <name>` | 使用指定配置 profile |
|
||
| `--verify-ssl` | 启用 SSL 验证(默认关闭) |
|
||
|
||
安装与配置见同目录 `INSTALL.md`。
|
||
|
||
## Quick Start
|
||
|
||
```bash
|
||
# 1. Single object: download → edit → sync
|
||
# 注意:--path 必须给到「对象类型目录」(src/TMP/<对象类型>),见铁律 5
|
||
python main.py download --name ZMY_CLASS --type class --path ./src/TMP/class
|
||
# edit ./src/TMP/class/zmy_class.abap
|
||
python main.py sync --name ZMY_CLASS --type class --path ./src/TMP/class/zmy_class.abap --corr_nr DEVK901XXX
|
||
|
||
# 2. Batch project sync (auto dependency-ordered)
|
||
python main.py init --path ./my_project # add objects under src/
|
||
python main.py sync --all --path ./my_project --corr_nr DEVK901XXX
|
||
|
||
# 3. Table query: structure (SE11) + data (SE16N)
|
||
python main.py show-table --name ZMY_TABLE
|
||
python main.py read-table --name ZMY_TABLE --fields "F1,F2" --where "F1 = 'X'" --max-rows 50
|
||
```
|
||
|
||
## Command Reference
|
||
|
||
Optional params in `[ ]`. 各命令参数以 `python main.py <cmd> --help` 为准。
|
||
|
||
| Category | Command | Key Parameters |
|
||
|----------|---------|----------------|
|
||
| CRUD | `create` | `--name --type [--description --source <.abap> --definition <.json> --package <$TMP> --corr_nr]` |
|
||
| CRUD | `info` | `--name --type` [^1] |
|
||
| CRUD | `download` | `--name --type --path` |
|
||
| CRUD | `sync` | `--name --type --path --corr_nr` **(REQUIRED)** |
|
||
| CRUD | `delete` | `--name --type` |
|
||
| CRUD | `activate` | `--name --type --corr_nr` (built-in NW 7.40 double-activate) |
|
||
| CRUD | `upload` | `--name --type --path --corr_nr` (lock→write→unlock only; no check/activate) |
|
||
| CRUD | `syntax-check` | `--name --type` (remote object; no upload/activate) |
|
||
| CRUD | `unlock` | `--name --type --lock-handle` (释放 delete 后残留的 enqueue 锁) |
|
||
| Batch | `init` | `--path` |
|
||
| Batch | `refresh` | `--path` |
|
||
| Batch | `sync --all` | `--path --corr_nr [--dry-run]` |
|
||
| Batch | `analyze` | `--path` (dependency analysis) |
|
||
| Batch | `clone` | `--name --type --from <profile> --to <profile> [--corr_nr]` (跨系统克隆对象) |
|
||
| Query | `show-table` | `--name` (SE11 structure) |
|
||
| Query | `read-table` | `--name [--fields --where --max-rows]` (SE16N data) |
|
||
| Query | `list` | `--type [--package --prefix]` |
|
||
| Query | `whereused` | `--name --type` |
|
||
| Query | `search` | `--query` |
|
||
| Query | `diff` | `--name --type --path` (local vs SAP) |
|
||
| Query | `history` | `--name --type` (对象版本历史) |
|
||
| Transport | `transport list` | — |
|
||
| Transport | `transport info` | `--corr_nr` |
|
||
| Transport | `transport release` | `--corr_nr` |
|
||
| Transport | `transport objects` | `--corr_nr` |
|
||
| Transport | `transport create` | `--description` (新建传输请求) |
|
||
| Config | `config show` | — |
|
||
| Config | `config list-profiles` | — |
|
||
| Config | `config set` | `<key> <val>` |
|
||
| Config | `auth login` / `auth status` | password stored in keyring |
|
||
| Other | `run-program` | `--name` (SA38) |
|
||
| Other | `check` | `--name --type` (ATC) |
|
||
| Other | `format` | `--name --type` (Pretty Printer) |
|
||
| Other | `enhancement` | `--name --type` (增强) |
|
||
| Other | `remote-enable` | `--name <组/模块> [--corr_nr]` (FM 远程启用/bgRFC 执行体) |
|
||
| Other | `unit-test` | `--name --type` (ABAP Unit 测试) |
|
||
| Other | `package create` | `--name` |
|
||
| Other | `cds download` | `--name --path` |
|
||
| Other | `scaffold` | `--name --template <t>` — alv-report, bapi-wrapper, interface-class, data-model |
|
||
|
||
[^1]: ⚠️ `info` 不返回 `package`/`packageRef` 字段。需通过 ADT API 查询:`GET /sap/bc/adt/programs/programs/<name>` 返回 XML 中含 `<adtcore:packageRef>`。也可用 `list --package <pkg>` 反向查找。
|
||
|
||
Batch sync dependency order: `domain(10) → dataelement(20) → table(30) → tabletype(40) → interface(50) → class(60) → function(70) → report(80)`.
|
||
|
||
Step-wise sync for lock-heavy automation — split the atomic `sync` when lock conflicts are frequent; upload now, verify, activate later:
|
||
```bash
|
||
python main.py upload --name ZMY_CLASS --type class --path ./src/TMP/class/zmy_class.abap --corr_nr DEVK901XXX # lock→write→unlock only
|
||
python main.py syntax-check --name ZDEPENDENT_REPORT --type report # verify dependents (no upload)
|
||
python main.py activate --name ZMY_CLASS --type class --corr_nr DEVK901XXX # activate once clean
|
||
```
|
||
|
||
### Supported Object Types (16)
|
||
|
||
| Category | Types | Has source |
|
||
|----------|-------|------------|
|
||
| Programs | `report`, `include` | ✅ |
|
||
| OOP | `class`, `interface` | ✅ |
|
||
| Functions | `function` | ✅ |
|
||
| DDIC base | `domain`, `dataelement`, `table`, `structure` | ✅ |
|
||
| DDIC ext | `cdsview`, `view` | ✅ |
|
||
| DDIC no-source | `tabletype`, `messageclass`, `searchhelp`, `lockobject` | ❌ |
|
||
| Groups | `functiongroup` | ❌ |
|
||
|
||
**Function naming**: must use `group/module`, e.g. `ZMY_FGROUP/Z_MY_FUNC`.
|
||
|
||
### Function Module Remote-Enable(bgRFC/RFC 执行体)
|
||
|
||
bgRFC 的执行体必须是**远程启用的函数模块**。ADT 建 FM 默认 `processingType=normal`,
|
||
语法检查**不校验**此标志,必须显式置 `rfc` 并以 `TFDIR.FMODE='R'` 复核。
|
||
|
||
```bash
|
||
python main.py remote-enable --name ZINT_FG_INTEGRATE/ZINT_FM_LOG_COMMIT --corr_nr DEVK901376
|
||
```
|
||
|
||
命令内部闭环(锁定→GET 原 XML→改 `processingType=rfc`→PUT→GET 复核→解锁),
|
||
仅改属性,不激活、不查 TFDIR。关键事实(本机 NW 7.52 实测):
|
||
|
||
| 要点 | 事实 |
|
||
|------|------|
|
||
| `processingType` 枚举值 | 只认小写 `rfc`;`remoteEnabled`/`remote`/`RFC` 等值全 400 |
|
||
| `lockHandle` 传递 | 必须走 query 参数 `?lockHandle=`;放 header 报 `ExceptionParameterNotFound` |
|
||
| 参数类型限制 | 只允许 DDIC 对象(结构含 STRING 列已验证);类本地类型 → HTTP 500「针对 RFC 不允许使用类或接口的类型」;表类型参数需 TTYP 端点(本机 404) |
|
||
| FM 源码限制 | `FUNCTION` 与 `ENDFUNCTION` 之间不得放 `*"` 参数注释块(ADT 拒绝「Parameter comment blocks are not allowed」) |
|
||
| 最终确认 | `TFDIR.FMODE='R'` 留给调用方 `read-table` 复核(本命令不查) |
|
||
|
||
—— 落款:吴让宇
|
||
|
||
## ⚠️ Constraints (HARD RULES — DO NOT VIOLATE)
|
||
|
||
Full rules: `references/sap-tool-constraints.md`. Violations are intercepted by hooks.
|
||
质检标准: `references/abap-coding-rules.md`(38条规则,6大类:安全/性能/可维护性/错误处理/NW740兼容/风格。其中 E04/E05 强制:CALL FUNCTION 前必须核实被调对象存在、参数结构与真实签名一致,ADT 语法检查不覆盖被调对象,核实记录纳入交付物)。质检员在代码审计时以此文档为唯一标准,判定体系:✅合规 / ❌违反(必须修复) / ⚠️建议(推荐修复)。
|
||
|
||
1. **Only `python main.py <cmd>` touches SAP** — no `requests`/`urllib`, no curl to ADT/SOAP/RFC, no `python -c` inline, no importing `ADTClient` internals, no hand-built ADT XML. Exceptions: `run-program` custom reports, explicit user request, or developing sap-cli itself.
|
||
2. **Never modify SAP standard objects** (`CL_*`, `CX_*`, `IF_*`, `SAPL*`, or any non-user original system) — read-only only: download/info/list/search/whereused/show-table/read-table/diff. When unsure, ask the user.
|
||
3. **Never write system tables** (TADIR, E071, SEOCLASS, REPOSRC, D010SINF, T000, TDEVC, TSTC) — read-only SELECT is fine; any write needs explicit authorization.
|
||
4. **`sync` must carry `--corr_nr`** — otherwise it triggers an interactive transport-request prompt.
|
||
5. **Non-interactive `delete` needs piped confirm** — `echo "yes" | python main.py delete ...` (else EOFError).
|
||
6. **DDIC `sync` failure on NW 7.40 (HTTP 406) is a system limit** — do not retry; report to the user for SE09.
|
||
|
||
## ⛔ 开发铁律(依赖顺序 + 强制闭环)
|
||
|
||
> 违反任一条的后果不是「效率低」,而是**后续全部代码必须返工**。2026-09-10 S4T 实测事故后固化。
|
||
|
||
### 铁律 1:DDIC 未完成,禁止开发任何引用它的代码
|
||
|
||
代码引用的每一个 DDIC 对象(域 / 数据元素 / 表 / 结构 / 表类型)**必须先完成「上传 → 语法检查通过 → 激活成功」三关**,才能开始写引用它的代码。
|
||
|
||
- 落地顺序:`domain → dataelement → table/structure → tabletype → interface → class → function → report`
|
||
- 「已完成」**以实测为准,不采信会话自述**:
|
||
- 结构 → `read-table DD02L`(`AS4LOCAL = 'A'` 才算激活)
|
||
- 表类型 → `read-table DD40L`
|
||
- 其他对象 → `info` / `read-table TADIR`
|
||
- 违反后果:后续每个引用它的对象语法检查报「类型 XXX 未知 / 结构不存在」,整批返工。
|
||
|
||
### 铁律 2:强制开发闭环(七步,不得跳步)
|
||
|
||
```
|
||
1. 本地编写 / 修改源码 ← 本地文件是唯一编辑入口,不在 SAP 端直接改
|
||
2. 同步到 SAP ← upload / sync --corr_nr
|
||
3. SAP 端语法检查 ← syntax-check
|
||
4. 有错?→ 回到第 1 步 ← 本地改 → 再同步 → 再检查,循环到 0 错误
|
||
5. 语法检查通过 → 激活 ← activate
|
||
6. 激活成功 → 才允许执行测试 ← run-program / unit-test
|
||
7. 测试不过 → 回到第 1 步
|
||
```
|
||
|
||
**禁止**:
|
||
|
||
- ❌ 跳过语法检查直接 `activate`
|
||
- ❌ 未激活就 `run-program` / `unit-test`(跑的是旧版本,或报「对象不存在」)
|
||
- ❌ 把「语法检查通过」当成「功能正常」—— `syntax-check` 不校验被调对象的存在性与签名(见 `references/abap-coding-rules.md` E04/E05)
|
||
- ❌ 把「S4T 演示机通过」表述为「CEM / 生产验证通过」(演示机缺 DDIC、无编号范围、权限不同)
|
||
|
||
### 铁律 3:引用前先核实存在性(E04/E05 落地)
|
||
|
||
写 `CALL FUNCTION` 或引用 `TYPE z...` 之前,必须先 `info` / `read-table DD02L|DD03L` 核实:对象存在、名称逐字符一致、签名与组件一致。核实记录(对象存在性 + 签名比对)纳入交付物。
|
||
|
||
### 铁律 4:同一任务同时只允许一个开发者
|
||
|
||
多会话并发操作同一批对象会相互覆盖。**派下一个会话前,先确认前一个已退出**(`ps aux | grep [h]ermes`)。长任务用 `background=true, notify=true`,等完成通知再派下一步。
|
||
|
||
### 铁律 5:src 目录三层结构(开发包 → 开发对象 → 代码)
|
||
|
||
源码仓 `src/` 下**只允许这一种层次**,三层缺一不可:
|
||
|
||
```
|
||
src/
|
||
└── TMP/ ← 第 1 层:开发包,本地开发固定用 TMP
|
||
└── <对象类型>/ ← 第 2 层:开发对象 = 对象类型,一个类型一个目录
|
||
└── zxxx.abap ← 第 3 层:代码文件,文件名 = 对象名(download 产出小写,扫描大小写不敏感)
|
||
```
|
||
|
||
- 第 1 层**固定写 `TMP`**(本地开发包):对应 SAP 端 `$TMP` 本地包,目录名去掉 `$` 以免 shell 把 `$TMP` 当变量展开。对象正式归入传输包时,该层目录改名为包名(如 `ZIDTR`),层次不变
|
||
- 第 2 层目录即开发对象类型的落地:`report` / `class` / `interface` / `function` / `domain` / `dataelement` / `table` / `structure` / `tabletype` / `include` …(完整清单见下方「📦 Gitee仓库规范 → 目录结构」)
|
||
- **禁止**:`.abap` 平铺在 `src/` 根下;禁止跳过开发包层直接把对象类型目录放 `src/` 下;禁止在对象类型目录下再嵌套子目录(函数模块的命名按下方结构图 `function/ZGROUP_ZFUNC.abap`)
|
||
- **`download --path` 要给到对象类型目录**:该命令只把文件写进给定目录,**不会自动建开发包层/对象层**。`--path ./src/TMP/class` 正确;`--path ./src` 会产出平铺目录,不合格
|
||
- 反例(2026-09-10 实测):`sap-cem-bip/src/` 25 个 `.abap` 平铺在根下,既无开发包层也无对象类型层 → 不合格,需归位
|
||
- 批量功能(`init` / `sync --all`)**已支持三层结构**:扫描器(`sapcli/scanner.py`)会扫项目根下的类型目录,也会下钻 `src/<开发包>/` 找类型目录;目录名**单复数均接受、大小写不敏感**(`class/` = `classes/`)。旧的扁平布局仍兼容
|
||
- 函数模块两种命名均可:`function/<函数组>/<函数模块>.abap` 或 ADT 式 `function/<函数组>.fugr.<函数模块>.abap`,对象名统一解析为 `函数组/函数模块`
|
||
|
||
### 2026-09-10 S4T 事故问题总结
|
||
|
||
| # | 问题 | 后果 | 对策(已固化) |
|
||
|---|------|------|----------------|
|
||
| 1 | 用 `CALL FUNCTION` 但检查不校验被调函数是否存在、调用结构是否正确 | 本地语法全绿、运行期 `CALL_FUNCTION_NOT_FOUND` 转储 | 编码规则 E04/E05(强制核实存在与签名) |
|
||
| 2 | DDIC 未落地就开发引用代码 | 后续对象语法检查全挂 | 铁律 1(DDIC 先行 + 实测判定) |
|
||
| 3 | 跳过「语法检查 → 激活 → 测试」闭环,直接跑测试 | 跑的是旧版本 / 对象不存在,结论无效 | 铁律 2(七步闭环不得跳步) |
|
||
| 4 | 采信自述「函数组壳已存在」 | 实查 TFDIR 0 行,对象从未落地 | 铁律 1(实测判定)+ 铁律 3 |
|
||
| 5 | 批量生成 DDIC 的工具报表反复 500/转储 | 34 分钟会话耗尽,零交付 | 逐个落对象;`run-program` 不稳定见下方「DDIC 落地方案」 |
|
||
| 6 | 多个会话并发改同一批对象 | 相互覆盖,效率崩盘 | 铁律 4(单工作者) |
|
||
| 7 | 未读技能就试错(`delete` 交互确认) | 白撞 EOFError 一轮 | 动手前先读 SKILL.md 与 references |
|
||
| 8 | `download --path ./src` 平铺下载,不建开发包/对象层 | 25 个 .abap 堆在 `src/` 根下,结构不合格需返工归位 | 铁律 5(src 三层结构 + `--path` 指向对象类型目录) |
|
||
|
||
## 🔄 Standard Workflow(SAP 对象操作标准流程)
|
||
|
||
> 所有 SAP 对象修改操作必须按此顺序执行,不得跳过或调整步骤顺序。
|
||
|
||
```
|
||
步骤1 info — 确认程序存在、已激活、关联请求号
|
||
├─ 有请求号 → 记录
|
||
└─ 无请求号 → transport list 找老板的请求号推荐
|
||
→ 无合适的则帮老板新建(含请求描述)
|
||
|
||
步骤2 download — 源码下载到本地
|
||
|
||
步骤3 五角色流水线:研究员 → 创作者 → 质检 → 老板批准
|
||
|
||
步骤4 建 Gitee 仓库(ADT 层级:src/包/类型/对象/)+ 同步确认请求号
|
||
└─ 请求号写入 doc 文档
|
||
|
||
步骤5 工程师改代码(本地,不 commit)
|
||
|
||
步骤6 请求号绑定对象(如 SE09 未自动绑定)
|
||
|
||
步骤7 sync --corr_nr → 语法检查 → 迭代修复 → 激活成功
|
||
└─ 全程带请求号,不要到编译阶段才关联
|
||
|
||
步骤8 激活成功 → git commit + tag → push
|
||
└─ git = 细粒度变更追溯 / 请求号 = 系统大版本管理
|
||
```
|
||
|
||
**核心原则:**
|
||
- info 同时查请求号,不单独处理
|
||
- 建 Gitee 仓库同时确认请求号,不滞后
|
||
- sync 全程带 `--corr_nr`,不等编译阶段补
|
||
- 只有激活成功才 git commit,不是每次本地改就提交
|
||
- git 管变更细节,请求号管系统大版本
|
||
|
||
## 📦 Gitee仓库规范
|
||
|
||
### 目录结构(ADT 层级)
|
||
|
||
> ⛔ **本节即铁律 5 的唯一合法层次**:`src/TMP/<对象类型>/<代码文件>`(本地开发固定 `TMP`,对象有正式包后用包名)。`.abap` 平铺在 `src/` 根下、或跳过开发包层,均为不合格。
|
||
|
||
每个 SAP 项目的 Gitee 仓库按 ADT 层级组织源码:
|
||
|
||
```
|
||
sap-<project-name>/
|
||
├── src/
|
||
│ └── <package>/ # SAP 包名(如 $ZIDTR)
|
||
│ ├── report/ # 程序类型目录
|
||
│ │ └── ZXXX.abap # ABAP 源码(.abap 扩展名)
|
||
│ ├── class/
|
||
│ │ └── ZCL_XXX.abap
|
||
│ ├── interface/
|
||
│ │ └── ZIF_XXX.abap
|
||
│ ├── function/
|
||
│ │ └── ZGROUP_ZFUNC.abap
|
||
│ ├── domain/
|
||
│ ├── dataelement/
|
||
│ ├── table/
|
||
│ └── ...
|
||
├── doc/ # 文档(请求号记录、设计说明)
|
||
│ └── transport-<corr_nr>.md # 每次传输的请求号记录
|
||
├── references/ # 参照文档
|
||
└── log/ # 错误知识库
|
||
```
|
||
|
||
### 请求号同步确认
|
||
|
||
1. **创建仓库时**:确认传输请求号(`transport list` 或 `transport info --corr_nr DEVK9XXXXX`),写入 `doc/transport-<corr_nr>.md`
|
||
2. **每次 sync 前**:确认请求号仍有效(未释放、未满),检查 `transport objects --corr_nr DEVK9XXXXX` 确保对象已绑定
|
||
3. **激活成功后**:更新 `doc/` 记录本次变更摘要
|
||
4. **仓库命名建议**:`sap-<package-name>`,小写、hyphen 分隔,如 `sap-zidtradmin`
|
||
|
||
### Git 提交时机
|
||
|
||
- **只有 `sync` 激活成功后才 git commit**,不是每次本地修改就提交
|
||
- commit message 包含:对象名 + 请求号 + 变更摘要
|
||
- tag 使用请求号命名:`DEVK9XXXXX`
|
||
- git 管变更细节追溯,请求号管系统大版本管理
|
||
|
||
## Error Handling (Quick Reference)
|
||
|
||
错误知识库: `log/` 目录(LLM-WIKI 格式),每个错误独立一页。**先查 log/,再查 `references/error-handling.md`**。新错误按 `log/SCHEMA.md` 规范入库。
|
||
|
||
Full flow: `references/error-handling.md`.
|
||
|
||
| Error Pattern | Action |
|
||
|---|---|
|
||
| HTTP 406 (DDIC Lock) | System limit — report to user → SE09 manual DDIC sync |
|
||
| HTTP 403 (Locked) | Residual enqueue lock — try `run-program` clear-locks report, then SM12 |
|
||
| HTTP 400 (SaveFailure) | Class DEFINITION mismatch — diff local vs SAP source |
|
||
| HTTP 404 (DDIC download/sync) | NW 7.40 has no `/source/main` endpoint (7.50+) — DDIC objects only create/info/delete |
|
||
| HTTP 423 (Transport lock) | Object bound to transport — report to user → SE09 |
|
||
| HTTP 500 (set_source) | Lock 成功但写入 500,传输请求中无对象 → SE09 手动添加对象到请求 → `log/adt-set-source-500.md` |
|
||
| DDIC 文本不持久化(NW740) | ADT POST 创建域/数据元素后 DD01T 0 行 / DD04T 占位名 / DD07T 0 行——**ADT create 不写任何文本**。工法:工具报表内 `DDIF_DOMA_GET→改 ddtext/dd07v-ddtext→DDIF_DOMA_PUT→DDIF_DOMA_ACTIVATE`(DTEL 同理 DD04V)。坑:①DDIF_DTEL_PUT 签名仅 NAME/DD04V_WA;②GET 返回的 dd07v 行 ddlanguage 为空,PUT 必须补 `ddlanguage='E'`;③dd07v 每行必须带 domname 否则整 PUT 拒收 subrc=2;④TABL/STRUCT 盲 PUT 后 ACTIVATE rc=8 静默失败(新版本停 N),必须先 GET(state='A')→改文本→PUT;⑤string 传 DDIF 的 name 参数须先 `DATA lv_obj TYPE ddobjname`;⑥验证 SELECT 必须 `AS4LOCAL='A'` 过滤(重 PUT 后 N+A 双行);⑦多语言:逐语言 PUT→最后一次激活(混语言单 PUT subrc=6 拒收);⑧TR_TADIR_INTERFACE 在 programrun 上下文返回 OK 但静默不落 TADIR(含 wi_test_modus=' ',两次实证)——TADIR 指派只能 SE11。**泛化工具:ABAP_Integrated/tools/ddic-tool/(engine.template.abap + gen_tool.py + RUNBOOK.md,多语言版全绿实证)** |
|
||
| oo/classes 激活 200 空响应 | K/S 型传输请求接不了 CLAS 激活(PROG/DOMA 端点不受限)——POST 200 但对象恒 inactive。判据:日志 `Object still inactive after retry`。出路:SE09 建 W 型工作台请求或 SAP GUI 右键 Activate |
|
||
| oo/classes 写入 500 "unknown comments" | IMPLEMENTATION 与 METHOD 之间的 `*"` 块注释不能存储——把类级注释移进 METHOD 体内 |
|
||
| PUT 源码后 DD02L 恒 N 态 | DD03L 内部类型名是 STRG 不是 SE11 界面显示的 STRING;comptype:数据元素引用='E'(非 'D')、结构引用='S' |
|
||
| Activate fails, still inactive | double-activate built-in; still fails → report → SE09 |
|
||
| Open SQL @ 转义不一致 | 语法检查 2 错误——一处用 `@` 则全局必须一致(`WHERE field = @lv_var` → `INTO TABLE @lt_data`) → `log/adt-nw740-open-sql-consistency.md` |
|
||
| `WITH EMPTY KEY` dump | NW 7.40 unsupported — use `WITH NON-UNIQUE KEY` / `WITH DEFAULT KEY` |
|
||
| Function name error | Missing `/` separator — use `ZGROUP/Z_FUNC` |
|
||
| EOFError on delete | Non-interactive — prepend `echo "yes" \|` |
|
||
| Syntax: "此处不允许逗号" | NW 7.40 逗号陷阱(9种) → `log/adt-nw740-comma-traps.md` |
|
||
|
||
General flow: **diagnose** (params / file / transport / network / object existence) → **usage error**: fix & retry → **sap-cli limit**: report, never bypass → **SAP limit**: exhaust automation below → **confirmed un-automatable**: request SAP GUI op.
|
||
|
||
Automation fallbacks — exhaust in order before requesting any SAP GUI action:
|
||
1. **Adjust params** — different `--corr_nr`, or `--dry-run` to preview a batch before committing.
|
||
2. **`run-program` workaround** — sync + run a helper report (e.g. `ZSAPILOT_CLEAR_LOCKS`) to clear residual enqueue locks.
|
||
3. **`delete` + recreate** — only if the object needs a full rewrite; `delete` may fail with HTTP 423 (transport-bound) → then it is SE09.
|
||
4. **`activate` retry** — double-activate is built in; if it still fails, stop retrying and report — do not chase other activation strategies.
|
||
|
||
- **Never bypass sap-cli** (no requests / curl / ADTClient) — report the failure and its cause.
|
||
- **Give the complete change checklist at once** — do the full comparison first (`show-table` vs code field refs); never surface issues incrementally.
|
||
- **System-table writes** — 4-step authorization: explain *** → list exact statements → state risks & alternatives → await explicit approval.
|
||
|
||
## NW 7.40 Compatibility (E2E verified — 2.5.1)
|
||
|
||
Full matrix: `docs/NW740-COMPATIBILITY.md`.
|
||
|
||
| Availability | Types |
|
||
|---|---|
|
||
| Full (download → edit → sync closed loop) | `report`, `class`, `interface`, `function`, `functiongroup`, `include` |
|
||
| CRUD only (create/info/delete, no source edit) | `domain`, `dataelement` — DDIC stored as XML at object URI, no `/source/main` endpoint (7.50+ feature) |
|
||
| Endpoint missing (404/415) | `table`, `structure`, `tabletype`, `view`, `messageclass`, `searchhelp`, `lockobject`, `cdsview` |
|
||
|
||
NW 7.40 specifics:
|
||
- **DDIC Lock** — `delete` fixed (dedicated Accept header); `sync` still 406.
|
||
- **Activation false-negative** — first activate may report failure but actually succeed; double-activate is built in.
|
||
- **ABAP syntax limits** — no string templates `\|...\|`, no inline `DATA(...)`, no `WITH EMPTY KEY`.
|
||
- **Open SQL @ 转义一致性** — NW 7.40 要求一处用 `@` 则全 SQL 必须一致(`WHERE field = @lv_var` → `INTO TABLE @lt_data`),混用导致语法检查 2 错误。详见 `log/adt-nw740-open-sql-consistency.md`。
|
||
- **set_source HTTP 500(传输请求无对象)** — Lock 成功但写入 500,根因:Lock API 创建锁句柄但未绑定对象到传输请求。NW 7.40 需 SE09 手动添加。详见 `log/adt-set-source-500.md`。
|
||
- **DDIC 文本不持久化(S4T 实测 2026-09-14)** — ADT POST 创建域/数据元素不落任何文本(DD01T/DD07T 0 行、DD04T 只剩对象名占位),且建对象时无论 XML 是否带 description。sap-cli 侧已补 JSON description 消费(--description > JSON.description > 对象名),但 NW740 服务端仍不落库——批量落 DDIC 文本用「工具报表 + DDIF_*_GET→PUT→ACTIVATE」补写工法(泛化工具三件套:ABAP_Integrated/tools/ddic-tool/ —— gen_tool.py 渲染 engine.template.abap 生成可上传报表,内嵌 JSON + /UI2/CL_JSON 动态解析(S4T 实证存在且三层嵌套深结构可用)+ 四类对象 PUT/ACTIVATE + 内建取证报告,五步工法与 12 条实证坑见其 RUNBOOK.md)。
|
||
- **CSRF token** — all writes require it; sap-cli handles automatically.
|
||
|
||
### DDIC 结构/表类型落地方案(NW 7.40 无 ADT 端点时)
|
||
|
||
`create --type structure|tabletype` 在 NW 7.40 报 404/415(端点缺失)。可用落地路径:自研落地报表 + `run-program`:
|
||
|
||
1. `upload` 一个工具报表到 `$TMP`,内部调 `DDIF_TABL_PUT`(结构)/ `DDIF_TTYP_PUT`(表类型)写 DDIC,再调 `DDIF_TABL_ACTIVATE` / `DDIF_TTYP_ACTIVATE` 激活
|
||
2. `run-program --name <工具报表>`
|
||
3. `read-table DD02L`(结构)/ `DD40L`(表类型)实查确认 `AS4LOCAL = 'A'`
|
||
|
||
踩坑(S4T 实测):
|
||
- **`DD_OBJ_ACTIVATOR` 会转储** — 必须用 `DDIF_TABL_ACTIVATE` / `DDIF_TTYP_ACTIVATE`
|
||
- **`run-program` 端点不稳定** — 一次性批量生成全部结构的工具会反复 500/转储;**逐个落**才稳态
|
||
- **结构不写 TADIR** — 落地后的结构在 DD02L/DD40L 可见但 TADIR 查不到,清点必须查字典表,不能用 TADIR 代替
|
||
- **清理脚手架用 `delete`** — 需 `echo "yes" \|` 管道确认(见约束 5);删完用 TADIR/DD02L 独立复核,不采信 delete 回显
|