Managing Updates to abapGit in Shared Development Systems

If you are using abapGit as a tool to facilitate your development processes you at some point have to decide on an update strategy for abapGit itself. Most likely you are only updating abapGit when a feature or bug fix is released that you need or file diffs are displayed that are related to format changes that you want to get rid off. (Or you feel guilty not having updated for a while…) This is a bit of a shame as new features are added all the time and keeping abapGit up-to-date from a technical perspective is extremely easy. There are no notes to implement, no support packages to import, no migrations to do and no dependencies to worry about. Issues rather arise because of processes and communication between teams regarding ongoing developments when you are sharing systems.

abapGit’s core feature is mapping development objects of the ABAP Platform to files and vice versa. By serializing and deserializing development objects general compatibility with standard git is achieved which can then be utilized by the git protocol implementation. The format of these serialized development objects is human readable by design and intentionally mostly handcrafted in the object handler of each supported object type. This approach allows for reviewing changes with standard tools outside the SAP ecosystem (git platforms, gerrit, …) and even developing ABAP without a backend system altogether just based on the editable files. This does however have one annoying side effect:

Changes to the serialization logic will have an impact on the file representation of an ABAP package as a git repository, without any changes being done to the development objects themselves.

To git this behavior is very unusual as normally no mapping is required and developers edit the actual files directly or at least the git client has no influence at all on the files’ contents.

This can even happen without changes to the object handlers. New fields may be added to standard structures serialized by abapGit in a new SAP release that may or may not be relevant for the file.

Case in point: Can you tell this repository is perfectly installed and up-to-date?

Figure 1: Repository with diffs caused by format changes

As a developer, this is rather frustrating. You just want to commit your changes and quickly review them on the staging screen. If abapGit was updated in the meantime and relevant format changes were done or support for new object types was added that are part of your package, the staging screen includes these in addition to your changes. This can be especially annoying if you edited the same objects that were just affected by the format change. Then you cannot even filter by transport or username to find your actual changes. To correctly only commit your change, you have to sift through the list and in the worst case commit partial changes to a file with git patch. You are more likely to just commit these format changes with your actual changes making the history a bit less understandable and annoying anyone who has to review the pull request or resolve merge conflicts later.

No one likes having to review and account for changes that are unrelated to the issue being worked on.

If that doesn’t really bother you or your developers, that’s totally fine. If it does or you would at least like to offer some options for those who are, they are some strategies you can consider.

The usual approach to avoid this issue would be to simply not update abapGit if any development efforts are still in progress. Or at least if format changes are listed in the change log / commit log. Update abapGit when all branches of all repos in the system are merged and then make a pull request for each repository just including the format changes where review can be skipped. This can be done on individual developer systems or project systems where the changes being done are very isolated, either to a developer or to specific projects. In my experience the far more common scenario is shared development systems with multiple mostly unrelated development teams doing changes in parallel in the same system.

Let’s discuss some approaches to deal with format changes in abapGit in this shared development system landscape.

You can of course make yourself the one responsible for the updates and gather all development teams at a round table in a monthly interval. Chances that a common time frame for an update is found are slim especially when the ratio between the number of development teams and development systems increases. If only each team or repository could use the version of abapGit they require independently of one another in the same system and update at their convenience. Unfortunately, you cannot have multiple active versions of the same development objects on the ABAP Platform… Except with abapGit itself you can!

abapGit is delivered in two flavors:

  1. Developer Version
  2. Standalone Version

While the developer version uses global objects where only one active version can exist, the standalone version is contained in a single report. You can install as many standalone versions in parallel as you wish. One of the only objects that is shared between the versions is the database table ZABAPGIT, meaning you can access the same data from all installed versions. Now you can simply update the developer version frequently and point anyone requiring an older version to a fitting older standalone version installation. They are even motivated to migrate back as parallel serialization is only supported in the developer version…

To keep track of which abapGit version should be used for which repository and why you can implement exits for convenience. The wall-exits allow for displaying messages in a specific repository or on the repository list.


Figure 2: Screenshot of adjusted repository header

You could for example first check if the repo belongs to the git host your company uses and then differentiate based on the repository name:

METHOD zif_abapgit_exit~wall_message_repo.
  DATA full_name TYPE string.

      IF    is_repo_meta-offline = abap_true
         OR to_lower( zcl_abapgit_url=>host( is_repo_meta-url ) ) <> ''.
      full_name = to_lower(
                      condense( cl_http_utility=>unescape_url( zcl_abapgit_url=>path_name( is_repo_meta-url ) ) ) ).
    CATCH zcx_abapgit_exception INTO DATA(exception).
      ii_html->add( |<div class="panel error">Error parsing URL { is_repo_meta-url }: | &&
                    |{ exception->get_text( ) }</div>| ).

  CASE full_name.
    WHEN '/fabianlupa/abapgit-exit-example'.
      ii_html->add( |<hr/>| ).
      ii_html->add( |<span>| ).
      ii_html->add_icon( 'info-circle-solid/blue' ).
      ii_html->add( |Please use the abapGit standalone version for this repo for now| ).
      ii_html->add( |</span>| ).
      ii_html->add( |<hr/>| ).

Listing 1: Exit implementation to add a custom message in the repository view

You can also offer a link to execute the other abapGit installation and directly open the specific repository.

  BEGIN OF actions,
    launch_standalone TYPE string VALUE 'zlaunch',
  END OF actions.

METHOD zif_abapgit_exit~wall_message_repo.
  ii_html->add( |Please use the abapGit standalone version for this repo for now| ).
  ii_html->add_a( iv_txt="Link"
                  iv_act   = actions-launch_standalone
                  iv_query = |program=ZABAPGIT_STANDALONE_20230802&repo={ is_repo_meta-key }| ).

METHOD zif_abapgit_exit~on_event.
  DATA program  TYPE progname.
  DATA repo_key TYPE rfc_spagpa-parval.

  CASE ii_event->mv_action.
    WHEN actions-launch_standalone.
      program = ii_event->query( )->get( 'program' ).
      repo_key = ii_event->query( )->get( 'repo' ).
      IF program IS INITIAL OR repo_key IS INITIAL OR program NP 'ZABAPGIT_STANDALONE*'.
        zcx_abapgit_exception=>raise( |Unknown jump location for { ii_event->mv_action }| ).

      SET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_repo_key
          FIELD repo_key.
      SUBMIT (program) AND RETURN.
      MESSAGE |Returned from { program }| TYPE 'S'.

      rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.

Listing 2: Exit implementation to handle a redirection link

Or you could even automatically redirect when opening the repository.


Figure 3: Redirection on opening a repository

METHOD zif_abapgit_exit~on_event.
  IF NOT ( ii_event->mv_current_page_name="ZCL_ABAPGIT_GUI_PAGE_REPO_OVER" AND ii_event->mv_action = 'select' ).

  DATA(repo_key) = EXACT rfc_spagpa-parval( ii_event->query( )->get( 'key' ) ).
  DATA(repo) = zcl_abapgit_repo_srv=>get_instance( )->get( EXACT #( repo_key ) ).
  IF repo->is_offline( ).

  DATA(online_repo) = CAST zcl_abapgit_repo_online( repo ).
  DATA(full_name) = to_lower(
      condense( cl_http_utility=>unescape_url( zcl_abapgit_url=>path_name( online_repo->get_url( ) ) ) ) ).

  DATA(program) = SWITCH #( full_name
                            WHEN '/fabianlupa/abapgit-exit-example'
                            THEN 'ZABAPGIT_STANDALONE_20230802' ).
  IF program IS INITIAL.

  DATA(answer) = zcl_abapgit_ui_factory=>get_popups( )->popup_to_confirm(
                     iv_text_question = |You will be redirected to program { program } for this repository.|
                     iv_icon_button_1 = CONV #( icon_okay )
                     iv_text_button_1 = 'Continue'
                     iv_text_button_2 = 'Open here' ).
  CASE answer.
    WHEN '1'.
      SET PARAMETER ID zif_abapgit_definitions=>c_spagpa_param_repo_key
          FIELD repo_key.
      SUBMIT (program) AND RETURN.
      MESSAGE |Returned from { program }| TYPE 'S'.
      rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.
    WHEN '2'.
      rs_handled-state = zcl_abapgit_gui=>c_event_state-not_handled.
    WHEN 'A'.
      rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.

Listing 3: Exit implementation to offer automatic redirection on opening a repository

Note: The last implementation requires a recent (2023-09-18) change in abapGit.

You can find the exit implementations for reference in this repository: abapgit-exit-example

To keep track of which abapGit versions are installed in the system and when they were last updated you can install abapGit Launcher, which provides a list of all available versions in the system and a central entry point.


Figure 4: abapGit Launcher entry screen

Ideally you wouldn’t need to do any of this and just update abapGit at a regular interval. This can still be done if you don’t mind the occasional diffs on the staging screen. Also the amount of times format changes happen has decreased significantly over the years as the most used object handlers are very stable by now. If format changes happen, they are usually bundled and merged together to minimize the impact as well as listed in the change log.

In addition, there are some other aspects which play into this topic not covered by this blog. For example, how these diffs are handled in CI/CD processes and how the repositories themselves regularly receive file updates caused by updates to abapGit. Or how the abapGit installation delivered in SAP BTP ABAP Environment and SAP S/4HANA Public Cloud may act differently compared to the open source one…

Regardless of the problem at hand you can easily see with the approaches listed above that abapGit is very adjustable and you do not necessarily need to change your processes to fit the software. The changes and additions didn’t even need to modify existing abapGit code, which would also have been entirely possible. Should you choose the latter, please consider contributing your changes so others may also benefit.

Source link

Be the first to comment

Leave a Reply

Your email address will not be published.