*&---------------------------------------------------------------------*
*& Include zabapgit_object_sxci
*&---------------------------------------------------------------------*

CLASS lcl_object_sxci DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_classic_badi_implementation,
             implementation_data TYPE impl_data,
             function_codes      TYPE seex_fcode_table,
             control_composites  TYPE seex_coco_table,
             customer_includes   TYPE seex_table_table,
             screens             TYPE seex_screen_table,
             filters             TYPE seex_filter_table,
           END OF ty_classic_badi_implementation.

    CONSTANTS: BEGIN OF co_badi_component_name,
                 filters            TYPE string VALUE 'FILTERS',
                 function_codes     TYPE string VALUE 'FUNCTION_CODES',
                 control_composites TYPE string VALUE 'CONTROL_COMPOSITES',
                 customer_includes  TYPE string VALUE 'CUSTOMER_INCLUDES',
                 screens            TYPE string VALUE 'SCREENS',
               END OF co_badi_component_name.

ENDCLASS.

CLASS lcl_object_sxci IMPLEMENTATION.

  METHOD lif_object~has_changed_since.

    rv_changed = abap_true.

  ENDMETHOD.

  METHOD lif_object~changed_by.

    rv_user = c_user_unknown.

  ENDMETHOD.

  METHOD lif_object~get_metadata.

    rs_metadata = get_metadata( ).

  ENDMETHOD.

  METHOD lif_object~exists.

    DATA: lv_implementation_name TYPE rsexscrn-imp_name.

    lv_implementation_name = ms_item-obj_name.

    CALL FUNCTION 'SXV_IMP_EXISTS'
      EXPORTING
        imp_name           = lv_implementation_name
      EXCEPTIONS
        not_existing       = 1
        data_inconsistency = 2
        OTHERS             = 3.

    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD lif_object~serialize.

    DATA: lv_implementation_name         TYPE rsexscrn-imp_name,
          lv_exit_name                   TYPE rsexscrn-exit_name,
          lo_filter_object               TYPE REF TO cl_badi_flt_struct,
          ls_badi_definition             TYPE badi_data,
          lo_filter_values_object        TYPE REF TO cl_badi_flt_values_alv,
          lt_methods                     TYPE seex_mtd_table,
          ls_classic_badi_implementation TYPE ty_classic_badi_implementation.

    lv_implementation_name = ms_item-obj_name.

    CALL FUNCTION 'SXV_EXIT_FOR_IMP'
      EXPORTING
        imp_name           = lv_implementation_name
      IMPORTING
        exit_name          = lv_exit_name
      TABLES
        filters            = ls_classic_badi_implementation-filters
      EXCEPTIONS
        data_inconsistency = 1
        OTHERS             = 2.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXV_EXIT_FOR_IMP' ).
    ENDIF.

    CALL FUNCTION 'SXO_BADI_READ'
      EXPORTING
        exit_name    = lv_exit_name
      IMPORTING
        badi         = ls_badi_definition
        filter_obj   = lo_filter_object
      TABLES
        fcodes       = ls_classic_badi_implementation-function_codes
        cocos        = ls_classic_badi_implementation-control_composites
        intas        = ls_classic_badi_implementation-customer_includes
        scrns        = ls_classic_badi_implementation-screens
        methods      = lt_methods
      EXCEPTIONS
        read_failure = 1
        OTHERS       = 2.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_BADI_READ' ).
    ENDIF.

    CALL FUNCTION 'SXO_IMPL_FOR_BADI_READ'
      EXPORTING
        imp_name          = lv_implementation_name
        exit_name         = lv_exit_name
        inter_name        = ls_badi_definition-inter_name
        filter_obj        = lo_filter_object
      IMPORTING
        impl              = ls_classic_badi_implementation-implementation_data
        filter_values_obj = lo_filter_values_object
      TABLES
        fcodes            = ls_classic_badi_implementation-function_codes
        cocos             = ls_classic_badi_implementation-control_composites
        intas             = ls_classic_badi_implementation-customer_includes
        scrns             = ls_classic_badi_implementation-screens
      CHANGING
        methods           = lt_methods
      EXCEPTIONS
        read_failure      = 1
        OTHERS            = 2.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_IMPL_FOR_BADI_READ' ).
    ENDIF.

    CLEAR: ls_classic_badi_implementation-implementation_data-aname,
           ls_classic_badi_implementation-implementation_data-adate,
           ls_classic_badi_implementation-implementation_data-atime,
           ls_classic_badi_implementation-implementation_data-uname,
           ls_classic_badi_implementation-implementation_data-udate,
           ls_classic_badi_implementation-implementation_data-utime,
           ls_classic_badi_implementation-implementation_data-active.

    io_xml->add( iv_name = 'SXCI'
                 ig_data = ls_classic_badi_implementation ).

  ENDMETHOD.

  METHOD lif_object~deserialize.

    DATA: ls_badi_definition             TYPE badi_data,
          lo_filter_object               TYPE REF TO cl_badi_flt_struct,
          lo_filter_values_object        TYPE REF TO cl_badi_flt_values_alv,
          lv_korrnum                     TYPE trkorr,
          lv_filter_type_enhanceability  TYPE rsexscrn-flt_ext,
          lv_package                     TYPE devclass,
          ls_classic_badi_implementation TYPE ty_classic_badi_implementation.

    io_xml->read(
      EXPORTING
        iv_name = 'SXCI'
      CHANGING
        cg_data = ls_classic_badi_implementation ).

    CALL FUNCTION 'SXO_BADI_READ'
      EXPORTING
        exit_name    = ls_classic_badi_implementation-implementation_data-exit_name
      IMPORTING
        badi         = ls_badi_definition
        filter_obj   = lo_filter_object
      EXCEPTIONS
        read_failure = 1
        OTHERS       = 2.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_BADI_READ' ).
    ENDIF.

    lv_package = iv_package.

    CREATE OBJECT lo_filter_values_object
      EXPORTING
        filter_object = lo_filter_object
        filter_values = ls_classic_badi_implementation-filters.

    CALL FUNCTION 'SXO_IMPL_SAVE'
      EXPORTING
        impl             = ls_classic_badi_implementation-implementation_data
        flt_ext          = lv_filter_type_enhanceability
        filter_val_obj   = lo_filter_values_object
        genflag          = abap_true
        no_dialog        = abap_true
      TABLES
        fcodes_to_insert = ls_classic_badi_implementation-function_codes
        cocos_to_insert  = ls_classic_badi_implementation-control_composites
        intas_to_insert  = ls_classic_badi_implementation-customer_includes
        sscrs_to_insert  = ls_classic_badi_implementation-screens
      CHANGING
        korrnum          = lv_korrnum
        devclass         = lv_package
      EXCEPTIONS
        save_failure     = 1
        action_canceled  = 2
        OTHERS           = 3.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_IMPL_SAVE' ).
    ENDIF.

    CALL FUNCTION 'SXO_IMPL_ACTIVE'
      EXPORTING
        imp_name                  = ls_classic_badi_implementation-implementation_data-imp_name
        no_dialog                 = abap_true
      EXCEPTIONS
        badi_not_existing         = 1
        imp_not_existing          = 2
        already_active            = 3
        data_inconsistency        = 4
        activation_not_admissable = 5
        action_canceled           = 6
        access_failure            = 7
        OTHERS                    = 8.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_IMPL_ACTIVE' ).
    ENDIF.

  ENDMETHOD.

  METHOD lif_object~delete.

    DATA: lv_implementation_name TYPE rsexscrn-imp_name.

    lv_implementation_name = ms_item-obj_name.

    CALL FUNCTION 'SXO_IMPL_DELETE'
      EXPORTING
        imp_name           = lv_implementation_name
        no_dialog          = abap_true
      EXCEPTIONS
        imp_not_existing   = 1
        action_canceled    = 2
        access_failure     = 3
        data_inconsistency = 4
        OTHERS             = 5.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_IMPL_DELETE' ).
    ENDIF.

  ENDMETHOD.

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation           = 'SHOW'
        object_name         = ms_item-obj_name
        object_type         = ms_item-obj_type
        in_new_window       = abap_true
      EXCEPTIONS
        not_executed        = 1
        invalid_object_type = 2
        OTHERS              = 3.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from RS_TOOL_ACCESS' ).
    ENDIF.

  ENDMETHOD.

  METHOD lif_object~compare_to_remote_version.

    CREATE OBJECT ro_comparison_result TYPE lcl_comparison_null.

  ENDMETHOD.

ENDCLASS.

*&---------------------------------------------------------------------*
*& Include zabapgit_object_sxci
*&---------------------------------------------------------------------*

CLASS lcl_object_sxci DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_classic_badi_implementation,
             implementation_data TYPE impl_data,
             function_codes      TYPE seex_fcode_table,
             control_composites  TYPE seex_coco_table,
             customer_includes   TYPE seex_table_table,
             screens             TYPE seex_screen_table,
             filters             TYPE seex_filter_table,
           END OF ty_classic_badi_implementation.

    CONSTANTS: BEGIN OF co_badi_component_name,
                 filters            TYPE string VALUE 'FILTERS',
                 function_codes     TYPE string VALUE 'FUNCTION_CODES',
                 control_composites TYPE string VALUE 'CONTROL_COMPOSITES',
                 customer_includes  TYPE string VALUE 'CUSTOMER_INCLUDES',
                 screens            TYPE string VALUE 'SCREENS',
               END OF co_badi_component_name.

ENDCLASS.

