Skip to content

Commit

Permalink
tree-wide: add support for ABAP Structures CRUD
Browse files Browse the repository at this point in the history
Unit test for sapcli structures support

Documentation for sapcli structures
  • Loading branch information
filak-sap authored and Libor Bucek committed Sep 11, 2023
1 parent b9ba9aa commit 1c3d83a
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 2 deletions.
5 changes: 3 additions & 2 deletions doc/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
18. [flp](commands/flp.md) - Fiori Launchpad
19. [rap](commands/businessservice.md) - RAP Business Services
20. [strust](commands/strust.md) - SSL Certificates
21. [table](commands/table.md) - ABAP DDIC transparent tables
21. [badi](commands/badi.md) - New style (Enhancements) BAdI operations
21. [structure](commands/structure.md) - ABAP DDIC structures
22. [table](commands/table.md) - ABAP DDIC transparent tables
23. [badi](commands/badi.md) - New style (Enhancements) BAdI operations
50 changes: 50 additions & 0 deletions doc/commands/structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Table

- [Table](#table)
- [create](#create)
- [write](#write)
- [activate](#activate)
- [read](#read)

## create

Create ABAP DDIC structure.

```bash
sapcli structure create [--corrnr TRANSPORT] "STRUCTURE_NAME" "Description" "PACKAGE_NAME"
```

* _--corrnr TRANSPORT_ specifies CTS Transport Request Number **(optional)**

## write

Change the definition of ABAP DDIC structure.

```bash
sapcli structure write [STRUCTURE_NAME|-] [FILE_PATH+|-] [--corrnr TRANSPORT] [-a|--activate] [--ignore-errors] [--warning-errors]
```

* _STRUCTURE\_NAME_ specifying the name of the structure or `-` to deduce it from the file name specified by FILE\_PATH
* _FILE\_PATH_ if TABLE\_NAME is not `-`, single file path or `-` for reading _stdin_; otherwise space separated list of file paths
* _--corrnr TRANSPORT_ specifies CTS Transport Request Number **(optional)**
* _--ignore-errors_ continue activating objects ignoring errors **(optional)**
* _--warning-errors_ treat activation warnings as errors **(optional)**

## activate

Activate ABAP DDIC structure.

```bash
sapcli structure activate [--ignore-errors] [--warning-errors] STRUCTURE_NAME ...
```

* _--ignore-errors_ continue activating objects ignoring errors **(optional)**
* _--warning-errors_ treat activation warnings as errors **(optional)**

## read

Get the definition of ABAP DDIC structure.

```bash
sapcli structure read STRUCTURE_NAME
```
1 change: 1 addition & 0 deletions sap/adt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
from sap.adt.businessservice import ServiceDefinition, ServiceBinding # noqa: F401
from sap.adt.table import Table # noqa: F401
from sap.adt.enhancement_implementation import EnhancementImplementation # noqa: F401
from sap.adt.structure import Structure # noqa: F401
22 changes: 22 additions & 0 deletions sap/adt/structure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""ABAP Structure ADT functionality module"""

from sap.adt.objects import ADTObject, ADTObjectType, xmlns_adtcore_ancestor, ADTObjectSourceEditor


class Structure(ADTObject):
"""ABAP Structure"""

OBJTYPE = ADTObjectType(
'TABL/DS',
'ddic/structures',
xmlns_adtcore_ancestor('blue', 'http://www.sap.com/wbobj/blue'),
'application/vnd.sap.adt.structures.v2+xml',
{'text/plain': 'source/main'},
'blueSource',
editor_factory=ADTObjectSourceEditor
)

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

self._metadata.package_reference.name = package
2 changes: 2 additions & 0 deletions sap/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def commands():
import sap.cli.rap
import sap.cli.table
import sap.cli.badi
import sap.cli.structure

if CommandsCache.adt is None:
CommandsCache.adt = [
Expand All @@ -67,6 +68,7 @@ def commands():
(adt_connection_from_args, sap.cli.abapgit.CommandGroup()),
(adt_connection_from_args, sap.cli.rap.CommandGroup()),
(adt_connection_from_args, sap.cli.table.CommandGroup()),
(adt_connection_from_args, sap.cli.structure.CommandGroup()),
(adt_connection_from_args, sap.cli.checkin.CommandGroup()),
(adt_connection_from_args, sap.cli.badi.CommandGroup()),
]
Expand Down
20 changes: 20 additions & 0 deletions sap/cli/structure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Operations on top of ABAP Structure"""

import sap.adt
import sap.cli.object


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

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

self.define()

def instance(self, connection, name, args, metadata=None):
package = getattr(args, 'package', None)

Check warning on line 18 in sap/cli/structure.py

View check run for this annotation

Codecov / codecov/patch

sap/cli/structure.py#L18

Added line #L18 was not covered by tests

return sap.adt.Structure(connection, name, package, metadata)

Check warning on line 20 in sap/cli/structure.py

View check run for this annotation

Codecov / codecov/patch

sap/cli/structure.py#L20

Added line #L20 was not covered by tests
59 changes: 59 additions & 0 deletions test/unit/fixtures_adt_structure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
STRUCTURE_NAME = 'TEST_STRUCTURE'

STRUCTURE_DEFINITION_ADT_XML = f'''<?xml version="1.0" encoding="utf-8"?>
<blue:blueSource xmlns:blue="http://www.sap.com/wbobj/blue"
abapsource:sourceUri="./{STRUCTURE_NAME.lower()}/source/main"
abapsource:fixPointArithmetic="false"
abapsource:activeUnicodeCheck="false"
adtcore:responsible="DEVELOPER"
adtcore:masterLanguage="EN"
adtcore:masterSystem="C50"
adtcore:abapLanguageVersion="standard"
adtcore:name="{STRUCTURE_NAME}"
adtcore:type="TABL/DS"
adtcore:changedAt="2023-09-11T11:38:40Z"
adtcore:version="active"
adtcore:createdAt="2023-09-11T00:00:00Z"
adtcore:changedBy="DEVELOPER"
adtcore:createdBy="DEVELOPER"
adtcore:description="Test structure"
adtcore:language="EN"
xmlns:abapsource="http://www.sap.com/adt/abapsource"
xmlns:adtcore="http://www.sap.com/adt/core">
<atom:link href="./{STRUCTURE_NAME.lower()}/source/main/versions" rel="http://www.sap.com/adt/relations/versions" title="Historic versions" xmlns:atom="http://www.w3.org/2005/Atom"/>
<atom:link href="/sap/bc/adt/repository/informationsystem/abaplanguageversions?uri=%2Fsap%2Fbc%2Fadt%2Fddic%2Fstructures%2F{STRUCTURE_NAME.lower()}" rel="http://www.sap.com/adt/relations/informationsystem/abaplanguageversions" type="application/vnd.sap.adt.nameditems.v1+xml" title="Allowed ABAP language versions" xmlns:atom="http://www.w3.org/2005/Atom"/>
<atom:link href="./{STRUCTURE_NAME.lower()}/source/main" rel="http://www.sap.com/adt/relations/source" type="text/plain" title="Source Content" etag="20230911113840001text/plain2" xmlns:atom="http://www.w3.org/2005/Atom"/>
<atom:link href="./{STRUCTURE_NAME.lower()}/source/main" rel="http://www.sap.com/adt/relations/source" type="text/html" title="Source Content (HTML)" etag="" xmlns:atom="http://www.w3.org/2005/Atom"/>
<atom:link href="/sap/bc/adt/vit/wb/object_type/tablds/object_name/{STRUCTURE_NAME}" rel="self" type="application/vnd.sap.sapgui" title="Representation in SAP Gui" xmlns:atom="http://www.w3.org/2005/Atom"/>
<atom:link href="/sap/bc/adt/vit/docu/object_type/tb/object_name/{STRUCTURE_NAME.lower()}?masterLanguage=E&amp;mode=edit" rel="http://www.sap.com/adt/relations/documentation" type="application/vnd.sap.sapgui" title="Documentation" xmlns:atom="http://www.w3.org/2005/Atom"/>
<atom:link href="/sap/bc/adt/ddic/logs/db/ACTTABL{STRUCTURE_NAME}" rel="http://www.sap.com/adt/relations/ddic/activationlog" type="application/vnd.sap.adt.logs+xml" title="Activation Log" xmlns:atom="http://www.w3.org/2005/Atom"/><adtcore:packageRef adtcore:uri="/sap/bc/adt/packages/%24zlb_hex_playground" adtcore:type="DEVC/K" adtcore:name="PACKAGE" adtcore:description="HEX comparator playground"/>
</blue:blueSource>'''

CREATE_STRUCTURE_ADT_XML = f'''<?xml version="1.0" encoding="UTF-8"?>
<blue:blueSource xmlns:blue="http://www.sap.com/wbobj/blue" xmlns:adtcore="http://www.sap.com/adt/core" adtcore:type="TABL/DS" adtcore:description="Test structure" adtcore:language="EN" adtcore:name="{STRUCTURE_NAME}" adtcore:masterLanguage="EN" adtcore:responsible="DEVELOPER" adtcore:version="inactive">
<adtcore:packageRef adtcore:name="PACKAGE"/>
</blue:blueSource>'''

READ_STRUCTURE_BODY = '''@EndUserText.label : 'Test structure'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
define structure test_structure {
client : abap.clnt;
foo : abap.clnt;
}'''

WRITE_STRUCTURE_BODY = '''@EndUserText.label : 'Test structure'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
define structure test_structure {
client : abap.clnt;
bar : abap.clnt;
}'''

FAKE_LOCK_HANDLE = 'lock_handle'

ACTIVATE_STRUCTURE_BODY = f'''<?xml version="1.0" encoding="UTF-8"?>
<adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
<adtcore:objectReference adtcore:uri="/sap/bc/adt/ddic/structures/{STRUCTURE_NAME.lower()}" adtcore:name="{STRUCTURE_NAME}"/>
</adtcore:objectReferences>'''
40 changes: 40 additions & 0 deletions test/unit/test_sap_adt_structure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python3

import logging
import unittest
import sap.adt

from mock import Connection, Response, Request
from fixtures_adt_structure import STRUCTURE_DEFINITION_ADT_XML, STRUCTURE_NAME, CREATE_STRUCTURE_ADT_XML


class TestADTStructure(unittest.TestCase):

def test_structure_fetch(self):
connection = Connection([Response(text=STRUCTURE_DEFINITION_ADT_XML, status_code=200, headers={})])

structure = sap.adt.Structure(connection, STRUCTURE_NAME)
structure.fetch()

self.assertEqual(structure.name, STRUCTURE_NAME)
self.assertEqual(structure.active, 'active')
self.assertEqual(structure.master_language, 'EN')
self.assertEqual(structure.description, 'Test structure')

def test_structure_serialize(self):
connection = Connection()

metadata = sap.adt.ADTCoreData(description='Test structure', language='EN', master_language='EN',
responsible='DEVELOPER')
structure = sap.adt.Structure(connection, STRUCTURE_NAME, package='PACKAGE', metadata=metadata)
structure.create()

expected_request = Request(
adt_uri='/sap/bc/adt/ddic/structures',
method='POST',
headers={'Content-Type': 'application/vnd.sap.adt.structures.v2+xml; charset=utf-8'},
body=bytes(CREATE_STRUCTURE_ADT_XML, 'utf-8'),
params=None
)

self.assertEqual(connection.execs[0], expected_request)

0 comments on commit 1c3d83a

Please sign in to comment.