--- name: sap-cli description: "SAP ABAP ADT CLI for AI agents. Trigger when: operating ABAP objects, syncing code to/from SAP, managing transports, querying DDIC, running ABAP programs, reading SAP tables, or any SAP development task via terminal." version: "2.3.0" 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**. ## Quick Start ```bash # 1. Single object: download → edit → sync python main.py download --name ZMY_CLASS --type class --path ./src # edit ./src/zmy_class.abap python main.py sync --name ZMY_CLASS --type class --path ./src/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 Global params (before command): `--profile `, `--verify-ssl`. Optional params in `[ ]`. | 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) | | Batch | `init` | `--path` | | Batch | `refresh` | `--path` | | Batch | `sync --all` | `--path --corr_nr [--dry-run]` | | Batch | `analyze` | `--path` (dependency analysis) | | 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) | | Transport | `transport list` | — | | Transport | `transport info` | `--corr_nr` | | Transport | `transport release` | `--corr_nr` | | Transport | `transport objects` | `--corr_nr` | | Config | `config show` | — | | Config | `config list-profiles` | — | | Config | `config set` | ` ` | | 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 | `package create` | `--name` | | Other | `cds download` | `--name --path` | | Other | `scaffold` | `--name --template ` — alv-report, bapi-wrapper, interface-class, data-model | [^1]: ⚠️ `info` 不返回 `package`/`packageRef` 字段。需通过 ADT API 查询:`GET /sap/bc/adt/programs/programs/` 返回 XML 中含 ``。也可用 `list --package ` 反向查找。 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/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`. ## ⚠️ 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 ` 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. ## 🔄 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 层级) 每个 SAP 项目的 Gitee 仓库按 ADT 层级组织源码: ``` sap-/ ├── src/ │ └── / # SAP 包名(如 $ZIDTR) │ ├── report/ # 程序类型目录 │ │ └── ZXXX.abap # ABAP 源码(.abap 扩展名) │ ├── class/ │ │ └── ZCL_XXX.abap │ ├── interface/ │ │ └── ZIF_XXX.abap │ ├── function/ │ │ └── ZGROUP_ZFUNC.abap │ ├── domain/ │ ├── dataelement/ │ ├── table/ │ └── ... ├── doc/ # 文档(请求号记录、设计说明) │ └── transport-.md # 每次传输的请求号记录 ├── references/ # 参照文档 └── log/ # 错误知识库 ``` ### 请求号同步确认 1. **创建仓库时**:确认传输请求号(`transport list` 或 `transport info --corr_nr DEVK9XXXXX`),写入 `doc/transport-.md` 2. **每次 sync 前**:确认请求号仍有效(未释放、未满),检查 `transport objects --corr_nr DEVK9XXXXX` 确保对象已绑定 3. **激活成功后**:更新 `doc/` 记录本次变更摘要 4. **仓库命名建议**:`sap-`,小写、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` | | 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 — v2.3.0) 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`。 - **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 回显