CLASS lcl_object_sxci IMPLEMENTATION.

  METHOD lif_object~has_changed_since.

    rv_changed = abap_true.

  ENDMETHOD.

  METHOD lif_object~changed_by.

    rv_user = c_user_unknown.

  ENDMETHOD.

  METHOD lif_object~get_metadata.

    rs_metadata = get_metadata( ).

  ENDMETHOD.

  METHOD lif_object~exists.

    DATA: lv_implementation_name TYPE rsexscrn-imp_name.

    lv_implementation_name = ms_item-obj_name.

    CALL FUNCTION 'SXV_IMP_EXISTS'
      EXPORTING
        imp_name           = lv_implementation_name
      EXCEPTIONS
        not_existing       = 1
        data_inconsistency = 2
        OTHERS             = 3.

    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD lif_object~serialize.

    DATA: lv_implementation_name         TYPE rsexscrn-imp_name,
          lv_exit_name                   TYPE rsexscrn-exit_name,
          lo_filter_object               TYPE REF TO cl_badi_flt_struct,
          ls_badi_definition             TYPE badi_data,
          lo_filter_values_object        TYPE REF TO cl_badi_flt_values_alv,
          lt_methods                     TYPE seex_mtd_table,
          ls_classic_badi_implementation TYPE ty_classic_badi_implementation.

    lv_implementation_name = ms_item-obj_name.

    CALL FUNCTION 'SXV_EXIT_FOR_IMP'
      EXPORTING
        imp_name           = lv_implementation_name
      IMPORTING
        exit_name          = lv_exit_name
      TABLES
        filters            = ls_classic_badi_implementation-filters
      EXCEPTIONS
        data_inconsistency = 1
        OTHERS             = 2.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXV_EXIT_FOR_IMP' ).
    ENDIF.

    CALL FUNCTION 'SXO_BADI_READ'
      EXPORTING
        exit_name    = lv_exit_name
      IMPORTING
        badi         = ls_badi_definition
        filter_obj   = lo_filter_object
      TABLES
        fcodes       = ls_classic_badi_implementation-function_codes
        cocos        = ls_classic_badi_implementation-control_composites
        intas        = ls_classic_badi_implementation-customer_includes
        scrns        = ls_classic_badi_implementation-screens
        methods      = lt_methods
      EXCEPTIONS
        read_failure = 1
        OTHERS       = 2.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_BADI_READ' ).
    ENDIF.

    CALL FUNCTION 'SXO_IMPL_FOR_BADI_READ'
      EXPORTING
        imp_name                    = lv_implementation_name
        exit_name                   = lv_exit_name
        inter_name                  = ls_badi_definition-inter_name
        filter_obj                  = lo_filter_object
        no_create_filter_values_obj = abap_true
      IMPORTING
        impl                        = ls_classic_badi_implementation-implementation_data
        filter_values_obj           = lo_filter_values_object
      TABLES
        fcodes                      = ls_classic_badi_implementation-function_codes
        cocos                       = ls_classic_badi_implementation-control_composites
        intas                       = ls_classic_badi_implementation-customer_includes
        scrns                       = ls_classic_badi_implementation-screens
      CHANGING
        methods                     = lt_methods
      EXCEPTIONS
        read_failure                = 1
        OTHERS                      = 2.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_IMPL_FOR_BADI_READ' ).
    ENDIF.

    CLEAR: ls_classic_badi_implementation-implementation_data-aname,
           ls_classic_badi_implementation-implementation_data-adate,
           ls_classic_badi_implementation-implementation_data-atime,
           ls_classic_badi_implementation-implementation_data-uname,
           ls_classic_badi_implementation-implementation_data-udate,
           ls_classic_badi_implementation-implementation_data-utime,
           ls_classic_badi_implementation-implementation_data-active.

    io_xml->add( iv_name = 'SXCI'
                 ig_data = ls_classic_badi_implementation ).

  ENDMETHOD.

  METHOD lif_object~deserialize.

    DATA: ls_badi_definition             TYPE badi_data,
          lo_filter_object               TYPE REF TO cl_badi_flt_struct,
          lo_filter_values_object        TYPE REF TO cl_badi_flt_values_alv,
          lv_korrnum                     TYPE trkorr,
          lv_filter_type_enhanceability  TYPE rsexscrn-flt_ext,
          lv_package                     TYPE devclass,
          ls_classic_badi_implementation TYPE ty_classic_badi_implementation.

    io_xml->read(
      EXPORTING
        iv_name = 'SXCI'
      CHANGING
        cg_data = ls_classic_badi_implementation ).

    CALL FUNCTION 'SXO_BADI_READ'
      EXPORTING
        exit_name    = ls_classic_badi_implementation-implementation_data-exit_name
      IMPORTING
        badi         = ls_badi_definition
        filter_obj   = lo_filter_object
      EXCEPTIONS
        read_failure = 1
        OTHERS       = 2.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_BADI_READ' ).
    ENDIF.

    lv_package = iv_package.

    CREATE OBJECT lo_filter_values_object
      EXPORTING
        filter_object = lo_filter_object
        filter_values = ls_classic_badi_implementation-filters.

    CALL FUNCTION 'SXO_IMPL_SAVE'
      EXPORTING
        impl             = ls_classic_badi_implementation-implementation_data
        flt_ext          = lv_filter_type_enhanceability
        filter_val_obj   = lo_filter_values_object
        genflag          = abap_true
        no_dialog        = abap_true
      TABLES
        fcodes_to_insert = ls_classic_badi_implementation-function_codes
        cocos_to_insert  = ls_classic_badi_implementation-control_composites
        intas_to_insert  = ls_classic_badi_implementation-customer_includes
        sscrs_to_insert  = ls_classic_badi_implementation-screens
      CHANGING
        korrnum          = lv_korrnum
        devclass         = lv_package
      EXCEPTIONS
        save_failure     = 1
        action_canceled  = 2
        OTHERS           = 3.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_IMPL_SAVE' ).
    ENDIF.

    CALL FUNCTION 'SXO_IMPL_ACTIVE'
      EXPORTING
        imp_name                  = ls_classic_badi_implementation-implementation_data-imp_name
        no_dialog                 = abap_true
      EXCEPTIONS
        badi_not_existing         = 1
        imp_not_existing          = 2
        already_active            = 3
        data_inconsistency        = 4
        activation_not_admissable = 5
        action_canceled           = 6
        access_failure            = 7
        OTHERS                    = 8.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_IMPL_ACTIVE' ).
    ENDIF.

  ENDMETHOD.

  METHOD lif_object~delete.

    DATA: lv_implementation_name TYPE rsexscrn-imp_name.

    lv_implementation_name = ms_item-obj_name.

    CALL FUNCTION 'SXO_IMPL_DELETE'
      EXPORTING
        imp_name           = lv_implementation_name
        no_dialog          = abap_true
      EXCEPTIONS
        imp_not_existing   = 1
        action_canceled    = 2
        access_failure     = 3
        data_inconsistency = 4
        OTHERS             = 5.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from SXO_IMPL_DELETE' ).
    ENDIF.

  ENDMETHOD.

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation           = 'SHOW'
        object_name         = ms_item-obj_name
        object_type         = ms_item-obj_type
        in_new_window       = abap_true
      EXCEPTIONS
        not_executed        = 1
        invalid_object_type = 2
        OTHERS              = 3.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from RS_TOOL_ACCESS' ).
    ENDIF.

  ENDMETHOD.

  METHOD lif_object~compare_to_remote_version.

    CREATE OBJECT ro_comparison_result TYPE lcl_comparison_null.

  ENDMETHOD.

ENDCLASS.

Fix #1086

Fix #1086

https://launchpad.support.sap.com/#/notes/1091157/E


CLASS ltcl_relevant DEFINITION DEFERRED.
CLASS zcl_abapgit_news DEFINITION LOCAL FRIENDS ltcl_relevant.

CLASS ltcl_relevant DEFINITION FINAL FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.

  PRIVATE SECTION.

    METHODS:
      test01 FOR TESTING,
      test02 FOR TESTING,
      test03 FOR TESTING.

ENDCLASS.

CLASS ltcl_relevant IMPLEMENTATION.

  METHOD test01.

    DATA: lv_relevant TYPE abap_bool.

    lv_relevant = zcl_abapgit_news=>is_relevant( 'https://github.com/larshp/abapGit.git' ).

    cl_abap_unit_assert=>assert_equals(
      act = lv_relevant
      exp = abap_true ).

  ENDMETHOD.

  METHOD test02.

    DATA: lv_relevant TYPE abap_bool.

    lv_relevant = zcl_abapgit_news=>is_relevant( 'https://github.com/larshp/abapGit' ).

    cl_abap_unit_assert=>assert_equals(
      act = lv_relevant
      exp = abap_true ).

  ENDMETHOD.

  METHOD test03.

    DATA: lv_relevant TYPE abap_bool.

    lv_relevant = zcl_abapgit_news=>is_relevant( 'https://github.com/larshp/something' ).

    cl_abap_unit_assert=>assert_equals(
      act = lv_relevant
      exp = abap_false ).

  ENDMETHOD.

ENDCLASS.

CLASS ltcl_news DEFINITION DEFERRED.
CLASS zcl_abapgit_news DEFINITION LOCAL FRIENDS ltcl_news.

*----------------------------------------------------------------------*
*       CLASS ltcl_news DEFINITION
*----------------------------------------------------------------------*
* Definition of test class for news announcement
*----------------------------------------------------------------------*
CLASS ltcl_news DEFINITION FINAL FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.

  PRIVATE SECTION.

    METHODS:
      version_to_numeric FOR TESTING,
      compare_versions   FOR TESTING,
      normalize_version  FOR TESTING,
      parse_line         FOR TESTING,
      parse              FOR TESTING.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS ltcl_news IMPLEMENTATION
*----------------------------------------------------------------------*
* Implementation of test class for news announcement
*----------------------------------------------------------------------*
CLASS ltcl_news IMPLEMENTATION.

  METHOD version_to_numeric.

    DATA: lv_version_exp TYPE i VALUE 1023010,
          lv_version_act TYPE i.

    lv_version_act = zcl_abapgit_news=>version_to_numeric( '1.23.10' ).

    cl_abap_unit_assert=>assert_equals( exp = lv_version_exp
                                        act = lv_version_act
                                        msg = ' Error during conversion of version to numeric value' ).

  ENDMETHOD.

  METHOD compare_versions.

    DATA lv_result TYPE i.

    " Case 1: version A > version B
    lv_result = zcl_abapgit_news=>compare_versions( iv_a = '1.28.10' iv_b = '1.23.10' ).

    cl_abap_unit_assert=>assert_equals( exp = 1
                                        act = lv_result
                                        msg = ' Error during comparison of versions. Case: A > B' ).

    CLEAR: lv_result.

    " Case 2: version A < version B
    lv_result = zcl_abapgit_news=>compare_versions( iv_a = '1.28.10' iv_b = '2.23.10' ).

    cl_abap_unit_assert=>assert_equals( exp = -1
                                        act = lv_result
                                        msg = ' Error during comparison of versions. Case: A < B' ).

    CLEAR: lv_result.

    " Case 3: version A = version B
    lv_result = zcl_abapgit_news=>compare_versions( iv_a = '1.28.10' iv_b = '1.28.10' ).

    cl_abap_unit_assert=>assert_equals( exp = 0
                                        act = lv_result
                                        msg = ' Error during comparison of versions. Case: A = B' ).

  ENDMETHOD.

  METHOD normalize_version.

    cl_abap_unit_assert=>assert_equals(
      act = zcl_abapgit_news=>normalize_version( '1.28.10' )
      exp = '1.28.10' ).

    cl_abap_unit_assert=>assert_equals(
      act = zcl_abapgit_news=>normalize_version( 'v1.28.10' )
      exp = '1.28.10' ).

    cl_abap_unit_assert=>assert_equals(
      act = zcl_abapgit_news=>normalize_version( 'b1.28.10' )
      exp = '' ).

    cl_abap_unit_assert=>assert_equals(
      act = zcl_abapgit_news=>normalize_version( 'x.y.z' )
      exp = '' ).

  ENDMETHOD.

  METHOD parse_line.

    DATA: ls_log TYPE zcl_abapgit_news=>ty_log.

    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = '======'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_initial( ls_log ).

    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = ''
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_initial( ls_log ).

    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = '------'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_initial( ls_log ).

    CLEAR ls_log.
    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = '2017-02-13 v1.28.0'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-version    exp = '1.28.0' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_header  exp = abap_true ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-pos_to_cur exp = 1 ).

    CLEAR ls_log.
    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = '2017-02-13 v1.26.0'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-version    exp = '1.26.0' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_header  exp = abap_true ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-pos_to_cur exp = -1 ).

    CLEAR ls_log.
    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = 'news'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-version      exp = '' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_header    exp = abap_false ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-pos_to_cur   exp = 0 ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_important exp = abap_false ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-text         exp = 'news' ).

    CLEAR ls_log.
    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = ' ! important news'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-version      exp = '' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_header    exp = abap_false ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-pos_to_cur   exp = 0 ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_important exp = abap_true ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-text         exp = ' ! important news' ).

  ENDMETHOD.

  METHOD parse.

    DEFINE _add_news_log_entry.
      CLEAR: ls_log.
      ls_log-version      = &1.
      ls_log-is_header    = &2.
      ls_log-is_important = &3.
      ls_log-pos_to_cur   = &4.
      ls_log-text         = &5.
      APPEND ls_log TO lt_log_exp.
    END-OF-DEFINITION.

    DEFINE _add_news_txt_entry.
      APPEND &1 TO lt_lines.
    END-OF-DEFINITION.

    DATA: lt_log_exp TYPE zcl_abapgit_news=>tt_log,
          lt_log_act TYPE zcl_abapgit_news=>tt_log,
          ls_log     LIKE LINE OF lt_log_exp,
          lt_lines   TYPE string_table.

    " Generate test data
    _add_news_txt_entry '======'.
    _add_news_txt_entry '------'.
    _add_news_txt_entry `      `.
    _add_news_txt_entry 'abapGit changelog'.
    _add_news_txt_entry '2017-02-13 v1.28.0'.
    _add_news_txt_entry '------------------'.
    _add_news_txt_entry '+ Staging page redesigned'.
    _add_news_txt_entry '! Support for core data services'.
    _add_news_txt_entry `      `.
    _add_news_txt_entry '2017-01-25 v1.27.0'.
    _add_news_txt_entry '------------------'.
    _add_news_txt_entry '+ Two factor authentication with github.com'.
    _add_news_txt_entry '2017-01-25 v1.26.0'.

    " Case 1
    " Generate expected results
    "                   VERSION  HEAD IMP POS TEXT
    _add_news_log_entry '1.28.0' 'X'  ''  1   '2017-02-13 v1.28.0'.
    _add_news_log_entry '1.28.0' ''   ''  0   '+ Staging page redesigned'.
    _add_news_log_entry '1.28.0' ''   'X' 0   '! Support for core data services'.
    _add_news_log_entry '1.27.0' 'X'  ''  1   '2017-01-25 v1.27.0'.
    _add_news_log_entry '1.27.0' ''   ''  0   '+ Two factor authentication with github.com'.

    lt_log_act = zcl_abapgit_news=>parse( it_lines = lt_lines iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( exp = lt_log_exp
                                        act = lt_log_act
                                        msg = ' Error during parsing: Case 1.' ).

    " Case 2 (exect version match)
    CLEAR lt_log_exp.
    "                   VERSION  HEAD IMP UPD TEXT
    _add_news_log_entry '1.28.0' 'X'  ''  1   '2017-02-13 v1.28.0'.
    _add_news_log_entry '1.28.0' ''   ''  0   '+ Staging page redesigned'.
    _add_news_log_entry '1.28.0' ''   'X' 0   '! Support for core data services'.

    " Case 1: Test parsing of data
    lt_log_act = zcl_abapgit_news=>parse( it_lines = lt_lines iv_current_version = '1.27.00' ).
    cl_abap_unit_assert=>assert_equals( exp = lt_log_exp
                                        act = lt_log_act
                                        msg = ' Error during parsing: Case 2.' ).

    " Case 3 (display tail)
    CLEAR lt_log_exp.
    "                   VERSION  HEAD IMP UPD TEXT
    _add_news_log_entry '1.28.0' 'X'  ''  0   '2017-02-13 v1.28.0'.
    _add_news_log_entry '1.28.0' ''   ''  0   '+ Staging page redesigned'.
    _add_news_log_entry '1.28.0' ''   'X' 0   '! Support for core data services'.
    _add_news_log_entry '1.27.0' 'X'  ''  -1  '2017-01-25 v1.27.0'.
    _add_news_log_entry '1.27.0' ''   ''  0   '+ Two factor authentication with github.com'.
    _add_news_log_entry '1.26.0' 'X'  ''  -1  '2017-01-25 v1.26.0'.

    " Case 1: Test parsing of data
    lt_log_act = zcl_abapgit_news=>parse( it_lines = lt_lines iv_current_version = '1.28.00' ).
    cl_abap_unit_assert=>assert_equals( exp = lt_log_exp
                                        act = lt_log_act
                                        msg = ' Error during parsing: Case 3.' ).

  ENDMETHOD.

ENDCLASS.

CLASS ltcl_relevant DEFINITION DEFERRED.
CLASS zcl_abapgit_news DEFINITION LOCAL FRIENDS ltcl_relevant.

CLASS ltcl_relevant DEFINITION FINAL FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.

  PRIVATE SECTION.

    METHODS:
      test01 FOR TESTING,
      test02 FOR TESTING,
      test03 FOR TESTING.

ENDCLASS.

CLASS ltcl_relevant IMPLEMENTATION.

  METHOD test01.

    DATA: lv_relevant TYPE abap_bool.

    lv_relevant = zcl_abapgit_news=>is_relevant( 'https://github.com/larshp/abapGit.git' ).

    cl_abap_unit_assert=>assert_equals(
      act = lv_relevant
      exp = abap_true ).

  ENDMETHOD.

  METHOD test02.

    DATA: lv_relevant TYPE abap_bool.

    lv_relevant = zcl_abapgit_news=>is_relevant( 'https://github.com/larshp/abapGit' ).

    cl_abap_unit_assert=>assert_equals(
      act = lv_relevant
      exp = abap_true ).

  ENDMETHOD.

  METHOD test03.

    DATA: lv_relevant TYPE abap_bool.

    lv_relevant = zcl_abapgit_news=>is_relevant( 'https://github.com/larshp/something' ).

    cl_abap_unit_assert=>assert_equals(
      act = lv_relevant
      exp = abap_false ).

  ENDMETHOD.

ENDCLASS.

**********************************************************************
* Helper classed

CLASS lcl_string_buffer DEFINITION FINAL.
  PUBLIC SECTION.
    DATA mt_buffer TYPE string_table.
    METHODS add
      IMPORTING
        iv_str TYPE string.
ENDCLASS.

CLASS lcl_string_buffer IMPLEMENTATION.
  METHOD add.
    APPEND iv_str TO mt_buffer.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_log_entries DEFINITION FINAL.
  PUBLIC SECTION.
    DATA mt_log_entries TYPE zcl_abapgit_news=>tt_log.
    METHODS add
      IMPORTING
        iv_str TYPE string.
ENDCLASS.

CLASS lcl_log_entries IMPLEMENTATION.
  METHOD add.
    DATA ls_log LIKE LINE OF mt_log_entries.
    DATA lv_pos_to_cur_str TYPE string.

    SPLIT iv_str AT '/' INTO
      ls_log-version
      ls_log-is_header
      ls_log-is_important
      lv_pos_to_cur_str
      ls_log-text.

    CONDENSE ls_log-version.
    CONDENSE ls_log-is_header.
    CONDENSE ls_log-is_important.
    CONDENSE ls_log-text.
    ls_log-pos_to_cur = lv_pos_to_cur_str.

    APPEND ls_log TO mt_log_entries.
  ENDMETHOD.
ENDCLASS.

**********************************************************************

CLASS ltcl_news DEFINITION DEFERRED.
CLASS zcl_abapgit_news DEFINITION LOCAL FRIENDS ltcl_news.

*----------------------------------------------------------------------*
*       CLASS ltcl_news DEFINITION
*----------------------------------------------------------------------*
* Definition of test class for news announcement
*----------------------------------------------------------------------*
CLASS ltcl_news DEFINITION FINAL FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.

  PRIVATE SECTION.

    METHODS:
      version_to_numeric FOR TESTING,
      compare_versions   FOR TESTING,
      normalize_version  FOR TESTING,
      parse_line         FOR TESTING,
      parse              FOR TESTING.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS ltcl_news IMPLEMENTATION
*----------------------------------------------------------------------*
* Implementation of test class for news announcement
*----------------------------------------------------------------------*
CLASS ltcl_news IMPLEMENTATION.

  METHOD version_to_numeric.

    DATA: lv_version_exp TYPE i VALUE 1023010,
          lv_version_act TYPE i.

    lv_version_act = zcl_abapgit_news=>version_to_numeric( '1.23.10' ).

    cl_abap_unit_assert=>assert_equals( exp = lv_version_exp
                                        act = lv_version_act
                                        msg = ' Error during conversion of version to numeric value' ).

  ENDMETHOD.

  METHOD compare_versions.

    DATA lv_result TYPE i.

    " Case 1: version A > version B
    lv_result = zcl_abapgit_news=>compare_versions( iv_a = '1.28.10' iv_b = '1.23.10' ).

    cl_abap_unit_assert=>assert_equals( exp = 1
                                        act = lv_result
                                        msg = ' Error during comparison of versions. Case: A > B' ).

    CLEAR: lv_result.

    " Case 2: version A < version B
    lv_result = zcl_abapgit_news=>compare_versions( iv_a = '1.28.10' iv_b = '2.23.10' ).

    cl_abap_unit_assert=>assert_equals( exp = -1
                                        act = lv_result
                                        msg = ' Error during comparison of versions. Case: A < B' ).

    CLEAR: lv_result.

    " Case 3: version A = version B
    lv_result = zcl_abapgit_news=>compare_versions( iv_a = '1.28.10' iv_b = '1.28.10' ).

    cl_abap_unit_assert=>assert_equals( exp = 0
                                        act = lv_result
                                        msg = ' Error during comparison of versions. Case: A = B' ).

  ENDMETHOD.

  METHOD normalize_version.

    cl_abap_unit_assert=>assert_equals(
      act = zcl_abapgit_news=>normalize_version( '1.28.10' )
      exp = '1.28.10' ).

    cl_abap_unit_assert=>assert_equals(
      act = zcl_abapgit_news=>normalize_version( 'v1.28.10' )
      exp = '1.28.10' ).

    cl_abap_unit_assert=>assert_equals(
      act = zcl_abapgit_news=>normalize_version( 'b1.28.10' )
      exp = '' ).

    cl_abap_unit_assert=>assert_equals(
      act = zcl_abapgit_news=>normalize_version( 'x.y.z' )
      exp = '' ).

  ENDMETHOD.

  METHOD parse_line.

    DATA: ls_log TYPE zcl_abapgit_news=>ty_log.

    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = '======'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_initial( ls_log ).

    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = ''
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_initial( ls_log ).

    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = '------'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_initial( ls_log ).

    CLEAR ls_log.
    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = '2017-02-13 v1.28.0'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-version    exp = '1.28.0' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_header  exp = abap_true ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-pos_to_cur exp = 1 ).

    CLEAR ls_log.
    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = '2017-02-13 v1.26.0'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-version    exp = '1.26.0' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_header  exp = abap_true ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-pos_to_cur exp = -1 ).

    CLEAR ls_log.
    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = 'news'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-version      exp = '' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_header    exp = abap_false ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-pos_to_cur   exp = 0 ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_important exp = abap_false ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-text         exp = 'news' ).

    CLEAR ls_log.
    ls_log = zcl_abapgit_news=>parse_line(
      iv_line            = ' ! important news'
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-version      exp = '' ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_header    exp = abap_false ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-pos_to_cur   exp = 0 ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-is_important exp = abap_true ).
    cl_abap_unit_assert=>assert_equals( act = ls_log-text         exp = ' ! important news' ).

  ENDMETHOD.

  METHOD parse.

    DATA lt_log_act TYPE zcl_abapgit_news=>tt_log.
    DATA lo_src_text_buf TYPE REF TO lcl_string_buffer.
    DATA lo_log_entries TYPE REF TO lcl_log_entries.

    " Generate test data
    CREATE OBJECT lo_src_text_buf.
    lo_src_text_buf->add( '======' ).
    lo_src_text_buf->add( '------' ).
    lo_src_text_buf->add( `      ` ).
    lo_src_text_buf->add( 'abapGit changelog' ).
    lo_src_text_buf->add( '2017-02-13 v1.28.0' ).
    lo_src_text_buf->add( '------------------' ).
    lo_src_text_buf->add( '+ Staging page redesigned' ).
    lo_src_text_buf->add( '! Support for core data services' ).
    lo_src_text_buf->add( `      ` ).
    lo_src_text_buf->add( '2017-01-25 v1.27.0' ).
    lo_src_text_buf->add( '------------------' ).
    lo_src_text_buf->add( '+ Two factor authentication with github.com' ).
    lo_src_text_buf->add( '2017-01-25 v1.26.0' ).

    " Case 1
    " Generate expected results
    CREATE OBJECT lo_log_entries.
    "                   VERSION  HEAD IMP POS  TEXT
    lo_log_entries->add( '1.28.0 /X   /   /1   /2017-02-13 v1.28.0' ).
    lo_log_entries->add( '1.28.0 /    /   /0   /+ Staging page redesigned' ).
    lo_log_entries->add( '1.28.0 /    /X  /0   /! Support for core data services' ).
    lo_log_entries->add( '1.27.0 /X   /   /1   /2017-01-25 v1.27.0' ).
    lo_log_entries->add( '1.27.0 /    /   /0   /+ Two factor authentication with github.com' ).

    lt_log_act = zcl_abapgit_news=>parse(
      it_lines = lo_src_text_buf->mt_buffer
      iv_current_version = '1.26.01' ).
    cl_abap_unit_assert=>assert_equals(
      exp = lo_log_entries->mt_log_entries
      act = lt_log_act
      msg = ' Error during parsing: Case 1.' ).

    " Case 2 (exect version match)
    CREATE OBJECT lo_log_entries.
    "                   VERSION  HEAD IMP UPD TEXT
    lo_log_entries->add( '1.28.0 /X  /   /1   /2017-02-13 v1.28.0' ).
    lo_log_entries->add( '1.28.0 /   /   /0   /+ Staging page redesigned' ).
    lo_log_entries->add( '1.28.0 /   /X  /0   /! Support for core data services' ).

    lt_log_act = zcl_abapgit_news=>parse(
      it_lines = lo_src_text_buf->mt_buffer
      iv_current_version = '1.27.00' ).
    cl_abap_unit_assert=>assert_equals(
      exp = lo_log_entries->mt_log_entries
      act = lt_log_act
      msg = ' Error during parsing: Case 2.' ).

    " Case 3 (display tail)
    CREATE OBJECT lo_log_entries.
    "                   VERSION  HEAD IMP UPD TEXT
    lo_log_entries->add( '1.28.0 /X  /   /0   /2017-02-13 v1.28.0' ).
    lo_log_entries->add( '1.28.0 /   /   /0   /+ Staging page redesigned' ).
    lo_log_entries->add( '1.28.0 /   /X  /0   /! Support for core data services' ).
    lo_log_entries->add( '1.27.0 /X  /   /-1  /2017-01-25 v1.27.0' ).
    lo_log_entries->add( '1.27.0 /   /   /0   /+ Two factor authentication with github.com' ).
    lo_log_entries->add( '1.26.0 /X  /   /-1  /2017-01-25 v1.26.0' ).

    lt_log_act = zcl_abapgit_news=>parse(
      it_lines = lo_src_text_buf->mt_buffer
      iv_current_version = '1.28.00' ).
    cl_abap_unit_assert=>assert_equals(
      exp = lo_log_entries->mt_log_entries
      act = lt_log_act
      msg = ' Error during parsing: Case 3.' ).

  ENDMETHOD.

ENDCLASS.

remove DEFINE from zcl_abapgit_news (#3194)

* remove DEFINE from zcl_abapgit_news

* linter fix

Co-authored-by: Lars Hvam <721d1b171982cd84b755f6b25130d2b88cd1f696@hotmail.com>


REPORT zwabap_installer.

PARAMETERS: a_zip  TYPE text_512 OBLIGATORY,
            a_devc TYPE devclass DEFAULT '$WABAP_FRONTEND' OBLIGATORY.

CLASS lcl_app DEFINITION FINAL.

  PUBLIC SECTION.
    CLASS-METHODS:
      run,
      initialization,
      select_file.

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_file,
             path     TYPE string,
             filename TYPE string,
             data     TYPE xstring,
           END OF ty_file.
    TYPES: ty_files_tt TYPE STANDARD TABLE OF ty_file WITH DEFAULT KEY.

    CLASS-METHODS:
      read_file
        RETURNING VALUE(rv_xstr) TYPE xstring,
      unzip
        IMPORTING iv_xstr         TYPE xstring
        RETURNING VALUE(rt_files) TYPE ty_files_tt,
      create_folder,
      create_mimes
        IMPORTING it_files TYPE ty_files_tt,
      filename
        IMPORTING iv_str             TYPE string
        RETURNING VALUE(rv_filename) TYPE string.

ENDCLASS.

CLASS lcl_app IMPLEMENTATION.

  METHOD filename.

    DATA: lv_path TYPE string.                              "#EC NEEDED

    IF iv_str CA '/'.
      FIND REGEX '(.*/)(.*)' IN iv_str
        SUBMATCHES lv_path rv_filename.
      ASSERT sy-subrc = 0.
    ELSE.
      rv_filename = iv_str.
    ENDIF.
    TRANSLATE rv_filename TO LOWER CASE.

  ENDMETHOD.

  METHOD unzip.

    DATA: lo_zip    TYPE REF TO cl_abap_zip,
          lv_xstr   TYPE xstring,
          lt_splice TYPE cl_abap_zip=>t_splice_entries.

    FIELD-SYMBOLS: <ls_splice> LIKE LINE OF lt_splice,
                   <ls_file>   LIKE LINE OF rt_files.

    CREATE OBJECT lo_zip.
    lo_zip->load( EXPORTING
                    zip             = iv_xstr
                  EXCEPTIONS
                    zip_parse_error = 1
                    OTHERS          = 2 ).
    ASSERT sy-subrc = 0.

    lt_splice = cl_abap_zip=>splice( iv_xstr ).

    LOOP AT lt_splice ASSIGNING <ls_splice>.
      lo_zip->get(
        EXPORTING
          name                    = <ls_splice>-name
        IMPORTING
          content                 = lv_xstr
        EXCEPTIONS
          zip_index_error         = 1
          zip_decompression_error = 2
          OTHERS                  = 3 ).
      ASSERT sy-subrc = 0.

      APPEND INITIAL LINE TO rt_files ASSIGNING <ls_file>.
      <ls_file>-path     = '/'.
      <ls_file>-filename = filename( <ls_splice>-name ).
      <ls_file>-data     = lv_xstr.

    ENDLOOP.

  ENDMETHOD.

  METHOD initialization.

    CALL FUNCTION 'RS_SUPPORT_SELECTIONS'
      EXPORTING
        report               = sy-cprog
        variant              = 'DEFAULT'
      EXCEPTIONS
        variant_not_existent = 01
        variant_obsolete     = 02
        ##fm_subrc_ok. "#EC CI_SUBRC

  ENDMETHOD.

  METHOD read_file.

    TYPES: ty_hex200 TYPE x LENGTH 200.

    DATA: lv_length   TYPE i,
          lv_filename TYPE string,
          lt_data     TYPE STANDARD TABLE OF ty_hex200.

    lv_filename = a_zip.

    cl_gui_frontend_services=>gui_upload(
      EXPORTING
        filename                = lv_filename
        filetype                = 'BIN'
      IMPORTING
        filelength              = lv_length
      CHANGING
        data_tab                = lt_data
      EXCEPTIONS
        file_open_error         = 1
        file_read_error         = 2
        no_batch                = 3
        gui_refuse_filetransfer = 4
        invalid_type            = 5
        no_authority            = 6
        unknown_error           = 7
        bad_data_format         = 8
        header_not_allowed      = 9
        separator_not_allowed   = 10
        header_too_long         = 11
        unknown_dp_error        = 12
        access_denied           = 13
        dp_out_of_memory        = 14
        disk_full               = 15
        dp_timeout              = 16
        not_supported_by_gui    = 17
        error_no_gui            = 18
        OTHERS                  = 19 ).
    ASSERT sy-subrc = 0.

    CONCATENATE LINES OF lt_data INTO rv_xstr IN BYTE MODE.

    rv_xstr = rv_xstr(lv_length).

  ENDMETHOD.

  METHOD run.

    create_mimes( unzip( read_file( ) ) ).

    WRITE: / 'Done'.

  ENDMETHOD.

  METHOD create_folder.

    DATA: li_api TYPE REF TO if_mr_api.

    li_api = cl_mime_repository_api=>if_mr_api~get_api( ).

    li_api->create_folder(
      EXPORTING
        i_url              = zcl_wabap_service=>gc_url
        i_description      = 'wabap'
        i_dev_package      = a_devc
      EXCEPTIONS
        parameter_missing  = 1
        error_occured      = 2
        cancelled          = 3
        permission_failure = 4
        folder_exists      = 5
        OTHERS             = 6 ).
    ASSERT sy-subrc = 0 OR sy-subrc = 5.

  ENDMETHOD.

  METHOD create_mimes.

    DATA: lv_url TYPE string,
          li_api TYPE REF TO if_mr_api.

    FIELD-SYMBOLS: <ls_file> LIKE LINE OF it_files.

    create_folder( ).

    li_api = cl_mime_repository_api=>if_mr_api~get_api( ).

    LOOP AT it_files ASSIGNING <ls_file>.
      lv_url = zcl_wabap_service=>gc_url && '/' && <ls_file>-filename.

      WRITE: / lv_url.

      li_api->put(
        EXPORTING
          i_url                   = lv_url
          i_content               = <ls_file>-data
          i_dev_package           = a_devc
        EXCEPTIONS
          parameter_missing       = 1
          error_occured           = 2
          cancelled               = 3
          permission_failure      = 4
          data_inconsistency      = 5
          new_loio_already_exists = 6
          is_folder               = 7
          OTHERS                  = 8 ).
      ASSERT sy-subrc = 0.

    ENDLOOP.

  ENDMETHOD.

  METHOD select_file.

    DATA: lt_filetable TYPE filetable,
          lv_rc        TYPE i.

    cl_gui_frontend_services=>file_open_dialog(
      CHANGING
        file_table              = lt_filetable
        rc                      = lv_rc
      EXCEPTIONS
        file_open_dialog_failed = 1
        cntl_error              = 2
        error_no_gui            = 3
        not_supported_by_gui    = 4
        OTHERS                  = 5 ).
    ASSERT sy-subrc = 0.

    IF lv_rc = 1.
      a_zip = lt_filetable[ 1 ]-filename.
    ENDIF.

  ENDMETHOD.

ENDCLASS.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR a_zip.
  lcl_app=>select_file( ).

INITIALIZATION.
  lcl_app=>initialization( ).

START-OF-SELECTION.
  lcl_app=>run( ).

test executable

test executable


"! Change transport system API
CLASS zcl_abapgit_cts_api DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE
  GLOBAL FRIENDS zcl_abapgit_factory.

  PUBLIC SECTION.
    INTERFACES:
      zif_abapgit_cts_api.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_abapgit_cts_api IMPLEMENTATION.
  METHOD zif_abapgit_cts_api~get_current_transport_for_obj.
    DATA: lv_object_lockable   TYPE abap_bool,
          lv_locked            TYPE abap_bool,
          lv_transport_request TYPE trkorr,
          lv_task              TYPE trkorr,
          lv_tr_object_name    TYPE trobj_name.

    lv_tr_object_name = iv_object_name.

    CALL FUNCTION 'TR_CHECK_OBJECT_LOCK'
      EXPORTING
        wi_pgmid             = iv_program_id
        wi_object            = iv_object_type
        wi_objname           = lv_tr_object_name
      IMPORTING
        we_lockable_object   = lv_object_lockable
        we_locked            = lv_locked
        we_lock_order        = lv_transport_request
        we_lock_task         = lv_task
      EXCEPTIONS
        empty_key            = 1
        no_systemname        = 2
        no_systemtype        = 3
        unallowed_lock_order = 4
        OTHERS               = 5.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    IF lv_locked = abap_false.
      zcx_abapgit_exception=>raise( |Object { iv_program_id }-{ iv_object_type }-{ iv_object_name } is not locked| ).
    ENDIF.

    IF lv_object_lockable = abap_false.
      zcx_abapgit_exception=>raise( |Object type { iv_program_id }-{ iv_object_type } not lockable| ).
    ENDIF.

    IF lv_task IS NOT INITIAL AND lv_task <> lv_transport_request AND iv_resolve_task_to_request = abap_false.
      rv_transport = lv_task.
    ELSE.
      rv_transport = lv_transport_request.
    ENDIF.
  ENDMETHOD.

  METHOD zif_abapgit_cts_api~is_object_locked_in_transport.
    DATA: ls_object_key        TYPE e071,
          lv_type_check_result TYPE c LENGTH 1,
          ls_lock_key          TYPE tlock_int,
          lv_lock_flag         TYPE c LENGTH 1.

    ls_object_key-pgmid = iv_program_id.
    ls_object_key-object = iv_object_type.
    ls_object_key-obj_name = iv_object_name.

    CALL FUNCTION 'TR_CHECK_TYPE'
      EXPORTING
        wi_e071     = ls_object_key
      IMPORTING
        pe_result   = lv_type_check_result
        we_lock_key = ls_lock_key.

    IF lv_type_check_result <> 'L'.
      zcx_abapgit_exception=>raise( |Object type { iv_program_id }-{ iv_object_type } not lockable| ).
    ENDIF.

    CALL FUNCTION 'TRINT_CHECK_LOCKS'
      EXPORTING
        wi_lock_key = ls_lock_key
      IMPORTING
        we_lockflag = lv_lock_flag
      EXCEPTIONS
        empty_key   = 1
        OTHERS      = 2.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |TRINT_CHECK_LOCKS: { sy-subrc }| ).
    ENDIF.

    rv_locked = boolc( lv_lock_flag <> space ).
  ENDMETHOD.

  METHOD zif_abapgit_cts_api~is_object_type_lockable.
    DATA: ls_object_key        TYPE e071,
          lv_type_check_result TYPE c LENGTH 1.

    ls_object_key-pgmid = iv_program_id.
    ls_object_key-object = iv_object_type.
    ls_object_key-obj_name = '*'.

    CALL FUNCTION 'TR_CHECK_TYPE'
      EXPORTING
        wi_e071   = ls_object_key
      IMPORTING
        pe_result = lv_type_check_result.

    rv_lockable = boolc( lv_type_check_result = 'L' ).
  ENDMETHOD.

  METHOD zif_abapgit_cts_api~is_chrec_possible_for_package.
    rv_possible = zcl_abapgit_factory=>get_sap_package( iv_package )->are_changes_recorded_in_tr_req( ).
  ENDMETHOD.
ENDCLASS.

"! Change transport system API
CLASS zcl_abapgit_cts_api DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE
  GLOBAL FRIENDS zcl_abapgit_factory.

  PUBLIC SECTION.
    INTERFACES:
      zif_abapgit_cts_api.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_abapgit_cts_api IMPLEMENTATION.
  METHOD zif_abapgit_cts_api~get_current_transport_for_obj.
    DATA: lv_object_lockable   TYPE abap_bool,
          lv_locked            TYPE abap_bool,
          lv_transport_request TYPE trkorr,
          lv_task              TYPE trkorr,
          lv_tr_object_name    TYPE trobj_name.

    lv_tr_object_name = iv_object_name.

    CALL FUNCTION 'TR_CHECK_OBJECT_LOCK'
      EXPORTING
        wi_pgmid             = iv_program_id
        wi_object            = iv_object_type
        wi_objname           = lv_tr_object_name
      IMPORTING
        we_lockable_object   = lv_object_lockable
        we_locked            = lv_locked
        we_lock_order        = lv_transport_request
        we_lock_task         = lv_task
      EXCEPTIONS
        empty_key            = 1
        no_systemname        = 2
        no_systemtype        = 3
        unallowed_lock_order = 4
        OTHERS               = 5.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    IF lv_locked = abap_false.
      zcx_abapgit_exception=>raise( |Object { iv_program_id }-{ iv_object_type }-{ iv_object_name } is not locked| ).
    ENDIF.

    IF lv_object_lockable = abap_false.
      zcx_abapgit_exception=>raise( |Object type { iv_program_id }-{ iv_object_type } not lockable| ).
    ENDIF.

    IF lv_task IS NOT INITIAL AND lv_task <> lv_transport_request AND iv_resolve_task_to_request = abap_false.
      rv_transport = lv_task.
    ELSE.
      rv_transport = lv_transport_request.
    ENDIF.
  ENDMETHOD.

  METHOD zif_abapgit_cts_api~is_object_locked_in_transport.
    DATA: ls_object_key        TYPE e071,
          lv_type_check_result TYPE c LENGTH 1,
          ls_lock_key          TYPE tlock_int,
          lv_lock_flag         TYPE c LENGTH 1.

    ls_object_key-pgmid = iv_program_id.
    ls_object_key-object = iv_object_type.
    ls_object_key-obj_name = iv_object_name.

    CALL FUNCTION 'TR_CHECK_TYPE'
      EXPORTING
        wi_e071     = ls_object_key
      IMPORTING
        pe_result   = lv_type_check_result
        we_lock_key = ls_lock_key.

    IF lv_type_check_result <> 'L'.
      zcx_abapgit_exception=>raise( |Object type { iv_program_id }-{ iv_object_type } not lockable| ).
    ENDIF.

    CALL FUNCTION 'TRINT_CHECK_LOCKS'
      EXPORTING
        wi_lock_key = ls_lock_key
      IMPORTING
        we_lockflag = lv_lock_flag
      EXCEPTIONS
        empty_key   = 1
        OTHERS      = 2.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |TRINT_CHECK_LOCKS: { sy-subrc }| ).
    ENDIF.

    rv_locked = boolc( lv_lock_flag <> space ).
  ENDMETHOD.

  METHOD zif_abapgit_cts_api~is_object_type_lockable.
    DATA: ls_object_key        TYPE e071,
          lv_type_check_result TYPE c LENGTH 1.

    ls_object_key-pgmid = iv_program_id.
    ls_object_key-object = iv_object_type.
    ls_object_key-obj_name = '_'. " Dummy value #2071

    CALL FUNCTION 'TR_CHECK_TYPE'
      EXPORTING
        wi_e071   = ls_object_key
      IMPORTING
        pe_result = lv_type_check_result.

    rv_lockable = boolc( lv_type_check_result = 'L' ).
  ENDMETHOD.

  METHOD zif_abapgit_cts_api~is_chrec_possible_for_package.
    rv_possible = zcl_abapgit_factory=>get_sap_package( iv_package )->are_changes_recorded_in_tr_req( ).
  ENDMETHOD.
ENDCLASS.

Change dummy value for TR_CHECK_TYPE

Change dummy value for TR_CHECK_TYPE

Fixes #2071


CLASS zcl_abapgit_gui_page_repo_sett DEFINITION
  PUBLIC
  INHERITING FROM zcl_abapgit_gui_page
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    METHODS constructor
      IMPORTING
                !io_repo TYPE REF TO zcl_abapgit_repo
      RAISING   zcx_abapgit_exception.

    METHODS zif_abapgit_gui_event_handler~on_event
        REDEFINITION .
  PROTECTED SECTION.

    CONSTANTS:
      BEGIN OF c_action,
        save_settings TYPE string VALUE 'save_settings',
      END OF c_action .
    DATA mo_repo TYPE REF TO zcl_abapgit_repo.

    METHODS render_dot_abapgit
      IMPORTING
        !ii_html TYPE REF TO zif_abapgit_html .
    METHODS render_local_settings
      IMPORTING
        !ii_html TYPE REF TO zif_abapgit_html
      RAISING
        zcx_abapgit_exception .
    METHODS save
      IMPORTING
        !it_postdata TYPE cnht_post_data_tab
      RAISING
        zcx_abapgit_exception .
    METHODS save_dot_abap
      IMPORTING
        !it_post_fields TYPE tihttpnvp
      RAISING
        zcx_abapgit_exception .
    METHODS save_local_settings
      IMPORTING
        !it_post_fields TYPE tihttpnvp
      RAISING
        zcx_abapgit_exception .
    METHODS parse_post
      IMPORTING
        !it_postdata          TYPE cnht_post_data_tab
      RETURNING
        VALUE(rt_post_fields) TYPE tihttpnvp .
    METHODS render_dot_abapgit_reqs
      IMPORTING
        ii_html         TYPE REF TO zif_abapgit_html
        it_requirements TYPE zif_abapgit_dot_abapgit=>ty_requirement_tt.
    METHODS render_table_row
      IMPORTING
        iv_name        TYPE string
        iv_value       TYPE string
      RETURNING
        VALUE(rv_html) TYPE string.

    METHODS render_content
        REDEFINITION .

  PRIVATE SECTION.

ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_PAGE_REPO_SETT IMPLEMENTATION.

  METHOD constructor.
    super->constructor( ).
    ms_control-page_title = 'REPO SETTINGS'.
    mo_repo = io_repo.
  ENDMETHOD.

  METHOD parse_post.

    DATA lv_serialized_post_data TYPE string.

    CONCATENATE LINES OF it_postdata INTO lv_serialized_post_data.
    rt_post_fields = zcl_abapgit_html_action_utils=>parse_fields( lv_serialized_post_data ).

  ENDMETHOD.

  METHOD render_content.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.
    ri_html->add( '
' ).
    ri_html->add( |<form id="settings_form" method="post" action="sapevent:{ c_action-save_settings }">| ).

    render_dot_abapgit( ri_html ).
    render_local_settings( ri_html ).

    ri_html->add( '<input type="submit" value="Save" class="floating-button blue-set emphasis">' ).
    ri_html->add( '</form>' ).
    ri_html->add( '
' ).

  ENDMETHOD.

  METHOD render_dot_abapgit.

    DATA: ls_dot          TYPE zif_abapgit_dot_abapgit=>ty_dot_abapgit,
          lv_select_html  TYPE string,
          lv_selected     TYPE string,
          lv_language     TYPE t002t-sptxt,
          lv_ignore       TYPE string,
          lt_folder_logic TYPE string_table.

    FIELD-SYMBOLS: <lv_folder_logic> TYPE LINE OF string_table,
                   <lv_ignore>       TYPE string.

    ls_dot = mo_repo->get_dot_abapgit( )->get_data( ).

    APPEND zif_abapgit_dot_abapgit=>c_folder_logic-full TO lt_folder_logic.
    APPEND zif_abapgit_dot_abapgit=>c_folder_logic-prefix TO lt_folder_logic.

    ii_html->add( '
.abapgit.xml
' ).
    ii_html->add( '
' ).

    SELECT SINGLE sptxt INTO lv_language FROM t002t
      WHERE spras = sy-langu AND sprsl = ls_dot-master_language.
    IF sy-subrc <> 0.
      lv_language = 'Unknown language. Check your settings.'.
    ENDIF.

    ii_html->add( render_table_row(
      iv_name  = 'Master language'
      iv_value = |{ ls_dot-master_language } ({ lv_language })|
    ) ).

    lv_select_html = '<select name="folder_logic">'.
    LOOP AT lt_folder_logic ASSIGNING <lv_folder_logic>.

      IF ls_dot-folder_logic = <lv_folder_logic>.
        lv_selected = ' selected'.
      ELSE.
        CLEAR: lv_selected.
      ENDIF.

      lv_select_html = lv_select_html
        && |<option value="{ <lv_folder_logic> }"{ lv_selected }>{ <lv_folder_logic> }</option>|.

    ENDLOOP.
    lv_select_html = lv_select_html && '</select>'.

    ii_html->add( render_table_row(
      iv_name  = 'Folder logic'
      iv_value = lv_select_html
    ) ).

    ii_html->add( render_table_row(
      iv_name  = 'Starting folder'
      iv_value = |<input name="starting_folder" type="text" size="10" value="{ ls_dot-starting_folder }">|
    ) ).

    LOOP AT ls_dot-ignore ASSIGNING <lv_ignore>.
      lv_ignore = lv_ignore && <lv_ignore> && zif_abapgit_definitions=>c_newline.
    ENDLOOP.

    ii_html->add( render_table_row(
      iv_name  = 'Ignore files'
      iv_value = |<textarea name="ignore_files" rows="{ lines( ls_dot-ignore )
                 }" cols="50">{ lv_ignore }</textarea>|
    ) ).

    ii_html->add( '
' ).

    render_dot_abapgit_reqs(
      it_requirements = ls_dot-requirements
      ii_html         = ii_html ).

  ENDMETHOD.

  METHOD render_dot_abapgit_reqs.

    CONSTANTS: lc_requirement_edit_min_count TYPE i VALUE 5.
    DATA lv_req_index TYPE i.
    DATA lv_requirement_count TYPE i.
    DATA lt_requirements LIKE it_requirements.
    FIELD-SYMBOLS <ls_requirement> TYPE zif_abapgit_dot_abapgit=>ty_requirement.

    lt_requirements      = it_requirements.
    lv_requirement_count = lines( lt_requirements ).
    IF lv_requirement_count < lc_requirement_edit_min_count.
      DO - lv_requirement_count + lc_requirement_edit_min_count TIMES.
        APPEND INITIAL LINE TO lt_requirements.
      ENDDO.
    ENDIF.

    ii_html->add( '
Requirements
' ).
    ii_html->add( '
' ).
    ii_html->add( '
Software Component	Min Release	Min Patch
' ).

    LOOP AT lt_requirements ASSIGNING <ls_requirement>.
      lv_req_index = sy-tabix.

      ii_html->add( '
' ).
      ii_html->add( |<input name="req_com_{ lv_req_index }" maxlength=30 type="text" | &&
                    |value="{ <ls_requirement>-component }">	| ).
      ii_html->add( |<input name="req_rel_{ lv_req_index }" maxlength=10 type="text" | &&
                    |value="{ <ls_requirement>-min_release }">	| ).
      ii_html->add( |<input name="req_pat_{ lv_req_index }" maxlength=10 type="text" | &&
                    |value="{ <ls_requirement>-min_patch }">	| ).
      ii_html->add( '
' ).
    ENDLOOP.

    ii_html->add( '
' ).

  ENDMETHOD.

  METHOD render_local_settings.

    DATA: lv_checked  TYPE string,
          ls_settings TYPE zif_abapgit_persistence=>ty_repo-local_settings.

    ls_settings = mo_repo->get_local_settings( ).

    ii_html->add( '
Local settings
' ).
    ii_html->add( '
' ).

    ii_html->add( render_table_row(
      iv_name  = 'Display name'
      iv_value = |<input name="display_name" type="text" size="30" value="{ ls_settings-display_name }">|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-write_protected = abap_true.
      IF zcl_abapgit_factory=>get_environment( )->is_repo_object_changes_allowed( ) = abap_true.
        lv_checked = | checked|.
      ELSE.
        lv_checked = | checked disabled|.
      ENDIF.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Write protected'
      iv_value = |<input name="write_protected" type="checkbox"{ lv_checked }>|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-ignore_subpackages = abap_true.
      lv_checked = | checked|.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Ignore subpackages'
      iv_value = |<input name="ignore_subpackages" type="checkbox"{ lv_checked }>|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-only_local_objects = abap_true.
      lv_checked = | checked|.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Only local objects'
      iv_value = |<input name="only_local_objects" type="checkbox"{ lv_checked }>|
    ) ).

    ii_html->add( render_table_row(
      iv_name  = 'Code inspector check variant'
      iv_value = |<input name="check_variant" type="text" size="30" value="{
        ls_settings-code_inspector_check_variant }">|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-block_commit = abap_true.
      lv_checked = | checked|.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Block commit if code inspection has errors'
      iv_value = |<input name="block_commit" type="checkbox"{ lv_checked }>|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-serialize_master_lang_only = abap_true.
      lv_checked = | checked|.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Serialize master language only'
      iv_value = |<input name="serialize_master_lang_only" type="checkbox"{ lv_checked }>|
    ) ).

    ii_html->add( '
' ).

  ENDMETHOD.

  METHOD render_table_row.

    rv_html = '
'
      && |{ iv_name }	|
      && |{ iv_value }	|
      && '
'.

  ENDMETHOD.

  METHOD save.

    DATA: lt_post_fields TYPE tihttpnvp.

    lt_post_fields = parse_post( it_postdata ).

    save_dot_abap( lt_post_fields ).
    save_local_settings( lt_post_fields ).

    mo_repo->refresh( ).

  ENDMETHOD.

  METHOD save_dot_abap.

    DATA: lo_dot          TYPE REF TO zcl_abapgit_dot_abapgit,
          ls_post_field   LIKE LINE OF it_post_fields,
          lv_ignore       TYPE string,
          lt_ignore       TYPE STANDARD TABLE OF string WITH DEFAULT KEY,
          lo_requirements TYPE REF TO lcl_requirements.

    lo_dot = mo_repo->get_dot_abapgit( ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'folder_logic'.
    ASSERT sy-subrc = 0.
    lo_dot->set_folder_logic( ls_post_field-value ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'starting_folder'.
    ASSERT sy-subrc = 0.
    lo_dot->set_starting_folder( ls_post_field-value ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'ignore_files'.
    ASSERT sy-subrc = 0.

    " Remove everything
    lt_ignore = lo_dot->get_data( )-ignore.
    LOOP AT lt_ignore INTO lv_ignore.
      lo_dot->remove_ignore( iv_path = ''
                             iv_filename = lv_ignore ).
    ENDLOOP.

    " Add newly entered files
    CLEAR lt_ignore.
    SPLIT ls_post_field-value AT zif_abapgit_definitions=>c_newline INTO TABLE lt_ignore.
    DELETE lt_ignore WHERE table_line IS INITIAL.
    LOOP AT lt_ignore INTO lv_ignore.
      lo_dot->add_ignore( iv_path = ''
                          iv_filename = lv_ignore ).
    ENDLOOP.

    lo_requirements = lcl_requirements=>new( ).
    LOOP AT it_post_fields INTO ls_post_field WHERE name CP 'req_*'.
      CASE ls_post_field-name+4(3).
        WHEN 'com'.
          lo_requirements->set_component( ls_post_field-value ).
        WHEN 'rel'.
          lo_requirements->set_min_release( ls_post_field-value ).
        WHEN 'pat'.
          lo_requirements->set_min_patch( ls_post_field-value ).
      ENDCASE.
    ENDLOOP.

    lo_dot->set_requirements( lo_requirements->get_as_table( ) ).

    mo_repo->set_dot_abapgit( lo_dot ).

  ENDMETHOD.

  METHOD save_local_settings.

    DATA: ls_settings      TYPE zif_abapgit_persistence=>ty_repo-local_settings,
          ls_post_field    LIKE LINE OF it_post_fields,
          lv_check_variant TYPE sci_chkv.

    ls_settings = mo_repo->get_local_settings( ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'display_name'.
    ASSERT sy-subrc = 0.
    ls_settings-display_name = ls_post_field-value.

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'write_protected' value = 'on'.
    ls_settings-write_protected = boolc( sy-subrc = 0 ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'ignore_subpackages' value = 'on'.
    ls_settings-ignore_subpackages = boolc( sy-subrc = 0 ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'only_local_objects' value = 'on'.
    ls_settings-only_local_objects = boolc( sy-subrc = 0 ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'check_variant'.
    ASSERT sy-subrc = 0.
    lv_check_variant = to_upper( ls_post_field-value ).
    IF ls_post_field-value IS NOT INITIAL.
      zcl_abapgit_code_inspector=>validate_check_variant( lv_check_variant ).
    ENDIF.
    ls_settings-code_inspector_check_variant = lv_check_variant.

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'block_commit' value = 'on'.
    ls_settings-block_commit = boolc( sy-subrc = 0 ).

    IF ls_settings-block_commit = abap_true
        AND ls_settings-code_inspector_check_variant IS INITIAL.
      zcx_abapgit_exception=>raise( |If block commit is active, a check variant has to be maintained.| ).
    ENDIF.

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'serialize_master_lang_only' value = 'on'.
    ls_settings-serialize_master_lang_only = boolc( sy-subrc = 0 ).

    mo_repo->set_local_settings( ls_settings ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    CASE iv_action.
      WHEN c_action-save_settings.
        save( it_postdata ).
        ev_state = zcl_abapgit_gui=>c_event_state-go_back.
    ENDCASE.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_gui_page_repo_sett DEFINITION
  PUBLIC
  INHERITING FROM zcl_abapgit_gui_page
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    METHODS constructor
      IMPORTING
                !io_repo TYPE REF TO zcl_abapgit_repo
      RAISING   zcx_abapgit_exception.

    METHODS zif_abapgit_gui_event_handler~on_event
        REDEFINITION .
  PROTECTED SECTION.

    CONSTANTS:
      BEGIN OF c_action,
        save_settings TYPE string VALUE 'save_settings',
      END OF c_action .
    DATA mo_repo TYPE REF TO zcl_abapgit_repo.

    METHODS render_dot_abapgit
      IMPORTING
        !ii_html TYPE REF TO zif_abapgit_html .
    METHODS render_local_settings
      IMPORTING
        !ii_html TYPE REF TO zif_abapgit_html
      RAISING
        zcx_abapgit_exception .
    METHODS save
      IMPORTING
        !it_postdata TYPE cnht_post_data_tab
      RAISING
        zcx_abapgit_exception .
    METHODS save_dot_abap
      IMPORTING
        !it_post_fields TYPE tihttpnvp
      RAISING
        zcx_abapgit_exception .
    METHODS save_local_settings
      IMPORTING
        !it_post_fields TYPE tihttpnvp
      RAISING
        zcx_abapgit_exception .
    METHODS parse_post
      IMPORTING
        !it_postdata          TYPE cnht_post_data_tab
      RETURNING
        VALUE(rt_post_fields) TYPE tihttpnvp .
    METHODS render_dot_abapgit_reqs
      IMPORTING
        ii_html         TYPE REF TO zif_abapgit_html
        it_requirements TYPE zif_abapgit_dot_abapgit=>ty_requirement_tt.
    METHODS render_table_row
      IMPORTING
        iv_name        TYPE string
        iv_value       TYPE string
      RETURNING
        VALUE(rv_html) TYPE string.

    METHODS render_content
        REDEFINITION .

  PRIVATE SECTION.

ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_PAGE_REPO_SETT IMPLEMENTATION.

  METHOD constructor.
    super->constructor( ).
    ms_control-page_title = 'REPO SETTINGS'.
    mo_repo = io_repo.
  ENDMETHOD.

  METHOD parse_post.

    DATA lv_serialized_post_data TYPE string.

    CONCATENATE LINES OF it_postdata INTO lv_serialized_post_data.
    rt_post_fields = zcl_abapgit_html_action_utils=>parse_fields( lv_serialized_post_data ).

  ENDMETHOD.

  METHOD render_content.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.
    ri_html->add( '
' ).
    ri_html->add( |<form id="settings_form" method="post" action="sapevent:{ c_action-save_settings }">| ).

    render_dot_abapgit( ri_html ).
    render_local_settings( ri_html ).

    ri_html->add( '<input type="submit" value="Save" class="floating-button blue-set emphasis">' ).
    ri_html->add( '</form>' ).
    ri_html->add( '
' ).

  ENDMETHOD.

  METHOD render_dot_abapgit.

    DATA: ls_dot          TYPE zif_abapgit_dot_abapgit=>ty_dot_abapgit,
          lv_select_html  TYPE string,
          lv_selected     TYPE string,
          lv_language     TYPE t002t-sptxt,
          lv_ignore       TYPE string,
          lt_folder_logic TYPE string_table.

    FIELD-SYMBOLS: <lv_folder_logic> TYPE LINE OF string_table,
                   <lv_ignore>       TYPE string.

    ls_dot = mo_repo->get_dot_abapgit( )->get_data( ).

    APPEND zif_abapgit_dot_abapgit=>c_folder_logic-full TO lt_folder_logic.
    APPEND zif_abapgit_dot_abapgit=>c_folder_logic-prefix TO lt_folder_logic.

    ii_html->add( '
.abapgit.xml
' ).
    ii_html->add( '
' ).

    SELECT SINGLE sptxt INTO lv_language FROM t002t
      WHERE spras = sy-langu AND sprsl = ls_dot-master_language.
    IF sy-subrc <> 0.
      lv_language = 'Unknown language. Check your settings.'.
    ENDIF.

    ii_html->add( render_table_row(
      iv_name  = 'Master language'
      iv_value = |{ ls_dot-master_language } ({ lv_language })|
    ) ).

    lv_select_html = '<select name="folder_logic">'.
    LOOP AT lt_folder_logic ASSIGNING <lv_folder_logic>.

      IF ls_dot-folder_logic = <lv_folder_logic>.
        lv_selected = ' selected'.
      ELSE.
        CLEAR: lv_selected.
      ENDIF.

      lv_select_html = lv_select_html
        && |<option value="{ <lv_folder_logic> }"{ lv_selected }>{ <lv_folder_logic> }</option>|.

    ENDLOOP.
    lv_select_html = lv_select_html && '</select>'.

    ii_html->add( render_table_row(
      iv_name  = 'Folder logic'
      iv_value = lv_select_html
    ) ).

    ii_html->add( render_table_row(
      iv_name  = 'Starting folder'
      iv_value = |<input name="starting_folder" type="text" size="10" value="{ ls_dot-starting_folder }">|
    ) ).

    LOOP AT ls_dot-ignore ASSIGNING <lv_ignore>.
      lv_ignore = lv_ignore && <lv_ignore> && zif_abapgit_definitions=>c_newline.
    ENDLOOP.

    ii_html->add( render_table_row(
      iv_name  = 'Ignore files'
      iv_value = |<textarea name="ignore_files" rows="{ lines( ls_dot-ignore )
                 }" cols="50">{ lv_ignore }</textarea>|
    ) ).

    ii_html->add( '
' ).

    render_dot_abapgit_reqs(
      it_requirements = ls_dot-requirements
      ii_html         = ii_html ).

  ENDMETHOD.

  METHOD render_dot_abapgit_reqs.

    CONSTANTS: lc_requirement_edit_min_count TYPE i VALUE 5.
    DATA lv_req_index TYPE i.
    DATA lv_requirement_count TYPE i.
    DATA lt_requirements LIKE it_requirements.
    FIELD-SYMBOLS <ls_requirement> TYPE zif_abapgit_dot_abapgit=>ty_requirement.

    lt_requirements      = it_requirements.
    lv_requirement_count = lines( lt_requirements ).
    IF lv_requirement_count < lc_requirement_edit_min_count.
      DO - lv_requirement_count + lc_requirement_edit_min_count TIMES.
        APPEND INITIAL LINE TO lt_requirements.
      ENDDO.
    ENDIF.

    ii_html->add( '
Requirements
' ).
    ii_html->add( '
' ).
    ii_html->add( '
Software Component	Min Release	Min Patch
' ).

    LOOP AT lt_requirements ASSIGNING <ls_requirement>.
      lv_req_index = sy-tabix.

      ii_html->add( '
' ).
      ii_html->add( |<input name="req_com_{ lv_req_index }" maxlength=30 type="text" | &&
                    |value="{ <ls_requirement>-component }">	| ).
      ii_html->add( |<input name="req_rel_{ lv_req_index }" maxlength=10 type="text" | &&
                    |value="{ <ls_requirement>-min_release }">	| ).
      ii_html->add( |<input name="req_pat_{ lv_req_index }" maxlength=10 type="text" | &&
                    |value="{ <ls_requirement>-min_patch }">	| ).
      ii_html->add( '
' ).
    ENDLOOP.

    ii_html->add( '
' ).

  ENDMETHOD.

  METHOD render_local_settings.

    DATA: lv_checked  TYPE string,
          ls_settings TYPE zif_abapgit_persistence=>ty_repo-local_settings.

    ls_settings = mo_repo->get_local_settings( ).

    ii_html->add( '
Local settings
' ).
    ii_html->add( '
' ).

    ii_html->add( render_table_row(
      iv_name  = 'Display name'
      iv_value = |<input name="display_name" type="text" size="30" value="{ ls_settings-display_name }">|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-write_protected = abap_true.
      IF zcl_abapgit_factory=>get_environment( )->is_repo_object_changes_allowed( ) = abap_true.
        lv_checked = | checked|.
      ELSE.
        lv_checked = | checked disabled|.
      ENDIF.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Write protected'
      iv_value = |<input name="write_protected" type="checkbox"{ lv_checked }>|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-ignore_subpackages = abap_true.
      lv_checked = | checked|.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Ignore subpackages'
      iv_value = |<input name="ignore_subpackages" type="checkbox"{ lv_checked }>|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-only_local_objects = abap_true.
      lv_checked = | checked|.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Only local objects'
      iv_value = |<input name="only_local_objects" type="checkbox"{ lv_checked }>|
    ) ).

    ii_html->add( render_table_row(
      iv_name  = 'Code inspector check variant'
      iv_value = |<input name="check_variant" type="text" size="30" value="{
        ls_settings-code_inspector_check_variant }">|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-block_commit = abap_true.
      lv_checked = | checked|.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Block commit if code inspection has errors'
      iv_value = |<input name="block_commit" type="checkbox"{ lv_checked }>|
    ) ).

    CLEAR lv_checked.
    IF ls_settings-serialize_master_lang_only = abap_true.
      lv_checked = | checked|.
    ENDIF.
    ii_html->add( render_table_row(
      iv_name  = 'Serialize master language only'
      iv_value = |<input name="serialize_master_lang_only" type="checkbox"{ lv_checked }>|
    ) ).

    ii_html->add( '
' ).

  ENDMETHOD.

  METHOD render_table_row.

    rv_html = '
'
      && |{ iv_name }	|
      && |{ iv_value }	|
      && '
'.

  ENDMETHOD.

  METHOD save.

    DATA: lt_post_fields TYPE tihttpnvp.

    lt_post_fields = parse_post( it_postdata ).

    save_dot_abap( lt_post_fields ).
    save_local_settings( lt_post_fields ).

    mo_repo->refresh( ).

  ENDMETHOD.

  METHOD save_dot_abap.

    DATA: lo_dot          TYPE REF TO zcl_abapgit_dot_abapgit,
          ls_post_field   LIKE LINE OF it_post_fields,
          lv_ignore       TYPE string,
          lt_ignore       TYPE STANDARD TABLE OF string WITH DEFAULT KEY,
          lo_requirements TYPE REF TO lcl_requirements.

    lo_dot = mo_repo->get_dot_abapgit( ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'folder_logic'.
    ASSERT sy-subrc = 0.
    lo_dot->set_folder_logic( ls_post_field-value ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'starting_folder'.
    ASSERT sy-subrc = 0.
    lo_dot->set_starting_folder( ls_post_field-value ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'ignore_files'.
    ASSERT sy-subrc = 0.

    " Remove everything
    lt_ignore = lo_dot->get_data( )-ignore.
    LOOP AT lt_ignore INTO lv_ignore.
      lo_dot->remove_ignore( iv_path = ''
                             iv_filename = lv_ignore ).
    ENDLOOP.

    " Add newly entered files
    CLEAR lt_ignore.
    REPLACE ALL OCCURRENCES OF zif_abapgit_definitions=>c_crlf IN ls_post_field-value
      WITH zif_abapgit_definitions=>c_newline.
    SPLIT ls_post_field-value AT zif_abapgit_definitions=>c_newline INTO TABLE lt_ignore.
    DELETE lt_ignore WHERE table_line IS INITIAL.
    LOOP AT lt_ignore INTO lv_ignore.
      lo_dot->add_ignore( iv_path = ''
                          iv_filename = lv_ignore ).
    ENDLOOP.

    lo_requirements = lcl_requirements=>new( ).
    LOOP AT it_post_fields INTO ls_post_field WHERE name CP 'req_*'.
      CASE ls_post_field-name+4(3).
        WHEN 'com'.
          lo_requirements->set_component( ls_post_field-value ).
        WHEN 'rel'.
          lo_requirements->set_min_release( ls_post_field-value ).
        WHEN 'pat'.
          lo_requirements->set_min_patch( ls_post_field-value ).
      ENDCASE.
    ENDLOOP.

    lo_dot->set_requirements( lo_requirements->get_as_table( ) ).

    mo_repo->set_dot_abapgit( lo_dot ).

  ENDMETHOD.

  METHOD save_local_settings.

    DATA: ls_settings      TYPE zif_abapgit_persistence=>ty_repo-local_settings,
          ls_post_field    LIKE LINE OF it_post_fields,
          lv_check_variant TYPE sci_chkv.

    ls_settings = mo_repo->get_local_settings( ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'display_name'.
    ASSERT sy-subrc = 0.
    ls_settings-display_name = ls_post_field-value.

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'write_protected' value = 'on'.
    ls_settings-write_protected = boolc( sy-subrc = 0 ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'ignore_subpackages' value = 'on'.
    ls_settings-ignore_subpackages = boolc( sy-subrc = 0 ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'only_local_objects' value = 'on'.
    ls_settings-only_local_objects = boolc( sy-subrc = 0 ).

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'check_variant'.
    ASSERT sy-subrc = 0.
    lv_check_variant = to_upper( ls_post_field-value ).
    IF ls_post_field-value IS NOT INITIAL.
      zcl_abapgit_code_inspector=>validate_check_variant( lv_check_variant ).
    ENDIF.
    ls_settings-code_inspector_check_variant = lv_check_variant.

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'block_commit' value = 'on'.
    ls_settings-block_commit = boolc( sy-subrc = 0 ).

    IF ls_settings-block_commit = abap_true
        AND ls_settings-code_inspector_check_variant IS INITIAL.
      zcx_abapgit_exception=>raise( |If block commit is active, a check variant has to be maintained.| ).
    ENDIF.

    READ TABLE it_post_fields INTO ls_post_field WITH KEY name = 'serialize_master_lang_only' value = 'on'.
    ls_settings-serialize_master_lang_only = boolc( sy-subrc = 0 ).

    mo_repo->set_local_settings( ls_settings ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    CASE iv_action.
      WHEN c_action-save_settings.
        save( it_postdata ).
        ev_state = zcl_abapgit_gui=>c_event_state-go_back.
    ENDCASE.

  ENDMETHOD.
ENDCLASS.

Fix incorrect status of ignored files in repo view (#3506)

* Fix incorrect status of ignored filed in repo view

After update of repo settings, some ignored files showed as "-/A".
https://github.com/larshp/abapGit/pull/3415

* Whitespace

Co-authored-by: Lars Hvam <721d1b171982cd84b755f6b25130d2b88cd1f696@hotmail.com>


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_SERVICES_GIT
*&---------------------------------------------------------------------*

CLASS lcl_services_git DEFINITION FINAL.
  PUBLIC SECTION.

    TYPES: BEGIN OF ty_commit_fields,
             repo_key        TYPE lcl_persistence_repo=>ty_repo-key,
             committer_name  TYPE string,
             committer_email TYPE string,
             author_name     TYPE string,
             author_email    TYPE string,
             comment         TYPE string,
             body            TYPE string,
           END OF ty_commit_fields.

    CLASS-METHODS pull
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS reset
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS create_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS switch_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS delete_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS commit
      IMPORTING io_repo   TYPE REF TO lcl_repo_online
                is_commit TYPE ty_commit_fields
                io_stage  TYPE REF TO lcl_stage
      RAISING   lcx_exception lcx_cancel.

ENDCLASS. " lcl_services_git

CLASS lcl_services_git IMPLEMENTATION.

  METHOD reset.

    DATA: lo_repo                   TYPE REF TO lcl_repo_online,
          lv_answer                 TYPE c LENGTH 1,
          lt_unnecessary_local_objs TYPE lif_defs=>ty_tadir_tt.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    IF lo_repo->is_write_protected( ) = abap_true.
      lcx_exception=>raise( 'Cannot reset. Local code is write-protected by repo config' ).
    ENDIF.

    lv_answer = lcl_popups=>popup_to_confirm(
      titlebar              = 'Warning'
      text_question         = 'Reset local objects?'
      text_button_1         = 'Ok'
      icon_button_1         = 'ICON_OKAY'
      text_button_2         = 'Cancel'
      icon_button_2         = 'ICON_CANCEL'
      default_button        = '2'
      display_cancel_button = abap_false ).                 "#EC NOTEXT

    IF lv_answer = '2'.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    lt_unnecessary_local_objs = lo_repo->get_unnecessary_local_objs( ).

    IF lines( lt_unnecessary_local_objs ) > 0.

      lv_answer = lcl_popups=>popup_to_confirm(
        titlebar              = 'Warning'
        text_question         = |Delete { lines( lt_unnecessary_local_objs ) } unnecessary local objects?|
        text_button_1         = 'Yes'
        icon_button_1         = 'ICON_OKAY'
        text_button_2         = 'No'
        icon_button_2         = 'ICON_CANCEL'
        default_button        = '2'
        display_cancel_button = abap_false ).               "#EC NOTEXT

      IF lv_answer = '1'.
        lo_repo->delete_unnecessary_local_objs( ).
      ENDIF.

    ENDIF.

    lo_repo->deserialize( ).

  ENDMETHOD.

  METHOD create_branch.

    DATA: lv_name   TYPE string,
          lv_cancel TYPE abap_bool,
          lo_repo   TYPE REF TO lcl_repo_online.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    lcl_popups=>create_branch_popup(
      IMPORTING
        ev_name   = lv_name
        ev_cancel = lv_cancel ).
    IF lv_cancel = abap_true.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    ASSERT lv_name CP 'refs/heads/+*'.

    lcl_git_porcelain=>create_branch(
      io_repo = lo_repo
      iv_name = lv_name
      iv_from = lo_repo->get_sha1_local( ) ).

    " automatically switch to new branch
    lo_repo->set_branch_name( lv_name ).

    MESSAGE 'Switched to new branch' TYPE 'S' ##NO_TEXT.

  ENDMETHOD.

  METHOD pull.

    DATA: lo_repo TYPE REF TO lcl_repo_online.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    IF lo_repo->is_write_protected( ) = abap_true.
      lcx_exception=>raise( 'Cannot pull. Local code is write-protected by repo config' ).
    ENDIF.

    lo_repo->refresh( ).
    lo_repo->deserialize( ).

    COMMIT WORK.

  ENDMETHOD.                    "pull

  METHOD switch_branch.

    DATA: lo_repo   TYPE REF TO lcl_repo_online,
          ls_branch TYPE lcl_git_branch_list=>ty_git_branch.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    ls_branch = lcl_popups=>branch_list_popup(
      iv_url             = lo_repo->get_url( )
      iv_default_branch  = lo_repo->get_branch_name( )
      iv_show_new_option = abap_true ).
    IF ls_branch IS INITIAL.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    IF ls_branch-name = lcl_popups=>c_new_branch_label.
      create_branch( iv_key ).
      RETURN.
    ENDIF.

    lo_repo->set_branch_name( ls_branch-name ).

    COMMIT WORK.

    lo_repo->deserialize( ).

  ENDMETHOD.  "switch_branch

  METHOD delete_branch.

    DATA: lo_repo   TYPE REF TO lcl_repo_online,
          ls_branch TYPE lcl_git_branch_list=>ty_git_branch.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    ls_branch = lcl_popups=>branch_list_popup( lo_repo->get_url( ) ).
    IF ls_branch IS INITIAL.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    IF ls_branch-name = 'HEAD'.
      lcx_exception=>raise( 'Cannot delete HEAD' ).
    ELSEIF ls_branch-name = lo_repo->get_branch_name( ).
      lcx_exception=>raise( 'Switch branch before deleting current' ).
    ENDIF.

    lcl_git_porcelain=>delete_branch(
      io_repo   = lo_repo
      is_branch = ls_branch ).

    MESSAGE 'Branch deleted' TYPE 'S'.

  ENDMETHOD.  "delete_branch

  METHOD commit.

    DATA: ls_comment TYPE lif_defs=>ty_comment,
          lo_user    TYPE REF TO lcl_persistence_user.

    lo_user = lcl_app=>user( ).
    lo_user->set_repo_git_user_name( iv_url      = io_repo->get_url( )
                                     iv_username = is_commit-committer_name ).
    lo_user->set_repo_git_user_email( iv_url     = io_repo->get_url( )
                                      iv_email   = is_commit-committer_email ).

    IF is_commit-committer_name IS INITIAL.
      lcx_exception=>raise( 'Commit: Committer name empty' ).
    ELSEIF is_commit-committer_email IS INITIAL.
      lcx_exception=>raise( 'Commit: Committer email empty' ).
    ELSEIF is_commit-author_email IS NOT INITIAL AND is_commit-author_name IS INITIAL.
      lcx_exception=>raise( 'Commit: Author email empty' ). " Opposite should be OK ?
    ELSEIF is_commit-comment IS INITIAL.
      lcx_exception=>raise( 'Commit: empty comment' ).
    ENDIF.

    ls_comment-committer-name  = is_commit-committer_name.
    ls_comment-committer-email = is_commit-committer_email.
    ls_comment-author-name     = is_commit-author_name.
    ls_comment-author-email    = is_commit-author_email.
    ls_comment-comment         = is_commit-comment.

    IF NOT is_commit-body IS INITIAL.
      CONCATENATE ls_comment-comment '' is_commit-body
        INTO ls_comment-comment SEPARATED BY lif_defs=>gc_newline.
    ENDIF.

    io_repo->push( is_comment = ls_comment
                   io_stage   = io_stage ).

    COMMIT WORK.

  ENDMETHOD.  "commit

ENDCLASS. " lcl_services_git

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_SERVICES_GIT
*&---------------------------------------------------------------------*

CLASS lcl_services_git DEFINITION FINAL.
  PUBLIC SECTION.

    TYPES: BEGIN OF ty_commit_fields,
             repo_key        TYPE lcl_persistence_repo=>ty_repo-key,
             committer_name  TYPE string,
             committer_email TYPE string,
             author_name     TYPE string,
             author_email    TYPE string,
             comment         TYPE string,
             body            TYPE string,
           END OF ty_commit_fields.

    CLASS-METHODS pull
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS reset
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS create_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS switch_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS delete_branch
      IMPORTING iv_key TYPE lcl_persistence_repo=>ty_repo-key
      RAISING   lcx_exception lcx_cancel.

    CLASS-METHODS commit
      IMPORTING io_repo   TYPE REF TO lcl_repo_online
                is_commit TYPE ty_commit_fields
                io_stage  TYPE REF TO lcl_stage
      RAISING   lcx_exception lcx_cancel.

ENDCLASS. " lcl_services_git

CLASS lcl_services_git IMPLEMENTATION.

  METHOD reset.

    DATA: lo_repo                   TYPE REF TO lcl_repo_online,
          lv_answer                 TYPE c LENGTH 1,
          lt_unnecessary_local_objs TYPE lif_defs=>ty_tadir_tt.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    IF lo_repo->is_write_protected( ) = abap_true.
      lcx_exception=>raise( 'Cannot reset. Local code is write-protected by repo config' ).
    ENDIF.

    lv_answer = lcl_popups=>popup_to_confirm(
      titlebar              = 'Warning'
      text_question         = 'Reset local objects?'
      text_button_1         = 'Ok'
      icon_button_1         = 'ICON_OKAY'
      text_button_2         = 'Cancel'
      icon_button_2         = 'ICON_CANCEL'
      default_button        = '2'
      display_cancel_button = abap_false ).                 "#EC NOTEXT

    IF lv_answer = '2'.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    lt_unnecessary_local_objs = lo_repo->get_unnecessary_local_objs( ).

    IF lines( lt_unnecessary_local_objs ) > 0.

      lv_answer = lcl_popups=>popup_to_confirm(
        titlebar              = 'Question'
        text_question         = |Delete { lines( lt_unnecessary_local_objs ) } unnecessary local objects?|
        text_button_1         = 'Yes'
        icon_button_1         = 'ICON_OKAY'
        text_button_2         = 'No'
        icon_button_2         = 'ICON_CANCEL'
        default_button        = '2'
        display_cancel_button = abap_false ).               "#EC NOTEXT

      IF lv_answer = '1'.
        lo_repo->delete_unnecessary_local_objs( ).
      ENDIF.

    ENDIF.

    lo_repo->deserialize( ).

  ENDMETHOD.

  METHOD create_branch.

    DATA: lv_name   TYPE string,
          lv_cancel TYPE abap_bool,
          lo_repo   TYPE REF TO lcl_repo_online.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    lcl_popups=>create_branch_popup(
      IMPORTING
        ev_name   = lv_name
        ev_cancel = lv_cancel ).
    IF lv_cancel = abap_true.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    ASSERT lv_name CP 'refs/heads/+*'.

    lcl_git_porcelain=>create_branch(
      io_repo = lo_repo
      iv_name = lv_name
      iv_from = lo_repo->get_sha1_local( ) ).

    " automatically switch to new branch
    lo_repo->set_branch_name( lv_name ).

    MESSAGE 'Switched to new branch' TYPE 'S' ##NO_TEXT.

  ENDMETHOD.

  METHOD pull.

    DATA: lo_repo TYPE REF TO lcl_repo_online.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    IF lo_repo->is_write_protected( ) = abap_true.
      lcx_exception=>raise( 'Cannot pull. Local code is write-protected by repo config' ).
    ENDIF.

    lo_repo->refresh( ).
    lo_repo->deserialize( ).

    COMMIT WORK.

  ENDMETHOD.                    "pull

  METHOD switch_branch.

    DATA: lo_repo   TYPE REF TO lcl_repo_online,
          ls_branch TYPE lcl_git_branch_list=>ty_git_branch.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    ls_branch = lcl_popups=>branch_list_popup(
      iv_url             = lo_repo->get_url( )
      iv_default_branch  = lo_repo->get_branch_name( )
      iv_show_new_option = abap_true ).
    IF ls_branch IS INITIAL.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    IF ls_branch-name = lcl_popups=>c_new_branch_label.
      create_branch( iv_key ).
      RETURN.
    ENDIF.

    lo_repo->set_branch_name( ls_branch-name ).

    COMMIT WORK.

    lo_repo->deserialize( ).

  ENDMETHOD.  "switch_branch

  METHOD delete_branch.

    DATA: lo_repo   TYPE REF TO lcl_repo_online,
          ls_branch TYPE lcl_git_branch_list=>ty_git_branch.

    lo_repo ?= lcl_app=>repo_srv( )->get( iv_key ).

    ls_branch = lcl_popups=>branch_list_popup( lo_repo->get_url( ) ).
    IF ls_branch IS INITIAL.
      RAISE EXCEPTION TYPE lcx_cancel.
    ENDIF.

    IF ls_branch-name = 'HEAD'.
      lcx_exception=>raise( 'Cannot delete HEAD' ).
    ELSEIF ls_branch-name = lo_repo->get_branch_name( ).
      lcx_exception=>raise( 'Switch branch before deleting current' ).
    ENDIF.

    lcl_git_porcelain=>delete_branch(
      io_repo   = lo_repo
      is_branch = ls_branch ).

    MESSAGE 'Branch deleted' TYPE 'S'.

  ENDMETHOD.  "delete_branch

  METHOD commit.

    DATA: ls_comment TYPE lif_defs=>ty_comment,
          lo_user    TYPE REF TO lcl_persistence_user.

    lo_user = lcl_app=>user( ).
    lo_user->set_repo_git_user_name( iv_url      = io_repo->get_url( )
                                     iv_username = is_commit-committer_name ).
    lo_user->set_repo_git_user_email( iv_url     = io_repo->get_url( )
                                      iv_email   = is_commit-committer_email ).

    IF is_commit-committer_name IS INITIAL.
      lcx_exception=>raise( 'Commit: Committer name empty' ).
    ELSEIF is_commit-committer_email IS INITIAL.
      lcx_exception=>raise( 'Commit: Committer email empty' ).
    ELSEIF is_commit-author_email IS NOT INITIAL AND is_commit-author_name IS INITIAL.
      lcx_exception=>raise( 'Commit: Author email empty' ). " Opposite should be OK ?
    ELSEIF is_commit-comment IS INITIAL.
      lcx_exception=>raise( 'Commit: empty comment' ).
    ENDIF.

    ls_comment-committer-name  = is_commit-committer_name.
    ls_comment-committer-email = is_commit-committer_email.
    ls_comment-author-name     = is_commit-author_name.
    ls_comment-author-email    = is_commit-author_email.
    ls_comment-comment         = is_commit-comment.

    IF NOT is_commit-body IS INITIAL.
      CONCATENATE ls_comment-comment '' is_commit-body
        INTO ls_comment-comment SEPARATED BY lif_defs=>gc_newline.
    ENDIF.

    io_repo->push( is_comment = ls_comment
                   io_stage   = io_stage ).

    COMMIT WORK.

  ENDMETHOD.  "commit

ENDCLASS. " lcl_services_git

change popup title

change popup title