Skip to Content
Author's profile photo Edo von Glan

How to perform an ATC check automatically during transport TASK release

The ABAP Test Cockpit (ATC) can easily be configured to check every transport request that is released.

But in case you are using transport of copies to import into the quality/test system (for example if you use SAP ChaRM for transport management), it is not possible in the standard to perform the ATC checks automatically when transporting from development to quality/test system.

On the other hand, in various places, for example the SAP Code Inspector book by Randolf Eilenberger and others, it is described how to trigger a Code Inspector test for every transport task release.

I have not yet found a description how to call the ATC automatically, when a transport task is released.

If this is what you want in your development system, you only have to implement one method in an implementation of BAdI CTS_REQUEST_CHECK:

METHOD if_ex_cts_request_check~check_before_release.

  DATA is_ok TYPE abap_bool VALUE abap_true.

  SELECT SINGLE trfunction, strkorr FROM e070 WHERE trkorr = @request

                              INTO (@DATA(trfunction), @DATA(strkorr)).

  ASSERT sysubrc = 0.

  ” only process release of transport tasks,

  ” not transport requests.

  ” And only customer code (not repairs, not customizing).

  CHECK strkorr IS NOT INITIAL AND trfunction = ‘S’.

  TRY.

      DATA(or_factory) = NEW cl_satc_api_factory( ).

      DATA(it_objects) = cl_satc_object_set_factory=>create_for_transport( request

                                                             )->if_satc_object_set~get_object_keys( ).

      DATA(or_objects) = cl_satc_object_set_factory=>create_for_object_keys( it_objects ).

      DATA(or_variant) = NEW cl_satc_ci_check_variant( ).

      or_variant->set_name( ‘Z_STANDARD’ ).  ” replace with your check variant

      DATA(or_run_config) = or_factory->create_run_config_with_chk_var( EXPORTING i_object_set = or_objects

                                                                                                                  i_check_variant = or_variant

                                                                                                                  i_description = |Transport release { request } | ).

      DATA(or_run_controller) = or_factory->create_run_controller( or_run_config ).

      or_run_controller->run( IMPORTING e_result_access = DATA(or_result_access) ).

      or_result_access->get_findings( IMPORTING e_findings = DATA(it_f) ).

      LOOP AT it_f ASSIGNING FIELD-SYMBOL(<wa_f>) WHERE ( kind = ‘E’ OR kind = ‘W’ ) ” errors/warnings

                                                    AND exceptn <> ‘P’. ” pseudo comments and pragmas

        is_ok = abap_false.

        EXIT.

      ENDLOOP.

    CATCH cx_satc_failure cx_satc_not_found INTO DATA(cx).

      DATA(exc_text) = cx->get_text( ).

      MESSAGE exc_text TYPE ‘E’.

      is_ok = abap_false.

    CATCH cx_satc_empty_object_set cx_satc_invalid_argument INTO cx” ok, if transport is empty or contains only non-checkable objects

  ENDTRY.

  IF is_ok = abap_true.

    MESSAGE s007(zs_dev_tools_local).  ” success message – create your own message

  ELSE.

    MESSAGE s008(zs_dev_tools_local).  ” failure message – create your own message

    ” we only get the execution ID with this “dirty” cast:

    DATA(or_result_access_int) = CAST cl_satc_result_access( or_result_access ).

    CALL FUNCTION ‘SATC_AC_DISPL_RESULT_BY_EXEC’

      EXPORTING i_execution_id = or_result_access_int->if_satc_result_access~result_id

      EXCEPTIONS

        xpt_no_results     = 1

        xpt_not_authorized = 2

        xpt_display_used   = 3

        OTHERS             = 4.

    ASSERT sysubrc = 0.

    RAISE cancel.

  ENDIF.

ENDMETHOD.

(This coding uses some of the new 7.40 SP08 language features, so you may have to adapt it.)

That’s it, basically.

