Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Print details of an ATC/code inspector check variant (not the results)

Sandra_Rossi
Active Contributor
4,747

Hello,

The Check Variant of ATC/Code Inspector can be displayed and maintained, but I'd like to print its details into a PDF file, with all the details (see screenshots below).

The question is not about printing the results of Code Inspector, but only about printing the details of the checks done.

Is it possible? Did someone create a program? A SAP GUI Scripting script to share maybe?

Thanks a lot.

Sandra

10 REPLIES 10
Read only

FredericGirod
Active Contributor
4,630

Each time I did it manually to fit the Development rules and the checks done on the system. If you find it ...

Read only

BaerbelWinkler
SAP Champion
SAP Champion
4,629

I'd love to have that option as well but when I did some digging during setting up our ATC-systems, I didn't find anything to get a listing. And seeing that package S_CODE_INSPECTOR contains - among others - Cluster table for Check Variant Parameters (SCICHKV_PA) doesn't make me too hopeful that something exists or could easily be created.

Getting curious, I quickly ran ATC via SAT to see where that cluster table gets accessed to add a breakpoint at the "import from database" statement. This is how the retrieved data looks internally:

So, the selected checks for the variant are legible but their respective details and attributes not so much.

Sorry to not have better news for you!

Read only

Sandra_Rossi
Active Contributor
0 Likes
4,629

Thanks frdric.girod and 8b889d0e8e6f4ed39f6c58e35664518f for your feedback. Alas, the parameters of each CI Check are compressed and can only be decoded by their corresponding CI Check class. I'll wait for good answers or do same as Frederic suggested 😉

Read only

Sandra_Rossi
Active Contributor
4,628

This code snippet is a starting point. Not a satisfactory answer though, because it doesn't output the checks without parameters and I had an exception which forced me to debug and skip the wrong case (a parameter being an internal table, in CL_CI_TEST_EMPTY_UNUSED_PROCS). Test in ABAP 7.56.

baerbelwinkler For information.

TRY.
    cl_ci_checkvariant=>get_ref(
      EXPORTING
        p_user                   = space " space for global variant
        p_name                   = 'Z_GLOBAL_VARIANT'
      RECEIVING
        p_ref                    = DATA(variant)
      EXCEPTIONS
        chkv_not_exists          = 1
        missing_parameter        = 2
        broken_variant           = 3
        OTHERS                   = 4 ).
    IF sy-subrc <> 0.
      LEAVE PROGRAM.
    ENDIF.
    DATA(config) = NEW cl_ci_variant_configuration( ).
    config->variant_to_xml(
      EXPORTING
        variant = variant
      RECEIVING
        xml     = DATA(xml) ).
  CATCH cx_root INTO DATA(error).
    ASSERT 1 = 1. " debugger
ENDTRY.
The final XML:

Read only

4,628

Here's a program which does a clean "print" of the details of a Code Inspector variant. It generates an intermediate XML containing the variant tests and selected attributes, convert the XML into an ABAP internal table via a Simple Transformation Z_CI_XML_TO_ITAB, and the internal table is output as a text with indented hierarchy.

*&---------------------------------------------------------------------*
*& Report z_export_variante_ci
*&---------------------------------------------------------------------*
*&
*& https://community.sap.com/t5/application-development-and-automation-discussions/print-details-of-an-atc-code-inspector-check-variant-not-the-results/td-p/12804009
*&
*&---------------------------------------------------------------------*
REPORT z_export_variante_ci LINE-SIZE 1023.

CLASS lcl_app DEFINITION DEFERRED.

PARAMETERS variname TYPE sci_chkv OBLIGATORY DEFAULT 'ZCHECK_PROGRAM'.

SELECTION-SCREEN BEGIN OF SCREEN 1001.
  PARAMETERS dummy.
SELECTION-SCREEN END OF SCREEN 1001.

AT SELECTION-SCREEN OUTPUT.
  CASE sy-dynnr.
    WHEN '1001'.
      " Use of PBO to make warning SCI144 (CL_CI_TESTS=>GET_INITIAL_TREE) displayed
      " as status message to not interrupt the logic (as done in SCI).
      CALL METHOD lcl_app=>('CALCULATE_VARIANT_OUTPUT').
      LEAVE TO SCREEN 0.
  ENDCASE.

START-OF-SELECTION.
  TRY.
      CALL SELECTION-SCREEN 1001.
      CALL METHOD lcl_app=>('RENDER_VARIANT_OUTPUT').
      ASSERT 1 = 1. " dummy statement for setting a breakpoint (if debug needed)
    CATCH cx_root INTO DATA(error).
      MESSAGE error TYPE 'I' DISPLAY LIKE 'E'.
  ENDTRY.



CLASS lcx_system_message DEFINITION INHERITING FROM cx_no_check FINAL.
  PUBLIC SECTION.
    METHODS constructor.
    METHODS get_text     REDEFINITION.
    METHODS get_longtext REDEFINITION.

  PRIVATE SECTION.
    DATA text TYPE string.
ENDCLASS.


CLASS lcx_no_check DEFINITION INHERITING FROM cx_no_check FINAL.
  PUBLIC SECTION.
    METHODS constructor  IMPORTING !text TYPE csequence.
    METHODS get_text     REDEFINITION.
    METHODS get_longtext REDEFINITION.

  PRIVATE SECTION.
    DATA text TYPE string.
ENDCLASS.


CLASS lcl_app DEFINITION FINAL CREATE PRIVATE.

  PUBLIC SECTION.
    CLASS-METHODS calculate_variant_output.
    CLASS-METHODS render_variant_output.

  PRIVATE SECTION.
    TYPES:
      BEGIN OF ty_parameter,
        value       TYPE string,
        description TYPE string,
      END OF ty_parameter.
    TYPES ty_parameters TYPE STANDARD TABLE OF ty_parameter WITH EMPTY KEY.
    TYPES:
      BEGIN OF ty_group,
        description TYPE string,
        parameters  TYPE ty_parameters,
      END OF ty_group.
    TYPES ty_groups TYPE STANDARD TABLE OF ty_group WITH EMPTY KEY.
    TYPES:
      BEGIN OF ty_check,
        check_class_name TYPE seoclsname,
        has_attributes   TYPE abap_bool,
        parameters       TYPE ty_parameters,
        groups           TYPE ty_groups,
      END OF ty_check.
    TYPES ty_checks TYPE STANDARD TABLE OF ty_check WITH EMPTY KEY.

    CLASS-DATA checks TYPE lcl_app=>ty_checks.
    CLASS-DATA tests  TYPE sci_tabtest.
    CLASS-DATA result TYPE string_table.

    CLASS-METHODS export_category
      IMPORTING category      TYPE REF TO if_ci_test
      RETURNING VALUE(result) TYPE string_table.

    CLASS-METHODS get_variant_tree
      RETURNING VALUE(r_hier) TYPE REF TO cl_ci_tests
      RAISING   cx_parameter_invalid_range
                cx_parameter_invalid_type
                cx_sy_codepage_converter_init
                cx_sy_conversion_codepage.
ENDCLASS.


