Files
sap-cli-skill/SKILL.md
T

23 KiB
Raw Blame History

name, description, version, author, license, triggers
name description version author license triggers
sap-cli 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. 2.5.1 WuRangyu MIT
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.

调用方式

cd <SKILL_DIR>/assets && python main.py <command> [options]

全局参数(置于命令之前):

参数 说明
--profile <name> 使用指定配置 profile
--verify-ssl 启用 SSL 验证(默认关闭)

安装与配置见同目录 INSTALL.md

Quick Start

# 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 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

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:

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.

⚠️ 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 confirmecho "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 DD02LAS4LOCAL = '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/ 根下,结构不合格需返工归位 铁律 5src 三层结构 + --path 指向对象类型目录)

🔄 Standard WorkflowSAP 对象操作标准流程)

所有 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 listtransport 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(多传 tpara_wa 运行期转储 500);②GET 返回的 dd07v 行 ddlanguage 为空,PUT 必须补 ddlanguage='E' 否则固定值文本静默丢失
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 界面显示的 STRINGcomptype:数据元素引用='E'(非 'D')、结构引用='S'
Activate fails, still inactive double-activate built-in; still fails → report → SE09
Open SQL @ 转义不一致 语法检查 2 错误——一处用 @ 则全局必须一致(WHERE field = @lv_varINTO TABLE @lt_datalog/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 Lockdelete 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_varINTO 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」补写工法(源码样板见 sap-build 之外的 ABAP_Integrated/src/ZINT.package/program/zint_pilot_ddic_tool.prog.abap),注意 DDIF_DTEL_PUT 仅 NAME/DD04V_WA 两参数、DDIF_DOMA_GET 返回的 dd07v 行 ddlanguage 为空需补 'E'。
  • 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 回显

  1. ⚠️ info 不返回 package/packageRef 字段。需通过 ADT API 查询:GET /sap/bc/adt/programs/programs/<name> 返回 XML 中含 <adtcore:packageRef>。也可用 list --package <pkg> 反向查找。 ↩︎