I noted however, that include programs are not tested when transported on their own, because the ATC methods that I call only test frame programs (type 1 reports, classes, function groups). I did not find an easy way to overcome this using standard ATC framework functions, so I programmed it in a local class with the following methods:

  CLASS-METHODS:

      enrich_main_programs

        CHANGING c_it_keys                  TYPE if_satc_object_set=>ty_object_keys,

      is_include_program

        IMPORTING i_object                    TYPE if_satc_object_set=>ty_object_key

        RETURNING VALUE(r_is_include_program) TYPE abap_bool,

      get_main_programs_for_include

        IMPORTING i_object    TYPE if_satc_object_set=>ty_object_key

        RETURNING VALUE(r_it) TYPE if_satc_object_set=>ty_object_keys,

      is_mainprog_included

        IMPORTING

                  i_it_mainprogs    TYPE if_satc_object_set=>ty_object_keys

                  i_it_current_keys TYPE if_satc_object_set=>ty_object_keys

        RETURNING VALUE(r) TYPE abap_bool,

  METHOD enrich_main_programs.

    LOOP AT c_it_keys ASSIGNING FIELD-SYMBOL(<wa>).

      IF is_include_program( <wa> ).

        DATA(it_main_programs) = get_main_programs_for_include( <wa> ).

        IF it_main_programs IS NOT INITIAL

           AND NOT is_mainprog_included( EXPORTING i_it_mainprogs = it_main_programs

                                                   i_it_current_keys  = c_it_keys ).

          INSERT it_main_programs[ 1 ] INTO TABLE c_it_keys.

        ENDIF.

      ENDIF.

    ENDLOOP.

  ENDMETHOD.

  METHOD is_include_program.

    r_is_include_program = abap_false.

    CHECK i_objectobj_type = ‘PROG’.

    SELECT SINGLE subc FROM reposrc WHERE progname = @i_objectobj_name AND subc = ‘I’

                                           INTO @DATA(subc) ##warn_ok ##needed.

    IF sysubrc = 0.

      r_is_include_program = abap_true.

    ENDIF.

  ENDMETHOD.

  METHOD get_main_programs_for_include.

    DATA it_mainprogs LIKE STANDARD TABLE OF i_objectobj_name.

    DATA wa LIKE LINE OF r_it.

    CLEAR r_it. ” if there are no main programs, return initial

    CALL FUNCTION ‘RS_GET_MAINPROGRAMS’

      EXPORTING

        name         = i_objectobj_name

      TABLES

        mainprograms = it_mainprogs

      EXCEPTIONS

        cancelled    = 1

        OTHERS       = 2.

    ASSERT sysubrc = 0.

    waobj_type = ‘PROG’.

    LOOP AT it_mainprogs ASSIGNING FIELD-SYMBOL(<wa>).

      waobj_name = <wa>.

      INSERT wa INTO TABLE r_it.

    ENDLOOP.

  ENDMETHOD.

  METHOD is_mainprog_included.

    r = abap_false.

    LOOP AT i_it_mainprogs ASSIGNING FIELD-SYMBOL(<wa>).

      READ TABLE i_it_current_keys WITH KEY obj_type = <wa>-obj_type obj_name = <wa>-obj_name

                                  TRANSPORTING NO FIELDS.

      IF sysubrc = 0.

        r = abap_true.

        RETURN.

      ENDIF.

    ENDLOOP.

  ENDMETHOD.

Now, enrich_main_programs() needs to be called to change it_objects after the statement that is creating it_objects.

Edit 25.04.2016: exception handling for cx_satc_invalid_argument added.

