chore: sync skill to v2.2.1

- NW 7.40 E2E-verified compatibility matrix in SKILL.md
- DDIC fixes: include namespace, tabletype exists check, DDIC delete lock Accept
- New commands: clone, enhancement, history, unit-test
- 665 tests, 96% coverage
This commit is contained in:
2026-07-10 19:13:46 +08:00
parent 3a7fba0860
commit 38e99638c5
16 changed files with 951 additions and 16 deletions
+46 -4
View File
@@ -56,6 +56,39 @@ DEFAULT_TEMPLATES: dict[str, str] = {
' METHODS: hello.\n'
'ENDINTERFACE.\n'
),
# 以下类型不提供完整业务骨架,仅给出占位注释。
# 建议通过 --source 指定本地源码文件,或用 --definition 创建 DDIC 定义。
"include": (
'*&---------------------------------------------------------------------*\n'
'*& Include {name}\n'
'*&---------------------------------------------------------------------*\n'
'* Include 程序骨架:在此编写可被其它程序 INCLUDE 的 ABAP 片段。\n'
'* 提示:用 --source 指定本地源码文件可覆盖本模板。\n'
),
"messageclass": (
'* Message Class {name}\n'
'* 消息类(T100)不包含 ABAP 源码,消息条目通过 SE91 维护。\n'
'* 提示:建议用 --definition 创建,或通过 SAP GUI (SE91) 维护消息。\n'
),
"view": (
'* Database View {name}\n'
'* 数据库视图 DDL 骨架(基础 SELECT 形式,按需替换):\n'
'* SELECT <字段列表>\n'
'* FROM <主表>\n'
'* [JOIN <关联表> ON <条件>]\n'
'* [WHERE <过滤条件>]\n'
'* 提示:用 --source 指定完整视图定义可覆盖本模板。\n'
),
"searchhelp": (
'* Search Help {name}\n'
'* 搜索帮助不包含 ABAP 源码,定义含数据源与显示字段。\n'
'* 提示:建议用 --definition 创建,或通过 SAP GUI (SE11) 维护。\n'
),
"lockobject": (
'* Lock Object {name}\n'
'* 锁对象不包含 ABAP 源码,定义含锁定模式与主表。\n'
'* 提示:建议用 --definition 创建,或通过 SAP GUI (SE11) 维护。\n'
),
}
@@ -92,7 +125,7 @@ def cmd_download(args: argparse.Namespace, client: ADTClient) -> None:
print(f" 保存路径: {save_dir}")
print(f"\n → 检查对象是否存在...")
if not client.object_exists(parsed.obj_uri):
if not client.object_exists(parsed.exists_uri or parsed.obj_uri):
print(f" ✗ 对象不存在: {parsed.display_name}")
print(f" 请确认名称和类型是否正确")
raise ObjectNotFoundError(parsed.display_name, obj_type)
@@ -210,7 +243,7 @@ def _sync_single(
if not quiet:
print(f"\n → 检查对象是否存在...")
if not client.object_exists(parsed.obj_uri):
if not client.object_exists(parsed.exists_uri or parsed.obj_uri):
if not quiet:
print(f" ℹ 对象不存在,自动创建空对象...")
try:
@@ -386,6 +419,15 @@ def cmd_info(args: argparse.Namespace, client: ADTClient) -> None:
"dataelement": "*/*",
"table": "*/*",
"tabletype": "*/*",
"structure": "application/vnd.sap.adt.ddic.structures.v1+xml",
"include": "application/vnd.sap.adt.programs.includes.v2+xml",
"cdsview": "application/vnd.sap.adt.ddic.ddls.v3+xml",
"messageclass": "application/vnd.sap.adt.t100.message.classes.v1+xml",
"view": "application/vnd.sap.adt.ddic.views.v1+xml",
"searchhelp": "application/vnd.sap.adt.ddic.searchhelps.v1+xml",
"lockobject": "application/vnd.sap.adt.ddic.lockobjects.v1+xml",
"dcl": "text/plain",
"ddlX": "text/plain",
}
print("=" * 60)
@@ -471,7 +513,7 @@ def cmd_delete(args: argparse.Namespace, client: ADTClient) -> None:
print(f" 对象名称: {parsed.display_name}")
print(f"\n → 检查对象是否存在...")
if not client.object_exists(parsed.obj_uri):
if not client.object_exists(parsed.exists_uri or parsed.obj_uri):
print(f" ✗ 对象不存在: {parsed.display_name}")
print(f" 请确认名称和类型是否正确")
raise ObjectNotFoundError(parsed.display_name, obj_type)
@@ -639,7 +681,7 @@ def cmd_create(args: argparse.Namespace, client: ADTClient) -> None:
print(f"\n → 检查对象是否存在...")
if obj_type != "functiongroup":
parsed = parse_object_name(name, obj_type)
if client.object_exists(parsed.obj_uri):
if client.object_exists(parsed.exists_uri or parsed.obj_uri):
print(f" ✗ 对象已存在: {display_name}")
raise ObjectAlreadyExistsError(display_name, type_label)
else: