Skip to Content
Technical Articles
Author's profile photo Karin Spiegel

Create a commit in Git when an ABAP task is released

Please note: the implementation described in this blog post should still work. Nevertheless, we recommend that you look into the blog post Integrating gCTS with Transport Organizer processes and use the sample coding that is provided in there.

If you already looked into Git-enabled CTS (gCTS), you might know that new commits are created in the standard as soon as you release a transport request.

But what if this is not possible or not helpful in your case? It might be that many developers work on one transport request – each one stores changed objects in a task that is part of that transport request. But each developer might want to commit and test his changes when he feels it is a good point in time for doing so. He might not want to wait for all the others to finish their tasks so that the whole transport request can be released.

So how about committing on a task level to enable individual progress and testing for each developer?

It is possible. The solution is to implement the ‘CHECK_BEFORE_RELEASE’-method of BAdI CTS_REQUEST_CHECK.

In the following description on how to do this, you will find some sample coding that you can use but that we provide without any further warranty or official SAP support.

In the example given below, we will use the userID (so ‘SY-UNAME’) and the package name as conditions to decide whether a commit shall be created on task level or on request level. Other criteria are for sure possible. You could e.g. use just the package name(s) – without any dependency on the user – or even check whether a certain object is already part of a cloned repository, or you can completely leave out these conditions if you want to always use the commit option on task level.
Please be aware that only released packages can be used for the condition.

In any case, make sure that the condition is met for every user, or for every transport task, or for whatever criterion that you choose – but nothing more, nothing less. So, it might happen that you have to adapt the condition from time to time in case new users join this working mode or additional packages shall make use of gCTS.

Let’s go!

  1. Open transaction SE18 in your ABAP development system and search for BAdI ‘CTS_REQUEST_CHECK’.
  2. Choose Display, and switch to the tab Interfaces to view the details:
    BAdI%20CTS_REQUEST_CHECKThe method that we need to implement is ‘CHECK_BEFORE_RELEASE’. Other methods of the standard interface are not relevant in this case. If you already implemented this method or other ones of this BAdI, make sure that implementations do not contradict or overwrite each other.
  3. Choose Implementation -> Create.
    Create%20BAdI
  4. Enter an Implementation Name – e.g. Z_GCTS_REQUEST_CHECK.
    Implementation%20NameClick on Continue (Enter) – the green check mark.
  5. On the next screen, enter an Implementation Short Text.
    If you like, you can also change the Name of Implementing Class. In the example given in here, I did that:
    Implementation%20DetailsLeave ABAP Code as Implementation Type.
    Save your changes.
    In the dialog popping up, you can add the implementation to a package. As I need the implementation only on my development system and don’t want to transport it, I chose to store it as local object.
    Save%20BAdI
  6. Double click on name of the implementing class:
    Start%20Class%20Implementation
  7. The class builder opens up.
    Go to Local Definitions/Implementations. Click on Source Code Based.Class%20Builder
  8. Copy the coding that you can find at the end of this blog into the editor.
    Source%20Code
    Please note: The way the object list is used in the method get_objects_to_push with the implementation provided in the sample coding below only works for GitHub. If you use another collaborative version control software based on Git, please check the APIs provided by your vendor to find out how this method could be implemented. Adapt the coding to your needs. If you use it ‘just like it is’, your implementation will not work.
    You can find some comments in the coding that will hopefully help you understand it and that explain what is required to be done if you want to commit on task level. The most important thing to do is that you adapt the basic conditions, when the commit on task level shall be executed:

    • The line if sy-uname = ‘MY_USER (in the method if_ex_cts_request_check~check_before_release) restricts the option to release on task level to the user-ID MY_USER. Adapt this line to your needs. You can e.g. replace ‘MY_USER’ with the userID(s) that should commit on task level, or use another condition that fits to your needs, or remove the condition completely if you would like to enable commits on task level in any case (if so, remove the corresponding ‘endif’ as well).
    • The line constants co_superpackage type string value ‘MY_TADIR_DEVC_PACKAGE‘ in the public section of the class definition restricts releasing on task level to the package MY_TADIR_DEVC_PACKAGE. Replace that by your package name or change the respective coding according to your needs.
  9. Check, save, and activate your coding.CheckActivate
  10. If everything is ok, click Back twice until you have reached the initial screen of your BAdI.
    Back
  11. In there, you should still see the Runtime Behavior ‘Implementation will not be called’. Click Activate business add-in Implementation as soon as you want to make use of the functionality.
    ActivateBAdI

 

You are done – try releasing a task where your conditions are met and check that a commit gets created.

 

