v2.3.0: info 新增开发包/传输请求字段 (纯只读 E071)
- info 输出新增「开发包」(packageRef)、「传输请求」(纯只读查 E071) - 优雅降级: 无请求/查询失败/非独立传输对象, 不中断 info - bump 2.2.1 -> 2.3.0 - pack 从源码同步 (含 parser/transport 最新代码)
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
sap-cli — 基于 SAP ADT REST API 的 ABAP 开发对象管理工具
|
||||
"""
|
||||
|
||||
__version__ = "2.2.1"
|
||||
__version__ = "2.3.0"
|
||||
|
||||
@@ -158,6 +158,8 @@ CDS View:
|
||||
tr_release.add_argument("--corr_nr", required=True, help="传输请求编号")
|
||||
tr_objects = transport_sub.add_parser("objects", help="列出传输请求中的对象")
|
||||
tr_objects.add_argument("--corr_nr", required=True, help="传输请求编号")
|
||||
tr_create = transport_sub.add_parser("create", help="新建传输请求")
|
||||
tr_create.add_argument("--description", required=True, help="传输请求描述")
|
||||
|
||||
# ── check (ATC 代码检查) ──
|
||||
check_parser = subparsers.add_parser("check", help="ATC 代码检查")
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from sapcli.client import ADTClient
|
||||
@@ -18,7 +19,7 @@ from sapcli.exceptions import (
|
||||
SapCliError,
|
||||
)
|
||||
from sapcli.manifest import Manifest, ManifestEntry
|
||||
from sapcli.types import get_type_config, parse_object_name
|
||||
from sapcli.types import get_r3tr_object_code, get_type_config, parse_object_name
|
||||
|
||||
DDIC_TYPES = {"domain", "dataelement", "table", "structure", "tabletype"}
|
||||
|
||||
@@ -401,6 +402,30 @@ def _update_manifest_after_sync(
|
||||
logger.warning("更新清单失败: %s", e)
|
||||
|
||||
|
||||
def _query_transport_request(
|
||||
client: ADTClient, obj_type: str, display_name: str
|
||||
) -> str:
|
||||
"""查对象当前所在(未释放)的传输请求号。纯只读查 E071;失败优雅降级。"""
|
||||
r3tr_code = get_r3tr_object_code(obj_type)
|
||||
if not r3tr_code:
|
||||
return "—(非独立传输对象)"
|
||||
obj_name_upper = display_name.upper().split("/")[-1]
|
||||
if not re.fullmatch(r"[A-Za-z0-9_/$]+", obj_name_upper):
|
||||
return "(对象名非法,跳过)"
|
||||
try:
|
||||
sql = (
|
||||
f"SELECT trkorr FROM e071 WHERE pgmid='R3TR' "
|
||||
f"AND object='{r3tr_code}' AND obj_name='{obj_name_upper}' "
|
||||
f"UP TO 10 ROWS"
|
||||
)
|
||||
result = client.query_table_data(sql, max_rows=10)
|
||||
trkorrs = sorted({row[0] for row in result.get("rows", []) if row and row[0]})
|
||||
return ", ".join(trkorrs) if trkorrs else "无"
|
||||
except Exception:
|
||||
logger.debug("查询 E071 传输请求失败", exc_info=True)
|
||||
return "(无法获取)"
|
||||
|
||||
|
||||
def cmd_info(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
"""查询对象元数据信息。"""
|
||||
obj_type: str = args.type
|
||||
@@ -469,6 +494,14 @@ def cmd_info(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
info_responsible = root.attrib.get(f"{{{ns['adtcore']}}}responsible", "")
|
||||
info_language = root.attrib.get(f"{{{ns['adtcore']}}}masterLanguage", "")
|
||||
|
||||
# 开发包:解析对象 XML 自带的 packageRef 子元素
|
||||
pkg_ref = root.find(f".//{{{ns['adtcore']}}}packageRef")
|
||||
info_package = (
|
||||
pkg_ref.attrib.get(f"{{{ns['adtcore']}}}name", "")
|
||||
if pkg_ref is not None
|
||||
else ""
|
||||
)
|
||||
|
||||
if info_version == "active":
|
||||
status_icon = "✓ 已激活"
|
||||
elif info_version == "inactive":
|
||||
@@ -476,6 +509,9 @@ def cmd_info(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
else:
|
||||
status_icon = f"❓ {info_version}"
|
||||
|
||||
# 传输请求号:纯只读查 E071(不在对象元数据 XML 中)
|
||||
corr_display = _query_transport_request(client, obj_type, parsed.display_name)
|
||||
|
||||
print(f" ✓ 查询成功\n")
|
||||
print(f" {'─' * 50}")
|
||||
print(f" 名称: {info_name}")
|
||||
@@ -484,6 +520,8 @@ def cmd_info(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
print(f" 状态: {status_icon}")
|
||||
print(f" 负责人: {info_responsible}")
|
||||
print(f" 语言: {info_language}")
|
||||
print(f" 开发包: {info_package or '(未指定)'}")
|
||||
print(f" 传输请求: {corr_display}")
|
||||
print(f" 创建者: {info_created_by}")
|
||||
print(f" 修改者: {info_changed_by}")
|
||||
print(f" 修改时间: {info_changed_at}")
|
||||
|
||||
@@ -21,12 +21,15 @@ def cmd_transport(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
_transport_release(args, client)
|
||||
elif action == "objects":
|
||||
_transport_objects(args, client)
|
||||
elif action == "create":
|
||||
_transport_create(args, client)
|
||||
else:
|
||||
print(" 用法: sap-cli transport [list|info|release|objects]")
|
||||
print(" 用法: sap-cli transport [list|info|release|objects|create]")
|
||||
print(" list — 列出可修改的传输请求")
|
||||
print(" info — 查看传输请求详情")
|
||||
print(" release — 释放传输请求")
|
||||
print(" objects — 列出传输请求中的对象")
|
||||
print(" create — 新建传输请求 (--description)")
|
||||
|
||||
|
||||
def _transport_list(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
@@ -107,6 +110,28 @@ def _transport_release(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
print(f" ✗ 释放失败,请检查传输请求状态")
|
||||
|
||||
|
||||
def _transport_create(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
"""新建传输请求。"""
|
||||
description: str = args.description
|
||||
|
||||
print("=" * 60)
|
||||
print(" SAP 新建传输请求")
|
||||
print("=" * 60)
|
||||
print(f" 描述: {description}")
|
||||
|
||||
print(f"\n → 正在创建...")
|
||||
try:
|
||||
new_nr = client.create_transport_request(description)
|
||||
except Exception as e:
|
||||
print(f" ✗ 创建失败: {e}")
|
||||
return
|
||||
|
||||
if new_nr:
|
||||
print(f"\n ✓ 传输请求已创建: {new_nr}")
|
||||
else:
|
||||
print(f"\n ✗ 创建失败(未返回编号),请检查系统或描述合法性")
|
||||
|
||||
|
||||
def _transport_objects(args: argparse.Namespace, client: ADTClient) -> None:
|
||||
"""列出传输请求中的对象。"""
|
||||
corr_nr: str = args.corr_nr
|
||||
|
||||
@@ -227,6 +227,35 @@ def all_type_keys() -> list[str]:
|
||||
return list(_OBJECT_TYPE_REGISTRY.keys())
|
||||
|
||||
|
||||
# sap-cli 类型 → SAP 传输系统 R3TR 对象代码(用于查 E071 表)。
|
||||
# None 表示该类型非独立 R3TR 对象,查 E071 无意义。
|
||||
_R3TR_OBJECT_CODE: dict[str, str | None] = {
|
||||
"report": "PROG",
|
||||
"class": "CLAS",
|
||||
"interface": "INTF",
|
||||
"function": None, # 函数模块属函数组(FUGR),非独立 R3TR
|
||||
"functiongroup": "FUGR",
|
||||
"domain": "DOMA",
|
||||
"dataelement": "DTEL",
|
||||
"table": "TABL",
|
||||
"structure": "TABL",
|
||||
"tabletype": "TTYP",
|
||||
"include": None, # Include 属所属程序,非独立 R3TR
|
||||
"cdsview": "DDLS",
|
||||
"messageclass": "MSAG",
|
||||
"view": "VIEW",
|
||||
"searchhelp": "SHLP",
|
||||
"lockobject": "ENQU",
|
||||
"dcl": "DCLS",
|
||||
"ddlX": "DDLX",
|
||||
}
|
||||
|
||||
|
||||
def get_r3tr_object_code(key: str) -> str | None:
|
||||
"""返回对象类型对应的 SAP R3TR 传输对象代码;无独立代码返回 None。"""
|
||||
return _R3TR_OBJECT_CODE.get(key)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParsedName:
|
||||
obj_uri: str
|
||||
|
||||
Reference in New Issue
Block a user