CLASS lcl_app IMPLEMENTATION.
  METHOD calculate_variant_output.
    DATA(tree) = get_variant_tree( ).

    " Export the top test category. It's a recursive method to export the child categories.
    result = export_category( tree->tree ).
  ENDMETHOD.

  METHOD render_variant_output.
    LOOP AT result REFERENCE INTO DATA(line).
      WRITE / line->*.
    ENDLOOP.
  ENDMETHOD.

  METHOD get_variant_tree.
    cl_ci_checkvariant=>get_ref( EXPORTING  p_user            = space " space for global variant
                                            p_name            = variname
                                 RECEIVING  p_ref             = DATA(variant)
                                 EXCEPTIONS chkv_not_exists   = 1
                                            missing_parameter = 2
                                            broken_variant    = 3
                                            OTHERS            = 4 ).
    CASE sy-subrc.
      WHEN 0. " ##NO_HANDLER.
      WHEN 1.
        RAISE EXCEPTION TYPE lcx_no_check
          EXPORTING text = 'Variant does not exist'.
      WHEN OTHERS.
        RAISE EXCEPTION TYPE lcx_system_message.
    ENDCASE.
    DATA(config) = NEW cl_ci_variant_configuration( ).
    DATA(xml) = config->variant_to_xml( variant = variant ).

    " Needed for ADT 3.48 debugger because of" missing "Wrap Text" feature in XSTRING XML Viewer.
    IF 0 = 1.
      DATA(xml_2) = cl_abap_codepage=>convert_from( xml ) ##NEEDED.
    ENDIF.

    checks = VALUE ty_checks( ).
    CALL TRANSFORMATION z_ci_xml_to_itab
         SOURCE XML xml
         RESULT checks = checks.

    " GET INSTANCES OF ALL TEST CLASSES SELECTED IN THE VARIANT
    variant->get_info( EXCEPTIONS could_not_read_variant = 1
                                  OTHERS                 = 2 ).
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE lcx_no_check
        EXPORTING text = 'Error of IMPORT FROM DATABASE SCICHKV_PA(AR)'.
    ENDIF.

    " ADD MISSING TESTS (those with no attributes)
    " This call is a complement of VARIANT_TO_XML which doesn't fill XML for tests without attributes.
    " NB: GET_LIST works only if called after GET_INFO.
    cl_ci_tests=>get_list( EXPORTING  p_variant       = variant->variant
                           RECEIVING  p_result        = DATA(collection_of_variant_tests)
                           EXCEPTIONS invalid_version = 1
                                      OTHERS          = 2 ).
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE lcx_no_check
        EXPORTING text = 'Version incorrecte du test dans la variante'.
    ENDIF.

    LOOP AT collection_of_variant_tests->give_list( ) INTO DATA(test)
         WHERE table_line->has_attributes = abap_false.
      INSERT VALUE #( check_class_name = test->name )
             INTO TABLE checks.
    ENDLOOP.

    " NEED TO RUN GET_TREE INSIDE DYNPRO (dynpro 1001 here) BECAUSE IT RUNS MESSAGE W144 (otherwise that stops a non-background process).
    cl_ci_tests=>get_tree( EXPORTING  p_variant          = variant->variant
                                      p_transport        = abap_false
                           RECEIVING  p_result           = r_hier
                           EXCEPTIONS invalid_category   = 1
                                      invalid_class_name = 2
                                      OTHERS             = 3 ).
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE lcx_system_message.
    ENDIF.
  ENDMETHOD.

  METHOD export_category.
    LOOP AT category->childs INTO DATA(child_test_or_category_2).
      IF child_test_or_category_2 IS INSTANCE OF cl_ci_category_root.
        DATA(intermediate_result) = export_category( child_test_or_category_2 ).
        INSERT LINES OF intermediate_result INTO TABLE result.
      ELSE.
        DATA(check) = REF #( checks[ check_class_name = child_test_or_category_2->name ] OPTIONAL ).
        IF check IS NOT BOUND.
          CONTINUE.
        ENDIF.

        INSERT |{ check->check_class_name } { child_test_or_category_2->description }| INTO TABLE result.

        IF check->has_attributes = abap_false.
          INSERT |    No attribute| INTO TABLE result.
        ELSE.

          LOOP AT check->parameters REFERENCE INTO DATA(parameter).
            INSERT |    {
                    COND #( WHEN parameter->description IS NOT INITIAL
                            THEN parameter->description
                            ELSE '(no parameter description)' )
                    } : {
                    COND #( WHEN parameter->value IS NOT INITIAL
                            THEN parameter->value
                            ELSE '(no value or false)' )
                    } {
                    child_test_or_category_2->description }|
                   INTO TABLE result.
          ENDLOOP.

          LOOP AT check->groups REFERENCE INTO DATA(group).
            INSERT |    {
                    COND #( WHEN group->description IS NOT INITIAL
                            THEN group->description
                            ELSE '(no group description)' ) }|
                   INTO TABLE result.
            LOOP AT group->parameters REFERENCE INTO parameter.
              INSERT |        {
                      COND #( WHEN parameter->description IS NOT INITIAL
                              THEN parameter->description
                              ELSE '(no parameter description)' )
                      } : {
                      COND #( WHEN parameter->value IS NOT INITIAL
                              THEN parameter->value
                              ELSE '(no value or false)' ) }|
                     INTO TABLE result.
            ENDLOOP.
          ENDLOOP.
        ENDIF.
      ENDIF.
    ENDLOOP.

    IF result IS NOT INITIAL.
      LOOP AT result REFERENCE INTO DATA(result_line).
        result_line->* = |    { result_line->* }|.
      ENDLOOP.
      INSERT |{ category->name } { category->description }| INTO result INDEX 1.
    ENDIF.
  ENDMETHOD.
ENDCLASS.


CLASS lcx_system_message IMPLEMENTATION.
  METHOD constructor.
    super->constructor( textid   = textid
                        previous = previous ).
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 INTO text.
  ENDMETHOD.

  METHOD get_longtext.
    result = text.
  ENDMETHOD.

  METHOD get_text.
    result = text.
  ENDMETHOD.
ENDCLASS.


CLASS lcx_no_check IMPLEMENTATION.
  METHOD constructor.
    super->constructor( textid   = textid
                        previous = previous ).
    me->text = text.
  ENDMETHOD.

  METHOD get_longtext.
    result = text.
  ENDMETHOD.

  METHOD get_text.
    result = text.
  ENDMETHOD.
ENDCLASS.

Simple Transformation Z_CI_XML_TO_ITAB:

<!-- https://community.sap.com/t5/application-development-and-automation-discussions/print-details-of-an-atc-code-inspector-check-variant-not-the-results/td-p/12804009 -->
<?sap.transform simple?>
<tt:transform
xmlns:tt="http://www.sap.com/transformation-templates"
xmlns:ci="https://www.sap.com/adt/codeinspector/checkvariant">
  <tt:root name="CHECKS"/>

  <tt:template>
    <ci:variant tt:extensible="deep-dynamic">
      <tt:loop ref="CHECKS">
        <check>
          <tt:attribute name="technicalName" value-ref="CHECK_CLASS_NAME"/>
          <tt:assign to-ref="HAS_ATTRIBUTES" val="'X'"/>
          <tt:loop ref="PARAMETERS">
            <parameter>
              <tt:cond>
              <tt:attribute name="value" value-ref="VALUE"/>
              </tt:cond>
              <tt:cond>
              <tt:attribute name="description" value-ref="DESCRIPTION"/>
              </tt:cond>
            </parameter>
          </tt:loop>
          <tt:loop ref="GROUPS">
            <group>
              <tt:attribute name="description" value-ref="DESCRIPTION"/>
              <tt:loop ref="PARAMETERS">
                <parameter>
                  <tt:cond>
                  <tt:attribute name="value" value-ref="VALUE"/>
                  </tt:cond>
                  <tt:cond>
                  <tt:attribute name="description" value-ref="DESCRIPTION"/>
                  </tt:cond>
                </parameter>
              </tt:loop>
            </group>
          </tt:loop>
        </check>
      </tt:loop>
    </ci:variant>
  </tt:template>

</tt:transform>

Final result in an ABAP List (ABAP WRITE) / truncated to fit forum maximum:

CL_CI_CATEGORY_ABAP_COMPILER  
    CL_CI_TEST_ABAP_GENERATE       Generate ABAP Programs
         Generate only if necessary : false
    CL_CI_TEST_EXPORT_COMP_PROCS_E Export of Program Information
         Export Using RFC : false
         RFC Destination : (no value or false)
         With Call Level : 0
         Force Generation : false
    CL_CI_TEST_EXTENDED_CHECK      Extended Program Check (SLIN)
         (no parameter description) : 1
         (no group description)
              PERFORM/FORM Interfaces : true
              CALL FUNCTION/METHOD Interfaces : true
    CL_CI_TEST_SYNTAX_CHECK        Syntax Check
         More than one error : true
         Warnings : true
         Message Codes : (no value or false)
CL_CI_CATEGORY_SECURITY       
    CL_CI_TEST_CRITICAL_STATEMENTS Critical Statements
         Calls
              C-CALLs : true
              SYSTEM-CALL : true
         Database
              ROLLBACK WORK : true
         Dynamic Program Editing
              GENERATE ... : true
              READ REPORT : false
              INSERT/DELETE REPORT : true
    CL_CI_TEST_FIND_DYN_SQL        Use of ADBC Interface
         Find uses of ...
              ... ADBC classes : true
              ... other classes : (no value or false)
         One message per ...
              (no parameter description) : 1
    CL_CI_TEST_SHO_CLIENT          Client-Specific Shared Objects Methods
         Attach Class Methods
              ATTACH_FOR_READ : true
              ATTACH_FOR_WRITE : true
              ATTACH_FOR_UPDATE : true
         Detach Class Methods
              DETACH_AREA : true
              DETACH_ALL_AREAS : true
CL_CI_CATEGORY_ROBUSTNESS     
    CL_CI_TEST_INT8                Test to check handling of type INT8
         Analyze only local procedures : true
         Non-local analysis depth : 1
         (no group description)
              Show detail information : false
              Inverted check : false 

 

Read only

0 Likes
4,628

Very good job Sandra !

if you are playing with ATC, I have created a specfic control to check object name (class, prog, ..)

Read only

0 Likes
4,628

frdric.girod Thanks. A standard check of program names already exists. Don't hesitate to share it with the community!

Read only

0 Likes
4,628

sandra.rossi these rules already exist ?

(I never been able to understand GitHub 😉 )

Read only

0 Likes
2,874

Yes for function group, program, function module, class, interface > Extended naming convention (see below screenshots).

No for the rest. But I have published a custom Code Inspector Check which checks DDIC Object Naming Convention, at Github with MIT license. The information is in this answer: Solved: Please any custom ABAP code to check DDIC object n... - SAP Community.

Feel free to publish your tool, too.

Sandra_Rossi_0-1744966739260.pngSandra_Rossi_1-1744966758205.png

Read only

BjoernJueliger
Product and Topic Expert
Product and Topic Expert
0 Likes
4,628

Why do you want to *print* a check variant? I feel there's another underlying problem here which should have a different solution.