Tips & Tricks

  • When you release a task, a commit will now automatically be created. The commit message will contain a transport request number, name, and /or ID. You have most probably never seen this transport request number before. It is the number of a transport of copies that has been automatically created in the background to allow exporting the task. You can change the commit message to something more meaningful by maintaining the parameters CLIENT_VCS_COMMIT_DESCRIPTION and CLIENT_VCS_COMMIT_MESSAGE for your repository. For more details, please take a look at the SAP Help Portal at Configuration Parameters for Repositories
  • If your implementation seems not to work as e.g. there is no commit visible in the commits list after you have released a task that fulfills your conditions, check the Log tab for your repository in the gCTS Fiori app.Commits
  • Commits and pushes are executed with the help of a job in transaction SM37. In case of issues, it might also be worth checking whether the job is there and (has been) executed: Choose the event SAP_TRIGGER_VCS_IMPORT and the ABAP Program Name SCTS_ABAP_VCS_IMPORT_OBSERVER and click Execute.ScheduledJobYou should get a list showing when the job was executed. If this is not the case, check your gCTS configuration. More details are provided on the SAP Help Portal under Enable Git-Enabled Change and Transport System in an ABAP System.

 

Sample Implementation

Please make sure that you copy the complete coding – the lines are longer than shown directly.

class zcl_im_cl_cts_git_forward definition
  public
  final
  create public .

  public section.

    types ty_tadir type standard table of tadir with default key.
    types ty_objects_to_push type table of if_cts_abap_vcs_transport_req=>ty_objects with default key.

    interfaces if_ex_cts_request_check .

    constants co_superpackage type string value 'MY_TADIR_DEVC_PACKAGE' ##NO_TEXT.
  protected section.
  private section.

    methods is_my_package_package
      importing
        !iv_package     type devclass
      returning
        value(rv_found) type boolean .

    methods get_objects_to_push
      importing
        !iv_repository            type    if_cts_abap_vcs_repository=>ty_repository_json
        !it_object_list           type ty_tadir
      returning
        value(rt_objects_to_push) type ty_objects_to_push .

endclass.



