界面已本地化;技能介绍与说明文档按所选语言由 AI 自动翻译,代码、命令、路径和专业术语保留原文,以原作者文档为准。
探索技能
效率与协作 · SKILL.md

add-support-for-new-adt-object-type

add-support-for-new-adt-object-type

【效率与协作】Implement new ADT object type handler with full read/write support and command line interface.

独立 GitHub 快照 · 自动分类 · 以原作者文档为准

技能说明

GitHub

name: add-support-for-new-adt-object-type description: Implement new ADT object type handler with full read/write support and command line interface. argument-hint: [capture-adt-http-communication-file-name]

How to add a new ADT object

The architecture is briefly explained at doc/architecture.md.

Prerequisite 1: captured ADT HTTP traffic

Either use ABAP Communication log of the ADT frontend (Eclipse) or use mitmproxy to capture the ADT HTTP traffic of the object you want to add.

The GET request defines ADT object URL. The URL consists of:

  • the prefix /sap/bc/adt/
  • the object category & type (e.g. oo/classes for ABAP classes)
  • the object name
  • and perhaps more (unfortunately, we are not aware of ADT API documentation)

The GET object object also defines objects mime-type:

  • Header: Accept: application/vnd.sap.adt.oo.classes.v4+xml

The response contains the XML representation of the object. The root node of the XML contains the namespace which is required for the class level object OBJTYPE.

<?xml version="1.0" encoding="utf-8"?>
<class:abapClass
    xmlns:class="http://www.sap.com/adt/oo/classes"
    xmlns:adtcore="http://www.sap.com/adt/core"
    class:final="true"
    adtcore:responsible="DEVELOPER"
    adtcore:name="ZCL_HELLO_WORLD"
    adtcore:type="CLAS/OC"
    adtcore:changedAt="2019-03-07T20:22:01Z"
    adtcore:version="active"
    adtcore:descriptionTextLimit="60" adtcore:language="EN">

...

<class:abapClass>

Always force the user to provide full capture of the ADT HTTP communication for the object type to be added. This is required to correctly create fixtures and then implement the deserialization and serialization of the object.

Step 1: create fixtures for the new class

In the directory test/unit, create the file fixtures_sap_adt_my_object.py.

# Expected Object Name in XML response and request, e.g. <adtcore:name>MY_OBJECT</adtcore:name>
MY_OBJECT_NAME='MY_OBJECT'

# Respose sent by ADT for GET request of an existing object.
MY_OBJECT_ADT_GET_EXSITING_RESPONSE_XML="""<?xml version="1.0" encoding="utf-8"?>
...
"""

# Expected request body for POST request to create the object. This is required
# to test if the object is correctly serialized to XML.
MY_OBJECT_ADT_NEW_OBJECT_REQUEST_XML="""<?xml version="1.0" encoding="utf-8"?>
...
"""

# Expected request body for PUT request to update the object ...
MY_OBJECT_ADT_UPDATE_FIELD_REQUEST__XML="""<?xml version="1.0" encoding="utf-8"?>
...
"""

# Expected response body for ..

Never change or deduce the XML structure. You can only update the values of the nodes and attributes to match the new object.

If the XML structure is not clear. Ask the user to clarify and provide full XML response and request examples for the object type to be added.

Step 2: create a new class for the ADT object

Either create a new file or place into a file with objects of the same category in the directory sap/adt/.

class MyObject(ADTObject):
    """This is a wrapper for the ADT object type MyObject."""

    OBJTYPE = ADTObjectType(
        <attribute adtcore:type -> CLAS/OC>,
        <URL object category/type -> oo/classes>,
        # Root element namespace -> http://www.sap.com/adt/oo/classes
        xmlns_adtcore_ancestor('classes', 'http://www.sap.com/adt/oo/classes'),
        <the content of the header Accept -> 'application/vnd.sap.adt.oo.classes.v4+xml'>,
        # If the object is composed of multiple parts: e.g. metadata and source code.
        # If the object is composed of single part, use None.
        <mime type to URL part mapping -> 'text/plain': 'source/main'>
        <root element of the XML response -> abapClass>,
        # If the object has a source code part, the write operation requires
        # to send the source code in a separate request. This attribute defines
        # the handler for writing the source code part.
        # If the object does not have a source code part, use None.
        editor_factory=ADTObjectSourceEditor
    )

    def __init__(self, connection, name, package=None, metadata=None):
        super().__init__(connection, name, metadata)

        self._metadata.package_reference.name = package

Step 3: export the new class

Export the new type MyObject in the file @sap/adt/init.py.

from sap.adt.my_object import MyObject

Step 4: create tests for the new class

In the directory test/unit, crate the file test_sap_adt_my_object.py.

Purpose of the test is to verify object deserialization from the XML response and serialization to the XML request.

Sample test cases is located at assets/new_object_mapper_tests.py.

Step 5: add command line interface

In the directory sap/cli, create the file my_object.py.

If your object does not need anything fancy, you can just use the template class CommandGroupObjectMaster @sap/cli/object.py which defines read, write, delete, and activate operations for the object.

"""Command line interface for MyObject ADT object."""

import sap.adt
import sap.cli.object


class CommandGroup(sap.cli.object.CommandGroupObjectMaster):
    """Adapter converting command line parameters to sap.adt.MyObject
       calls.
    """

    def __init__(self):
        super().__init__('dataelement')

        self.define()

    def instance(self, connection, name, args, metadata=None):
        return sap.adt.MyObject(connection, name.upper(), package=args.package, metadata=metadata)

Step 6: add test for command line interface

In the directory test/unit, create the file test_sap_cli_my_object.py. Use the file assets/new_command_tests.py as a template for the tests.

The purpose of the tests is to verify that the command line interface correctly translates the command line parameters to the calls of the methods of the class MyObject and to verify that the de-serialized object is correctly printed to the console.

Step 7: hook the command line interface to the main CLI entry point

In the file sap/cli/__init__.py, import the command group class and add it to the main CLI entry point.

class CommandsCache:

    def commands()
        ...
        import sap.cli.my_object
        ...

        if CommandsCache.adt is None:
            CommandsCache.adt = [
                ...
                (adt_connection_from_args, sap.cli.my_object.CommandGroup()),
                ...
            ]

Step 8: add documentation for the command line interface

In the directory doc/cli, create the file my_object.md. Use the file assets/new_command_documentation_template.md as a template for the documentation.

The documentation must contain all commands and options returned by the new command help. Run sapcli my-object --help to get the list of commands and options.

Checklist:

  • ADT object class has serilization and deserialization implemented and tested
  • Command line iterface documentation matches output of the command help
  • The command make check runs without errors
我的收藏