Assigned Tags

      11 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo rayudu vallabhaneni
      rayudu vallabhaneni

      Hi, thanks for your document. This BADI implementation will helps to handle the task level ATC checks.  Could you please help me to understand the below scenarios.

      If same program existing in two different tasks, during first task releasing time some of the errors are APPROVED by QA reviewer.

      So, whether these errors will be repeated during second task releasing time??

      After both the tasks and respective transport numbers are released. Again, modified the same program. During this task releasing time, again it will consider previous approved errors or not?

      Author's profile photo Edo von Glan
      Edo von Glan
      Blog Post Author

      Hi Rayudu,

      this is Standard ATC functionality: findings for which an exemption ("approval") has been granted, will not show up in the future.

      Exception: optionally, the approver can grant the exemptions for a limited time, for example for 1 month. In this case, they are shown again after that time.

      Best regards,

      Edo

      Author's profile photo Sandra Rossi
      Sandra Rossi

      Thanks a lot. In 7.40 SP 7, most of the ATS classes you use don't exist yet. If people want to use it in 7.40 SP 7 and before, here is an example how to run ATC. Hope it helps.

      PARAMETERS program TYPE syrepid DEFAULT 'Z_PROGRAM'.

      PARAMETERS dialog RADIOBUTTON GROUP rb1 DEFAULT 'X'.
      PARAMETERS batch RADIOBUTTON GROUP rb1.

      START-OF-SELECTION.

      DATA:
      key_iterator TYPE REF TO cl_satc_ac_iterate_fixed_keys,
      f_r3tr_keys TYPE satc_t_r3tr_keys.

      f_r3tr_keys = VALUE #( ( obj_name = program obj_type = 'PROG' ) ).

      CREATE OBJECT key_iterator.
      key_iterator->set_object_keys( f_r3tr_keys ).

      DATA:
      check_variant TYPE satc_ci_chk_variant,
      project_handle TYPE REF TO if_satc_md_project,
      project_parameters TYPE REF TO cl_satc_ac_project_parameters.

      check_variant = 'Z_STANDARD'.

      CREATE OBJECT project_parameters.
      project_parameters->set_project_title( 'analysis name' ).
      project_parameters->set_is_transient( abap_false ).
      project_parameters->set_profile_name_of_checks( check_variant ).
      project_parameters->set_evaluate_exemptions( abap_true ).
      project_parameters->set_evaluate_runtime_error( abap_true ).
      project_parameters->set_object_key_iterator( key_iterator ).
      project_parameters->set_mode_fndng_xmptd_in_code( cl_satc_ac_project_parameters=>c_mode_fndng_xmptd_in_code-suppress ).

      project_handle = cl_satc_ac_project_svc=>get_instance( )->create_project( project_parameters ).

      DATA:
      progress_listener TYPE REF TO cl_satc_ac_ui_progress,
      success TYPE abap_bool,
      execution_id TYPE satc_d_exec_id.

      CASE abap_true.
      WHEN dialog.

      IF ( sy-batch abap_true ).
      CREATE OBJECT progress_listener.
      ENDIF.

      CALL FUNCTION 'SATC_EXECUTE_PROJECT'
      EXPORTING
      i_project = project_handle
      i_progress_listener = progress_listener
      IMPORTING
      e_exec_id = execution_id
      e_success = success.
      IF ( success = abap_false ).
      MESSAGE 'Execution failed' TYPE 'I' DISPLAY LIKE 'E'.
      ELSE.
      MESSAGE 'Execution succeded' TYPE 'I' DISPLAY LIKE 'S'.
      ENDIF.

      WHEN batch.

      CALL FUNCTION 'SATC_EXECUTE_PROJECT_VIA_BATCH'
      EXPORTING
      i_project = project_handle.

      MESSAGE 'Your request has been scheduled for execution in batch.' TYPE 'I'.

      ENDCASE.

      Author's profile photo Mahadevan Venkata
      Mahadevan Venkata

      Has been officially implemented by SAP with the note 2495410.

       

      Thanks, the blog has been very helpful otherwise.

       

      BR

      Venkat

       

      Author's profile photo Phillip Eisenhauer
      Phillip Eisenhauer

      Hey Edo,

      exactly what I searched for, thank You.

      But I don’t get one thing:

            DATA(it_objects) = cl_satc_object_set_factory=>create_for_transport( request
      
                                                                   )->if_satc_object_set~get_object_keys( ).
      
            DATA(or_objects) = cl_satc_object_set_factory=>create_for_object_keys( it_objects ).

      You use the object factory class to create an object for a transport request (first line).

      You then use this object to get the object keys of the created object (second line).

      In the third line You use the keys of the first object to create another object_set object.

       

      Why don’t You simple use the the “create_for_transport” method and use this object in

      DATA(or_run_config) = or_factory->create_run_config_with_chk_var( EXPORTING i_object_set = or_objects [...]

      ?

      Is this solving any problem you ran into which I don’t see at the moment?

      Greetings Phillip

      Author's profile photo Edo von Glan
      Edo von Glan
      Blog Post Author

       

      Hi Philip,

      I think the reason is described in the second but last sentence of the blog:

      Now, enrich_main_programs() needs to be called to change it_objects after the statement that is creating it_objects.

      I have to admit that I do not remember this detail anymore.

      Best regards,

      Edo

      Author's profile photo Ian Stubbings
      Ian Stubbings

      Hi Edo

      Great information in this blog. Thank you for sharing.

      We are using the standard functionality to trigger the checks which is fine but I have one other question in relation to transport release:

      Is there a standard check to validate transport naming standards or do we have to create our own check for this? I've seen the source code naming standards as a standard (and extensive check) but our focus is for the transport (and task).

      Regards

      Ian

      Author's profile photo Bärbel Winkler
      Bärbel Winkler

      Ian Stubbings

      Hi Ian,

      do you mean checking the content of transport titles? If yes, than I don't think that you can do that via ATC-checks which happen too late in the game to avoid the creation of transports with wrong titles. I did however implement a check during transport creation last year via METHOD if_ex_cts_request_check~check_before_creation, a couple of Z-tables and a function module (a description is here - but the potential task to convert the logic to ABAP OO is still pending).

      Cheers

      Bärbel

      Author's profile photo Ian Stubbings
      Ian Stubbings

      Hi Bärbel

      Thanks as always for the speedy reply.

      Yes, indeed I am interested in checking the transport title as we have a standard way this should be built.

      The check should occur at task or transport release and could therefore fit into the ATC Check framework (in my opinion). I guess seeing as there is a standard check there already for source code, I wondered if there was a standard solution for transport titles I had missed, or seeing as it's probably quite a common request, I wondered if someone else had implemented it.

      Although it would be preferable to add into the if_ex_cts_request_check~check_before_creation method, we don't always know the details up front, so although your previous solution you mentioned could potentially work for us, it would unfortunately be of limited benefit.

      For the if_ex_cts_request_check~check_before_release method, this is fine and could work in a small SAP estate but ours is quite extensive and therefore I'd like to implement the check in our Central ATC system rather than in each satellite system and hence an ATC check would be an ideal solution. I think anyway 🙂

       

      Regards

      Ian

      Author's profile photo Edo von Glan
      Edo von Glan
      Blog Post Author

      Hi Bärbel, Hi Ian,

      the ATC checks work only on development objects. They can (to my best knowledge) not work on transports themselves.

      We also implemented some "non-ATC" checks manually in the  check_before_release() exit, for example to check that modifications (which are not checked by our version of ATC) always have a comment.

      You could still have the check central, if you call an RFC function on your central system. Then you only have to implement the RFC call in each system (and provide all parameters that you would ever want :-), and implement (and update) the actual logic only in your central system.

      Best regards,

      Edo

      Author's profile photo Ian Stubbings
      Ian Stubbings

      Hi Edo

       

      Thanks also for the speedy reply!

       

      I have been reading about implementing ATC checks using the standard framework and it mentions about not being reliant on in system data - such as from TADIR and therefore this would naturally extend to transport data from E07T etc.

      Therefore, I shall take your advice and implement an RFC call back to the the Central ATC system and also house any naming standing config tables here.

      I'll let you know how I get on.

      Regards

      Ian