class zcl_im_cl_cts_git_forward implementation.

  method if_ex_cts_request_check~check_before_add_objects.
    " Not needed
  endmethod.


  method if_ex_cts_request_check~check_before_changing_owner.
    " Not needed
  endmethod.


  method if_ex_cts_request_check~check_before_creation.
    " Not needed
  endmethod.


  method if_ex_cts_request_check~check_before_release.

    data: ls_tadir       type tadir,
          ls_e071        type e071,
          lt_e071        type table of e071 with default key,
          lt_object_list type ty_tadir,
          ls_address     type bapiaddr3,
          lv_objname     type sobj_name,
          lv_check       type flag.

    " Execute just for a specific user (optional)
    if sy-uname = 'MY_USER'.

      "   Execute just for certain TR type (e.g. task)
      "   R - repair, S - development/correction,  Q -customizing task
      if type = 'R' or type = 'S' or type = 'Q'.

        " loop over provided objects from the BAdI signature parameter
        loop at objects into data(ls_object).
          data(lv_pgmid) = ls_object-pgmid.
          data(lv_obj_type) = ls_object-object.
          lv_objname = ls_object-obj_name.

          " Find the super object for part objects which have not pgmid = R3TR
          " This is needed if that object will be committed for the very first time
          " Otherwise the repository will just contain, e.g. a single method, which cannot be deployed to a target system
          if ls_object-pgmid = 'LIMU'.
            call function 'TR_CHECK_TYPE'
              exporting
                wi_e071  = ls_object
              importing
                we_tadir = ls_tadir
              exceptions
                others   = 1.

            " There was a TADIR entry for that object
            if sy-subrc = 0.
              lv_pgmid = ls_tadir-pgmid.
              lv_obj_type = ls_tadir-object.
              lv_objname = ls_tadir-obj_name.
              clear ls_tadir.
            else.
              continue.
            endif.
          endif.

          " Also keep sure that this is a 'real' object and not a generated one
          call function 'DEV_CHECK_OBJECT_EXISTS'
            exporting
              i_pgmid   = lv_pgmid
              i_objtype = lv_obj_type
              i_objname = lv_objname
            importing
              e_exists  = lv_check.

          if sy-subrc = 0.
            if lv_check = abap_true.

              " Double check that the related object could be transported by SE01/SE09
              call function 'TR_TADIR_INTERFACE'
                exporting
                  wi_tadir_pgmid    = lv_pgmid
                  wi_tadir_object   = lv_obj_type
                  wi_tadir_obj_name = lv_objname
                  wi_read_only      = 'X'
                importing
                  new_tadir_entry   = ls_tadir
                exceptions
                  others            = 1.

              " Evaluate that the current object is related to my DEVC package (optional)
              " Why do we need that?
              " It could be the case that we have a lot of different TR which will be transported trought our STMS landscape
              " In the case that gCTS will be used in parallel with common CTS we have to distinguish between the various object package relation
              " because of the fact that we probably just want to push objects which are related to our repository
              " For S/4HANA 2020: There is method which can be used in order to determine repository relation:
              " CL_CTS_ABAP_VCS_ORGANIZER_FAC=>check_objects
              if is_my_package_package( ls_tadir-devclass ) = abap_true and ls_tadir-genflag = abap_false.
                if not line_exists( lt_object_list[ obj_name = ls_tadir-obj_name ] ).
                  append ls_tadir to lt_object_list.
                  clear ls_tadir.
                endif.
              endif.
            else.
              continue.
            endif.
          else.
            " Handle Exception Here
            raise cancel.
          endif.
        endloop.

        " Get all exisiting repositories for current system
        data(lt_repositories) = cl_cts_abap_vcs_api_facade=>get_repositories( value #( ) ).

        " Was everything okay?
        if lt_repositories-exception is initial.
          loop at lt_repositories-result into data(ls_repository).

            " Compare provided object list with objects list of repository ...
            data(lt_objects_to_push) = get_objects_to_push( iv_repository = ls_repository it_object_list = lt_object_list ).
            if lt_objects_to_push is not initial.

              " Consume simplified facade method in order to commit&push objects to remote repository
              data(lv_response) = cl_cts_abap_vcs_trans_facade=>push_objects( value #(
                " Define Commit message
                desc = text
                " Define repository id for related objects
                repository = ls_repository-rid
                " Define repository related objects
                objects = lt_objects_to_push
              ) ).
            endif.
          endloop.
        endif.

      endif.
    endif.

  endmethod.


  method if_ex_cts_request_check~check_before_release_slin.
  endmethod.


  method is_my_package_package.

    " Is this our wanted package?
    if iv_package = co_superpackage.
      rv_found = abap_true.
    else.

      " Load package method information
      call method cl_package=>load_package
        exporting
          i_package_name = iv_package
        importing
          e_package      = data(lo_package)
        exceptions
          others         = 1.
      if lo_package is not initial.

        " is there a superpackage?
        " If not the process is over and this isn't our wanted package
        if lo_package->super_package_name is initial.
          rv_found = abap_false.
        elseif lo_package->super_package_name = co_superpackage .
          rv_found = abap_true.
        else.

          " Recursive call if there is a superpackage which also have to be evaluated
          rv_found = is_my_package_package( lo_package->super_package_name  ).
        endif.
      else.
        "this isn't our wanted package
        rv_found = abap_false.
      endif.
    endif.
  endmethod.


  method get_objects_to_push.

    data: ls_single_object type if_cts_abap_vcs_repository=>ty_object.

    " Get all available objects for repository (Warning: this will just work with GitHub API repositories!)
    data(ls_objects_response) = cl_cts_abap_vcs_repo_facade=>get_objects( iv_repository-rid ).

    if ls_objects_response-objects is not initial and ls_objects_response-exception is initial.
      loop at it_object_list into data(ls_object).
        if line_exists( ls_objects_response-objects[ object = ls_object-devclass type = 'DEVC' ] ) or
            line_exists( ls_objects_response-objects[ object = co_superpackage type = 'DEVC' ] ).

          if line_exists( ls_objects_response-objects[ object = ls_object-obj_name type = ls_object-object ] ).

            ls_single_object =  ls_objects_response-objects[ object = ls_object-obj_name type = ls_object-object ].
            append value #( object = ls_single_object-object type = ls_single_object-type ) to rt_objects_to_push.
          else.
            append value #( object = ls_object-obj_name type = ls_object-object ) to rt_objects_to_push.
          endif.

        elseif line_exists( ls_objects_response-objects[ object = ls_object-obj_name type = ls_object-object ] ).
          ls_single_object =  ls_objects_response-objects[ object = ls_object-obj_name type = ls_object-object ].
          append value #( object = ls_single_object-object type = ls_single_object-type ) to rt_objects_to_push.

        endif.
        clear ls_single_object.
      endloop.
    endif.
  endmethod.
endclass.

 

Hope that you find this useful. If you find issues or have questions or suggestions, feel free to post them as comments to this blog post.

Assigned Tags

      15 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Himanshu Sharma
      Himanshu Sharma

      Hello Karin,

      Thank you so much for a very detailed blog. I tried implementing the BADI and Implementation.
      But it didn't worked for me, as I am trying to push my Code to Azure DevOps. So, I Deactivated the implementation to went back to normal scenario of TR releasing. But after deactivating the implementation, our normal functions are not working now, after releasing TR, GCTS is not getting any new commit. So, we got stuck here now.

      Author's profile photo Karin Spiegel
      Karin Spiegel
      Blog Post Author

      Hi Himanshu,

      two things that you could maybe check:

      1. set a breakpoint at the beginning of your BAdI implementation to make sure that it is not executed
      2. check that your transport request uses the correct transport layer which is the one resulting from the virtual SID that you created when creating the repository

      Hope this helps

      Kind regards
      Karin

      Author's profile photo Asanka Liyanage
      Asanka Liyanage

      Hi Karin,

      Thank you so much for this valuable blog.

      I have configured gCTS in our SAP S/4 HANA environment(1909 & SPS01).

      I implemented the BAdI with given instruction and customized it accordingly.

      The issue that'm facing is whenever I try to release my transport request, It triggers the BAdI yet it doesn't fill any objects from the repository.

      I'm able to push the objects manually to the git repository using push objects from gCTS application.

      Please let me know how to resolve this issue.

      Thank you!

      Asanka.

      Author's profile photo Karin Spiegel
      Karin Spiegel
      Blog Post Author

      Hi Askana,

      I am not sure that I got the question. Do you mean that you implemented the BAdI and now, nothing happens any more when you release a transport request? Or does it not work to add objects when you release a task?

      If the first, I would suggest that you deactivate the BAdI for a while and try again

      If the second: which conditions do you use when the BAdI shall be called? Are they met by your task?

      Can you see anything new on the Activities tab or on the Logs tab when releasing?

       

      Kind regards'

      Karin

      Author's profile photo Asanka Liyanage
      Asanka Liyanage

      Thanks for your quick response Karin.

      The BAdI triggers when I release my transport. Yet it doesn't do anything. It doesn't show anything in Activities and log tabs.

       

      If I use 'Push' objects in objects tab. It works fine.

      I hope it's clear to you?

      Thanks,

      Asanka.

      Author's profile photo Karin Spiegel
      Karin Spiegel
      Blog Post Author

      Hi Asanka,

      sorry, I don't get the point why you need the BAdI. Triggering a push when a transport request is released is the standard behavior of gCTS - no need to implement that BAdI in that case

      Kind regards

      Karin

      Author's profile photo Asanka Liyanage
      Asanka Liyanage

      Hi Karin,

      We have a change management software. We release transports through the software. Therefore we have the need to activate the BAdI.

      I think I have figured out the issue now.

       

      Thanks.

      Asanka.

       

      Author's profile photo Karin Spiegel
      Karin Spiegel
      Blog Post Author

      Hi Askana,

      the BAdI as shown in the example coding above reacts on tasks - it doesn't do anything special for transport requests. If in your case nothing happens when a transport request is released, I would suggest that you start with checking whether the observer job is scheduled and executed correctly. You can find that described in here: https://help.sap.com/viewer/4a368c163b08418890a406d413933ba7/202009.002/en-US/db778a446db942deafdbcfc5dcfa029d.html

      Kind regards

      Karin

      Author's profile photo Asanka Liyanage
      Asanka Liyanage

      Thanks Karin. I will check the observer job.

      Asanka.

      Author's profile photo Mukund Joshi
      Mukund Joshi

      Hi Karin,

      As per the blog post https://blogs.sap.com/2021/09/05/how-change-request-management-charm-leverages-git-enabled-cts-gcts/ by Sawyer Peng

      "By default the code was pushed when releasing the transport request, but ChaRM requires the code pushing at task release, refer to SAP Note 2983745 for more details."

      Question is that, is it really mandatory have Task Release based commit to use in gCTS  to work with SolMan ChaRM?

       

      Author's profile photo Karin Spiegel
      Karin Spiegel
      Blog Post Author

      Hi,

      yes, this is to my knowledge how the gCTS integration with ChaRM works

      Kind regards

      karin

      Author's profile photo Mukund Joshi
      Mukund Joshi

      Hi Karin,

      This is regarding below comment from blog post to customize the code as per need, the development package related to ABAP development, but what about packages for Customizing changes?

      "The line constants co_superpackage type string value ‘MY_TADIR_DEVC_PACKAGE‘ in the public section of the class definition restricts releasing on task level to the package MY_TADIR_DEVC_PACKAGE. Replace that by your package name or change the respective coding according to your needs."

      Author's profile photo Karin Spiegel
      Karin Spiegel
      Blog Post Author

      Hi,

      is your question about BC-sets? I am not sure that I get what you mean by 'packages for customizing changes'

      Kind regards

      karin

      Author's profile photo Mukund Joshi
      Mukund Joshi

      Hi Karin,

      Yes, BC-sets for customizing objects, how should we handle such changes when we use task based released process along with ChaRM?

      Author's profile photo Karin Spiegel
      Karin Spiegel
      Blog Post Author

      Hi,
      I am not sure that I get the issue. gCTS supports the object type SCP1. So if you release a task containing this object type, it is pushed to the repository.

      Kind regards

      Karin