diff --git a/src/zabapgit_gui_pages.prog.abap b/src/zabapgit_gui_pages.prog.abap index 46343076e..255a32c09 100644 --- a/src/zabapgit_gui_pages.prog.abap +++ b/src/zabapgit_gui_pages.prog.abap @@ -4,8 +4,17 @@ * All UI pages -INCLUDE zabapgit_html_action_utils. +* Super class INCLUDE zabapgit_page. + +* Utils and helpers +INCLUDE zabapgit_html_action_utils. +INCLUDE zabapgit_repo_browser_util. + +* Components and templates +INCLUDE zabapgit_view_repo. + +* Pages INCLUDE zabapgit_page_commit. INCLUDE zabapgit_page_merge. INCLUDE zabapgit_page_background. diff --git a/src/zabapgit_objects.prog.abap b/src/zabapgit_objects.prog.abap index d3e465352..844716d85 100644 --- a/src/zabapgit_objects.prog.abap +++ b/src/zabapgit_objects.prog.abap @@ -1427,7 +1427,9 @@ CLASS lcl_objects_program IMPLEMENTATION. WHERE progname = iv_program AND r3state = 'A'. - _object_check_timestamp lv_date lv_time. + IF sy-subrc = 0. " Text not found ? Assuming no changes, see #404 + _object_check_timestamp lv_date lv_time. + ENDIF. IF iv_skip_gui = abap_true. RETURN. diff --git a/src/zabapgit_page_main.prog.abap b/src/zabapgit_page_main.prog.abap index 66a1241d7..7d2c04b0b 100644 --- a/src/zabapgit_page_main.prog.abap +++ b/src/zabapgit_page_main.prog.abap @@ -2,8 +2,6 @@ *& Include ZABAPGIT_PAGE_MAIN *&---------------------------------------------------------------------* -INCLUDE zabapgit_view_repo. - CLASS lcl_gui_page_main DEFINITION FINAL INHERITING FROM lcl_gui_page_super. PUBLIC SECTION. diff --git a/src/zabapgit_repo_browser_util.prog.abap b/src/zabapgit_repo_browser_util.prog.abap new file mode 100644 index 000000000..cfee28bed --- /dev/null +++ b/src/zabapgit_repo_browser_util.prog.abap @@ -0,0 +1,243 @@ +*&---------------------------------------------------------------------* +*& Include ZABAPGIT_REPO_BROWSER_UTIL +*&---------------------------------------------------------------------* + +CLASS lcl_repo_content_browser DEFINITION FINAL. + + PUBLIC SECTION. + + CONSTANTS: BEGIN OF c_sortkey, + default TYPE i VALUE 9999, + parent_dir TYPE i VALUE 0, + dir TYPE i VALUE 1, + orphan TYPE i VALUE 2, + changed TYPE i VALUE 3, + END OF c_sortkey. + + TYPES: BEGIN OF ty_repo_item, + obj_type TYPE tadir-object, + obj_name TYPE tadir-obj_name, + sortkey TYPE i, + path TYPE string, + is_dir TYPE abap_bool, + changes TYPE i, + lstate TYPE char1, + rstate TYPE char1, + files TYPE tt_repo_files, + END OF ty_repo_item. + TYPES tt_repo_items TYPE STANDARD TABLE OF ty_repo_item WITH DEFAULT KEY. + + METHODS constructor + IMPORTING io_repo TYPE REF TO lcl_repo. + + METHODS list + IMPORTING iv_path TYPE string + iv_by_folders TYPE abap_bool + iv_changes_only TYPE abap_bool + RETURNING VALUE(rt_repo_items) TYPE tt_repo_items + RAISING lcx_exception. + + METHODS get_log + RETURNING VALUE(ro_log) TYPE REF TO lcl_log. + + PRIVATE SECTION. + DATA: mo_repo TYPE REF TO lcl_repo, + mo_log TYPE REF TO lcl_log. + + METHODS build_repo_items_offline + RETURNING VALUE(rt_repo_items) TYPE tt_repo_items + RAISING lcx_exception. + + METHODS build_repo_items_online + RETURNING VALUE(rt_repo_items) TYPE tt_repo_items + RAISING lcx_exception. + + METHODS build_folders + IMPORTING iv_cur_dir TYPE string + CHANGING ct_repo_items TYPE tt_repo_items + RAISING lcx_exception. + + METHODS filter_changes + CHANGING ct_repo_items TYPE tt_repo_items. + +ENDCLASS. "lcl_repo_content_browser + +DEFINE _reduce_state. + " &1 - prev, &2 - cur + IF &1 = &2 OR &2 IS INITIAL. + ASSERT 1 = 1. " No change + ELSEIF &1 IS INITIAL. + &1 = &2. + ELSE. + &1 = gc_state-mixed. + ENDIF. +END-OF-DEFINITION. + +CLASS lcl_repo_content_browser IMPLEMENTATION. + + METHOD constructor. + mo_repo = io_repo. + CREATE OBJECT mo_log. + ENDMETHOD. "constructor + + METHOD get_log. + ro_log = mo_log. + ENDMETHOD. "get_log + + METHOD list. + + mo_log->clear( ). + + IF mo_repo->is_offline( ) = abap_true. + rt_repo_items = build_repo_items_offline( ). + ELSE. + rt_repo_items = build_repo_items_online( ). + ENDIF. + + IF iv_by_folders = abap_true. + build_folders( + EXPORTING iv_cur_dir = iv_path + CHANGING ct_repo_items = rt_repo_items ). + ENDIF. + + IF iv_changes_only = abap_true. + filter_changes( CHANGING ct_repo_items = rt_repo_items ). + ENDIF. + + SORT rt_repo_items BY + sortkey ASCENDING + obj_type ASCENDING + obj_name ASCENDING. + + ENDMETHOD. "list + + METHOD build_folders. + + DATA: lv_index TYPE i, + lt_subitems LIKE ct_repo_items, + ls_subitem LIKE LINE OF ct_repo_items, + ls_folder LIKE LINE OF ct_repo_items. + + FIELD-SYMBOLS LIKE LINE OF ct_repo_items. + + LOOP AT ct_repo_items ASSIGNING . + lv_index = sy-tabix. + CHECK -path <> iv_cur_dir. " files in target dir - just leave them be + + IF lcl_path=>is_subdir( iv_path = -path iv_parent = iv_cur_dir ) = abap_true. + ls_subitem-changes = -changes. + ls_subitem-path = -path. + ls_subitem-lstate = -lstate. + ls_subitem-rstate = -rstate. + APPEND ls_subitem TO lt_subitems. + ENDIF. + + DELETE ct_repo_items INDEX lv_index. + ENDLOOP. + + SORT lt_subitems BY path ASCENDING. + + LOOP AT lt_subitems ASSIGNING . + AT NEW path. + CLEAR ls_folder. + ls_folder-path = -path. + ls_folder-sortkey = c_sortkey-dir. " Directory + ls_folder-is_dir = abap_true. + ENDAT. + + ls_folder-changes = ls_folder-changes + -changes. + _reduce_state ls_folder-lstate -lstate. + _reduce_state ls_folder-rstate -rstate. + + AT END OF path. + APPEND ls_folder TO ct_repo_items. + ENDAT. + ENDLOOP. + + ENDMETHOD. "build_folders + + METHOD filter_changes. + + DATA lt_repo_temp LIKE ct_repo_items. + + FIELD-SYMBOLS LIKE LINE OF ct_repo_items. + + LOOP AT ct_repo_items ASSIGNING . + CHECK -changes > 0. + APPEND TO lt_repo_temp. + ENDLOOP. + + IF lines( lt_repo_temp ) > 0. " Prevent showing empty package if no changes, show all + ct_repo_items = lt_repo_temp. + ENDIF. + + ENDMETHOD. "filter_changes + + METHOD build_repo_items_offline. + + DATA: lt_tadir TYPE ty_tadir_tt. + + FIELD-SYMBOLS: LIKE LINE OF rt_repo_items, + LIKE LINE OF lt_tadir. + + + lt_tadir = lcl_tadir=>read( mo_repo->get_package( ) ). + LOOP AT lt_tadir ASSIGNING . + APPEND INITIAL LINE TO rt_repo_items ASSIGNING . + -obj_type = -object. + -obj_name = -obj_name. + -path = '/' && -path. " Add root anchor + -sortkey = c_sortkey-default. " Default sort key + ENDLOOP. + + ENDMETHOD. "build_repo_items_offline + + METHOD build_repo_items_online. + + DATA: lo_repo_online TYPE REF TO lcl_repo_online, + ls_file TYPE ty_repo_file, + lt_status TYPE ty_results_tt. + + FIELD-SYMBOLS: LIKE LINE OF lt_status, + LIKE LINE OF rt_repo_items. + + + lo_repo_online ?= mo_repo. + lt_status = lo_repo_online->status( mo_log ). + + LOOP AT lt_status ASSIGNING . + AT NEW obj_name. "obj_type + obj_name + APPEND INITIAL LINE TO rt_repo_items ASSIGNING . + -obj_type = -obj_type. + -obj_name = -obj_name. + -sortkey = c_sortkey-default. " Default sort key + -changes = 0. + -path = -path. + ENDAT. + + IF -filename IS NOT INITIAL. + ls_file-path = -path. + ls_file-filename = -filename. + ls_file-is_changed = boolc( -match = abap_false ). " TODO refactor + ls_file-rstate = -rstate. + ls_file-lstate = -lstate. + APPEND ls_file TO -files. + + IF ls_file-is_changed = abap_true. + -sortkey = c_sortkey-changed. " Changed files + -changes = -changes + 1. + _reduce_state -lstate ls_file-lstate. + _reduce_state -rstate ls_file-rstate. + ENDIF. + ENDIF. + + AT END OF obj_name. "obj_type + obj_name + IF -obj_type IS INITIAL. + -sortkey = c_sortkey-orphan. "Virtual objects + ENDIF. + ENDAT. + ENDLOOP. + + ENDMETHOD. "build_repo_items_online + +ENDCLASS. "lcl_repo_content_browser \ No newline at end of file diff --git a/src/zabapgit_repo_browser_util.prog.xml b/src/zabapgit_repo_browser_util.prog.xml new file mode 100644 index 000000000..53f8f567b --- /dev/null +++ b/src/zabapgit_repo_browser_util.prog.xml @@ -0,0 +1,48 @@ + + + + + + ZABAPGIT_REPO_BROWSER_UTIL + A + + + X + + + + + + I + + + + 0000-00-00 + + 0000-00-00 + + + + + E + + + 0000-00-00 + + 0000-00-00 + + + X + + + + R + + Include ZABAPGIT_REPO_BROWSER_UTIL + 34 + + + + + + diff --git a/src/zabapgit_sap_package.prog.abap b/src/zabapgit_sap_package.prog.abap index 603307ee4..2600c9c24 100644 --- a/src/zabapgit_sap_package.prog.abap +++ b/src/zabapgit_sap_package.prog.abap @@ -98,7 +98,11 @@ CLASS lcl_sap_package IMPLEMENTATION. METHOD check. - DATA: lv_path TYPE string. + DATA: lv_path TYPE string, + ls_item TYPE ty_item, + ls_file TYPE ty_file_signature, + lt_res_sort LIKE it_results, + lt_item_idx LIKE it_results. FIELD-SYMBOLS: LIKE LINE OF it_results, LIKE LINE OF it_results. @@ -108,22 +112,37 @@ CLASS lcl_sap_package IMPLEMENTATION. RETURN. ENDIF. -* check files for one object is in the same folder - LOOP AT it_results ASSIGNING - WHERE NOT obj_type IS INITIAL. - LOOP AT it_results ASSIGNING - WHERE obj_type = -obj_type - AND obj_name = -obj_name - AND path <> -path. + " Collect object indexe + lt_res_sort = it_results. + SORT lt_res_sort BY obj_type ASCENDING obj_name ASCENDING. + + LOOP AT it_results ASSIGNING WHERE NOT obj_type IS INITIAL. + IF NOT ( -obj_type = ls_item-obj_type AND -obj_name = ls_item-obj_name ). + APPEND INITIAL LINE TO lt_item_idx ASSIGNING . + -obj_type = -obj_type. + -obj_name = -obj_name. + -path = -path. + MOVE-CORRESPONDING TO ls_item. + ENDIF. + ENDLOOP. + + " Check files for one object is in the same folder + + LOOP AT it_results ASSIGNING WHERE NOT obj_type IS INITIAL. + READ TABLE lt_item_idx ASSIGNING + WITH KEY obj_type = -obj_type obj_name = -obj_name + BINARY SEARCH. " Sorted above + + IF sy-subrc <> 0 OR -path <> -path. " All paths are same io_log->add( iv_msgv1 = 'Files for object' iv_msgv2 = -obj_type iv_msgv3 = -obj_name - iv_msgv4 = 'are not placed in the same folder' ) ##no_text. - EXIT. - ENDLOOP. + iv_msgv4 = 'are not placed in the same folder' + iv_rc = '1' ) ##no_text. + ENDIF. ENDLOOP. -* check that objects are created in package corresponding to folder + " Check that objects are created in package corresponding to folder LOOP AT it_results ASSIGNING WHERE NOT package IS INITIAL AND NOT path IS INITIAL. lv_path = class_to_path( iv_top = iv_top @@ -132,20 +151,29 @@ CLASS lcl_sap_package IMPLEMENTATION. IF lv_path <> -path. io_log->add( iv_msgv1 = 'Package and path does not match for object,' iv_msgv2 = -obj_type - iv_msgv3 = -obj_name ) ##no_text. + iv_msgv3 = -obj_name + iv_rc = '2' ) ##no_text. ENDIF. ENDLOOP. -* check for multiple files with same filename - LOOP AT it_results ASSIGNING - WHERE NOT filename IS INITIAL. - LOOP AT it_results ASSIGNING - WHERE filename = -filename - AND path <> -path. + " Check for multiple files with same filename + SORT lt_res_sort BY filename ASCENDING. + + LOOP AT lt_res_sort ASSIGNING . + IF -filename IS NOT INITIAL AND -filename = ls_file-filename. io_log->add( iv_msgv1 = 'Multiple files with same filename,' - iv_msgv2 = -filename ) ##no_text. - EXIT. - ENDLOOP. + iv_msgv2 = -filename + iv_rc = '3' ) ##no_text. + ENDIF. + + IF -filename IS INITIAL. + io_log->add( iv_msgv1 = 'Filename is empty for object' + iv_msgv2 = -obj_type + iv_msgv3 = -obj_name + iv_rc = '4' ) ##no_text. + ENDIF. + + MOVE-CORRESPONDING TO ls_file. ENDLOOP. ENDMETHOD. "check diff --git a/src/zabapgit_unit_test.prog.abap b/src/zabapgit_unit_test.prog.abap index 21eb041bc..054dec114 100644 --- a/src/zabapgit_unit_test.prog.abap +++ b/src/zabapgit_unit_test.prog.abap @@ -2,6 +2,42 @@ *& Include ZABAPGIT_UNIT_TEST *&---------------------------------------------------------------------* +DEFINE _append_local. + APPEND INITIAL LINE TO lt_local ASSIGNING . + -item-obj_type = &1. + -item-obj_name = &2. + -item-devclass = '$Z$'. + -file-path = '/'. + -file-filename = &3. + -file-sha1 = &4. +END-OF-DEFINITION. + +DEFINE _append_remote. + APPEND INITIAL LINE TO lt_remote ASSIGNING . + -path = '/'. + -filename = &1. + -sha1 = &2. +END-OF-DEFINITION. + +DEFINE _append_state. + APPEND INITIAL LINE TO lt_state ASSIGNING . + -path = '/'. + -filename = &1. + -sha1 = &2. +END-OF-DEFINITION. + +DEFINE _append_result. + APPEND INITIAL LINE TO lt_results ASSIGNING . + -obj_type = &1. + -obj_name = &2. + -match = &3. + -lstate = &4. + -rstate = &5. + -package = &6. + -path = &7. + -filename = &8. +END-OF-DEFINITION. + * todo, should the tests be in the same include as the classes * they are testing? @@ -1758,42 +1794,6 @@ ENDCLASS. "ltcl_file_status CLASS ltcl_file_status IMPLEMENTATION. - DEFINE _append_local. - APPEND INITIAL LINE TO lt_local ASSIGNING . - -item-obj_type = &1. - -item-obj_name = &2. - -item-devclass = '$Z$'. - -file-path = '/'. - -file-filename = &3. - -file-sha1 = &4. - END-OF-DEFINITION. - - DEFINE _append_remote. - APPEND INITIAL LINE TO lt_remote ASSIGNING . - -path = '/'. - -filename = &1. - -sha1 = &2. - END-OF-DEFINITION. - - DEFINE _append_state. - APPEND INITIAL LINE TO lt_state ASSIGNING . - -path = '/'. - -filename = &1. - -sha1 = &2. - END-OF-DEFINITION. - - DEFINE _append_result. - APPEND INITIAL LINE TO lt_results_exp ASSIGNING . - -obj_type = &1. - -obj_name = &2. - -match = &3. - -lstate = &4. - -rstate = &5. - -package = &6. - -filename = &7. - -path = '/'. - END-OF-DEFINITION. - METHOD calculate_status. DATA: lt_local TYPE ty_files_item_tt, @@ -1853,24 +1853,25 @@ CLASS ltcl_file_status IMPLEMENTATION. _append_remote 'xfeld.doma.xml' 'XFELD'. " Object from different package _append_remote 'num01.doma.xml' 'NUM01_CHANGED'. " Changed object from different package - "EXP RESULT TYPE NAME MATCH LST RST PKG FILE - _append_result '' '' ' ' ' ' 'A' '' 'textfile.txt'. - _append_result 'CLAS' 'ZCLASS1' ' ' ' ' 'A' '$Z$' 'zclass1.clas.abap'. - _append_result 'CLAS' 'ZCLASS1' ' ' 'A' ' ' '$Z$' 'zclass1.clas.testclasses.abap'. - _append_result 'CLAS' 'ZCLASS1' 'X' ' ' ' ' '$Z$' 'zclass1.clas.xml'. - _append_result 'CLAS' 'ZCLASS2' ' ' ' ' 'A' '' 'zclass2.clas.abap'. - _append_result 'CLAS' 'ZCLASS2' ' ' ' ' 'A' '' 'zclass2.clas.xml'. - _append_result 'DOMA' 'NUM01' ' ' ' ' 'M' 'SUTI' 'num01.doma.xml'. - _append_result 'DOMA' 'XFELD' 'X' ' ' ' ' 'SUTI' 'xfeld.doma.xml'. - _append_result 'DOMA' 'ZDOMA1' 'X' ' ' ' ' '$Z$' 'zdoma1.doma.xml'. - _append_result 'DOMA' 'ZDOMA2' ' ' 'M' ' ' '$Z$' 'zdoma2.doma.xml'. - _append_result 'DOMA' 'ZDOMA3' ' ' ' ' 'M' '$Z$' 'zdoma3.doma.xml'. - _append_result 'DOMA' 'ZDOMA4' ' ' 'A' ' ' '$Z$' 'zdoma4.doma.xml'. - _append_result 'DOMA' 'ZDOMA5' ' ' ' ' 'A' '' 'zdoma5.doma.xml'. - _append_result 'DOMA' 'ZDOMA6' ' ' 'M' 'M' '$Z$' 'zdoma6.doma.xml'. - _append_result 'DOMA' 'ZDOMA7' 'X' ' ' ' ' '$Z$' 'zdoma7.doma.xml'. - _append_result 'DOMA' 'ZDOMA8' ' ' 'M' 'M' '$Z$' 'zdoma8.doma.xml'. - _append_result 'DOMA' 'ZDOMA9' ' ' 'D' ' ' '' 'zdoma9.doma.xml'. + "EXP RESULT TYPE NAME MATCH LST RST PKG PATH FILE + _append_result '' '' ' ' ' ' 'A' '' '/' 'textfile.txt'. + _append_result 'CLAS' 'ZCLASS1' ' ' ' ' 'A' '$Z$' '/' 'zclass1.clas.abap'. + _append_result 'CLAS' 'ZCLASS1' ' ' 'A' ' ' '$Z$' '/' 'zclass1.clas.testclasses.abap'. + _append_result 'CLAS' 'ZCLASS1' 'X' ' ' ' ' '$Z$' '/' 'zclass1.clas.xml'. + _append_result 'CLAS' 'ZCLASS2' ' ' ' ' 'A' '' '/' 'zclass2.clas.abap'. + _append_result 'CLAS' 'ZCLASS2' ' ' ' ' 'A' '' '/' 'zclass2.clas.xml'. + _append_result 'DOMA' 'NUM01' ' ' ' ' 'M' 'SUTI' '/' 'num01.doma.xml'. + _append_result 'DOMA' 'XFELD' 'X' ' ' ' ' 'SUTI' '/' 'xfeld.doma.xml'. + _append_result 'DOMA' 'ZDOMA1' 'X' ' ' ' ' '$Z$' '/' 'zdoma1.doma.xml'. + _append_result 'DOMA' 'ZDOMA2' ' ' 'M' ' ' '$Z$' '/' 'zdoma2.doma.xml'. + _append_result 'DOMA' 'ZDOMA3' ' ' ' ' 'M' '$Z$' '/' 'zdoma3.doma.xml'. + _append_result 'DOMA' 'ZDOMA4' ' ' 'A' ' ' '$Z$' '/' 'zdoma4.doma.xml'. + _append_result 'DOMA' 'ZDOMA5' ' ' ' ' 'A' '' '/' 'zdoma5.doma.xml'. + _append_result 'DOMA' 'ZDOMA6' ' ' 'M' 'M' '$Z$' '/' 'zdoma6.doma.xml'. + _append_result 'DOMA' 'ZDOMA7' 'X' ' ' ' ' '$Z$' '/' 'zdoma7.doma.xml'. + _append_result 'DOMA' 'ZDOMA8' ' ' 'M' 'M' '$Z$' '/' 'zdoma8.doma.xml'. + _append_result 'DOMA' 'ZDOMA9' ' ' 'D' ' ' '' '/' 'zdoma9.doma.xml'. + lt_results_exp = lt_results. lt_results = lcl_file_status=>calculate_status( it_local = lt_local @@ -1881,4 +1882,119 @@ CLASS ltcl_file_status IMPLEMENTATION. ENDMETHOD. "calculate_status -ENDCLASS. "ltcl_file_status \ No newline at end of file +ENDCLASS. "ltcl_file_status + +CLASS ltcl_sap_package DEFINITION + FOR TESTING RISK LEVEL HARMLESS DURATION SHORT FINAL + INHERITING FROM CL_AUNIT_ASSERT. + + PUBLIC SECTION. + METHODS check FOR TESTING. + +ENDCLASS. "ltcl_sap_package + +CLASS ltcl_sap_package IMPLEMENTATION. + + METHOD check. + + DATA: lt_results TYPE ty_results_tt, + lo_log TYPE REF TO lcl_log. + + FIELD-SYMBOLS: LIKE LINE OF lt_results. + +*** 0 Positive + + CLEAR lt_results. + CREATE OBJECT lo_log. + "EXP RESULT TYPE NAME MATCH LST RST PKG PATH FILE + _append_result 'CLAS' 'ZCLASS1' ' ' ' ' 'A' '$Z$' '/' 'zclass1.clas.abap'. + _append_result 'CLAS' 'ZCLASS1' 'X' ' ' ' ' '$Z$' '/' 'zclass1.clas.xml'. + _append_result 'DOMA' 'ZDOMA1' 'X' ' ' ' ' '$Z$' '/' 'zdoma1.doma.xml'. + _append_result 'DOMA' 'ZDOMA2' ' ' 'M' ' ' '$Z$' '/' 'zdoma2.doma.xml'. + + lcl_sap_package=>check( io_log = lo_log + it_results = lt_results + iv_start = '/' + iv_top = '$Z$' ). + + assert_equals( act = lo_log->count( ) exp = 0 ). + +*** 1 Negative, different path for same object + + CLEAR lt_results. + CREATE OBJECT lo_log. + + "EXP RESULT TYPE NAME MATCH LST RST PKG PATH FILE + _append_result 'CLAS' 'ZCLASS1' ' ' ' ' 'A' '$Z$' '/' 'zclass1.clas.abap'. + _append_result 'CLAS' 'ZCLASS1' 'X' ' ' ' ' '$Z$' '/sub' 'zclass1.clas.xml'. + _append_result 'DOMA' 'ZDOMA1' 'X' ' ' ' ' '$Z$' '/' 'zdoma1.doma.xml'. + _append_result 'DOMA' 'ZDOMA2' ' ' 'M' ' ' '$Z$' '/' 'zdoma2.doma.xml'. + + lcl_sap_package=>check( io_log = lo_log + it_results = lt_results + iv_start = '/' + iv_top = '$Z$' ). + + " This one is not pure - incorrect path also triggers path vs package check + assert_equals( act = lo_log->count( ) exp = 2 ). + assert_equals( act = lo_log->has_rc( '1' ) exp = abap_true ). + +*** 2 Negative, incorrect path vs package + + CLEAR lt_results. + CREATE OBJECT lo_log. + + "EXP RESULT TYPE NAME MATCH LST RST PKG PATH FILE + _append_result 'CLAS' 'ZCLASS1' ' ' ' ' 'A' '$Z$' '/' 'zclass1.clas.abap'. + _append_result 'CLAS' 'ZCLASS1' 'X' ' ' ' ' '$Z$' '/' 'zclass1.clas.xml'. + _append_result 'DOMA' 'ZDOMA1' 'X' ' ' ' ' '$Z$' '/sub' 'zdoma1.doma.xml'. + _append_result 'DOMA' 'ZDOMA2' ' ' 'M' ' ' '$Z$' '/' 'zdoma2.doma.xml'. + + lcl_sap_package=>check( io_log = lo_log + it_results = lt_results + iv_start = '/' + iv_top = '$Z$' ). + + assert_equals( act = lo_log->count( ) exp = 1 ). + assert_equals( act = lo_log->has_rc( '2' ) exp = abap_true ). + +*** 3 Negative, similar filenames + + CLEAR lt_results. + CREATE OBJECT lo_log. + + "EXP RESULT TYPE NAME MATCH LST RST PKG PATH FILE + _append_result 'CLAS' 'ZCLASS1' ' ' ' ' 'A' '$Z$' '/' 'zclass1.clas.abap'. + _append_result 'CLAS' 'ZCLASS1' 'X' ' ' ' ' '$Z$' '/' 'zclass1.clas.xml'. + _append_result 'DOMA' 'ZDOMA1' 'X' ' ' ' ' '$Z$' '/' 'zdoma1.doma.xml'. + _append_result 'DOMA' 'ZDOMA2' ' ' 'M' ' ' '$Z$' '/' 'zdoma1.doma.xml'. + + lcl_sap_package=>check( io_log = lo_log + it_results = lt_results + iv_start = '/' + iv_top = '$Z$' ). + + assert_equals( act = lo_log->count( ) exp = 1 ). + assert_equals( act = lo_log->has_rc( '3' ) exp = abap_true ). + +*** 4 Negative, empty filenames + + CLEAR lt_results. + CREATE OBJECT lo_log. + + "EXP RESULT TYPE NAME MATCH LST RST PKG PATH FILE + _append_result 'CLAS' 'ZCLASS1' ' ' ' ' 'A' '$Z$' '/' 'zclass1.clas.abap'. + _append_result 'CLAS' 'ZCLASS1' 'X' ' ' ' ' '$Z$' '/' 'zclass1.clas.xml'. + _append_result 'DOMA' 'ZDOMA1' 'X' ' ' ' ' '$Z$' '/' ''. + + lcl_sap_package=>check( io_log = lo_log + it_results = lt_results + iv_start = '/' + iv_top = '$Z$' ). + + assert_equals( act = lo_log->count( ) exp = 1 ). + assert_equals( act = lo_log->has_rc( '4' ) exp = abap_true ). + + ENDMETHOD. " check. + +ENDCLASS. "ltcl_sap_package \ No newline at end of file diff --git a/src/zabapgit_util.prog.abap b/src/zabapgit_util.prog.abap index a42aa0469..9d33a058e 100644 --- a/src/zabapgit_util.prog.abap +++ b/src/zabapgit_util.prog.abap @@ -1012,11 +1012,16 @@ CLASS lcl_log DEFINITION FINAL. iv_msgv1 TYPE csequence iv_msgv2 TYPE csequence OPTIONAL iv_msgv3 TYPE csequence OPTIONAL - iv_msgv4 TYPE csequence OPTIONAL, + iv_msgv4 TYPE csequence OPTIONAL + iv_rc TYPE balsort OPTIONAL, count RETURNING VALUE(rv_count) TYPE i, to_html RETURNING VALUE(ro_html) TYPE REF TO lcl_html_helper, + clear, + has_rc "For unit tests mainly + IMPORTING iv_rc TYPE balsort + RETURNING VALUE(rv_yes) TYPE abap_bool, show. PRIVATE SECTION. @@ -1056,13 +1061,14 @@ CLASS lcl_log IMPLEMENTATION. FIELD-SYMBOLS: LIKE LINE OF mt_log. APPEND INITIAL LINE TO mt_log ASSIGNING . - -msgty = 'W'. - -msgid = '00'. - -msgno = '001'. - -msgv1 = iv_msgv1. - -msgv2 = iv_msgv2. - -msgv3 = iv_msgv3. - -msgv4 = iv_msgv4. + -msgty = 'W'. + -msgid = '00'. + -msgno = '001'. + -msgv1 = iv_msgv1. + -msgv2 = iv_msgv2. + -msgv3 = iv_msgv3. + -msgv4 = iv_msgv4. + -alsort = iv_rc. " Error code for unit test, not sure about better field ENDMETHOD. @@ -1081,4 +1087,13 @@ CLASS lcl_log IMPLEMENTATION. rv_count = lines( mt_log ). ENDMETHOD. + METHOD clear. + CLEAR mt_log. + ENDMETHOD. " clear. + + METHOD has_rc. + READ TABLE mt_log WITH KEY alsort = iv_rc TRANSPORTING NO FIELDS. + rv_yes = boolc( sy-subrc = 0 ). + ENDMETHOD. "has_rc + ENDCLASS. \ No newline at end of file diff --git a/src/zabapgit_view_repo.prog.abap b/src/zabapgit_view_repo.prog.abap index e599565df..70d53ac4d 100644 --- a/src/zabapgit_view_repo.prog.abap +++ b/src/zabapgit_view_repo.prog.abap @@ -2,252 +2,6 @@ *& Include ZABAPGIT_VIEW_REPO *&---------------------------------------------------------------------* -CLASS lcl_repo_content_browser DEFINITION FINAL. - - PUBLIC SECTION. - - CONSTANTS: BEGIN OF c_sortkey, - default TYPE i VALUE 9999, - parent_dir TYPE i VALUE 0, - dir TYPE i VALUE 1, - orphan TYPE i VALUE 2, - changed TYPE i VALUE 3, - END OF c_sortkey. - - TYPES: BEGIN OF ty_repo_item, - obj_type TYPE tadir-object, - obj_name TYPE tadir-obj_name, - sortkey TYPE i, - path TYPE string, - is_dir TYPE abap_bool, - changes TYPE i, - lstate TYPE char1, - rstate TYPE char1, - files TYPE tt_repo_files, - END OF ty_repo_item. - TYPES tt_repo_items TYPE STANDARD TABLE OF ty_repo_item WITH DEFAULT KEY. - - METHODS constructor - IMPORTING io_repo TYPE REF TO lcl_repo. - - METHODS list - IMPORTING iv_path TYPE string - iv_by_folders TYPE abap_bool - iv_changes_only TYPE abap_bool - RETURNING VALUE(rt_repo_items) TYPE tt_repo_items - RAISING lcx_exception. - - METHODS get_log - RETURNING VALUE(ro_log) TYPE REF TO lcl_log. - - PRIVATE SECTION. - DATA: mo_repo TYPE REF TO lcl_repo, - mo_log TYPE REF TO lcl_log. - - METHODS get_local - RETURNING VALUE(rt_repo_items) TYPE tt_repo_items - RAISING lcx_exception. - - METHODS get_remote - RETURNING VALUE(rt_repo_items) TYPE tt_repo_items - RAISING lcx_exception. - - METHODS build_folders - IMPORTING iv_cur_dir TYPE string - CHANGING ct_repo_items TYPE tt_repo_items - RAISING lcx_exception. - - METHODS filter_changes - CHANGING ct_repo_items TYPE tt_repo_items. - -ENDCLASS. "lcl_repo_content_browser - -DEFINE _reduce_state. - " &1 - prev, &2 - cur - IF &1 = &2 OR &2 IS INITIAL. - ASSERT 1 = 1. " No change - ELSEIF &1 IS INITIAL. - &1 = &2. - ELSE. - &1 = gc_state-mixed. - ENDIF. -END-OF-DEFINITION. - -CLASS lcl_repo_content_browser IMPLEMENTATION. - - METHOD constructor. - mo_repo = io_repo. - ENDMETHOD. "constructor - - METHOD get_log. - ro_log = mo_log. - ENDMETHOD. "get_log - - METHOD list. - -* todo, create mo_log in constuctor instead? - CREATE OBJECT mo_log. - - IF mo_repo->is_offline( ) = abap_true. - rt_repo_items = get_local( ). - ELSE. - rt_repo_items = get_remote( ). - ENDIF. - - IF iv_by_folders = abap_true. - build_folders( - EXPORTING iv_cur_dir = iv_path - CHANGING ct_repo_items = rt_repo_items ). - ENDIF. - - IF iv_changes_only = abap_true. - filter_changes( CHANGING ct_repo_items = rt_repo_items ). - ENDIF. - - SORT rt_repo_items BY - sortkey ASCENDING - obj_type ASCENDING - obj_name ASCENDING. - - ENDMETHOD. "list - - METHOD build_folders. - - DATA: lv_index TYPE i, - lt_subitems LIKE ct_repo_items, - ls_subitem LIKE LINE OF ct_repo_items, - ls_folder LIKE LINE OF ct_repo_items. - - FIELD-SYMBOLS LIKE LINE OF ct_repo_items. - - LOOP AT ct_repo_items ASSIGNING . - lv_index = sy-tabix. - CHECK -path <> iv_cur_dir. " files in target dir - just leave them be - - IF lcl_path=>is_subdir( iv_path = -path iv_parent = iv_cur_dir ) = abap_true. - ls_subitem-changes = -changes. - ls_subitem-path = -path. - ls_subitem-lstate = -lstate. - ls_subitem-rstate = -rstate. - APPEND ls_subitem TO lt_subitems. - ENDIF. - - DELETE ct_repo_items INDEX lv_index. - ENDLOOP. - - SORT lt_subitems BY path ASCENDING. - - LOOP AT lt_subitems ASSIGNING . - AT NEW path. - CLEAR ls_folder. - ls_folder-path = -path. - ls_folder-sortkey = c_sortkey-dir. " Directory - ls_folder-is_dir = abap_true. - ENDAT. - - ls_folder-changes = ls_folder-changes + -changes. - _reduce_state ls_folder-lstate -lstate. - _reduce_state ls_folder-rstate -rstate. - - AT END OF path. - APPEND ls_folder TO ct_repo_items. - ENDAT. - ENDLOOP. - - ENDMETHOD. "build_folders - - METHOD filter_changes. - - DATA lt_repo_temp LIKE ct_repo_items. - - FIELD-SYMBOLS LIKE LINE OF ct_repo_items. - - LOOP AT ct_repo_items ASSIGNING . - CHECK -changes > 0. - APPEND TO lt_repo_temp. - ENDLOOP. - - IF lines( lt_repo_temp ) > 0. " Prevent showing empty package if no changes, show all - ct_repo_items = lt_repo_temp. - ENDIF. - - ENDMETHOD. "filter_changes - - METHOD get_local. -* todo, should this method be part of lcl_repo instead? - - DATA: lt_tadir TYPE ty_tadir_tt. - - FIELD-SYMBOLS: LIKE LINE OF rt_repo_items, - LIKE LINE OF lt_tadir. - - - lt_tadir = lcl_tadir=>read( mo_repo->get_package( ) ). - LOOP AT lt_tadir ASSIGNING . - APPEND INITIAL LINE TO rt_repo_items ASSIGNING . - -obj_type = -object. - -obj_name = -obj_name. - -path = '/' && -path. " Add root anchor - -sortkey = c_sortkey-default. " Default sort key - ENDLOOP. - - ENDMETHOD. "get_local - - METHOD get_remote. -* todo, name "get_remote" is misleading? it does a lot more than just fetching -* remote objects - - DATA: lo_repo_online TYPE REF TO lcl_repo_online, - ls_file TYPE ty_repo_file, - lt_status TYPE ty_results_tt. - - FIELD-SYMBOLS: LIKE LINE OF lt_status, - LIKE LINE OF rt_repo_items. - - - lo_repo_online ?= mo_repo. - lt_status = lo_repo_online->status( mo_log ). - - LOOP AT lt_status ASSIGNING . - AT NEW obj_name. "obj_type + obj_name - APPEND INITIAL LINE TO rt_repo_items ASSIGNING . - -obj_type = -obj_type. - -obj_name = -obj_name. - -sortkey = c_sortkey-default. " Default sort key - -changes = 0. - -path = -path. - ENDAT. - - IF -filename IS NOT INITIAL. - ls_file-path = -path. - ls_file-filename = -filename. - ls_file-is_changed = boolc( -match = abap_false ). " TODO refactor - ls_file-rstate = -rstate. - ls_file-lstate = -lstate. - APPEND ls_file TO -files. - - IF ls_file-is_changed = abap_true. - -sortkey = c_sortkey-changed. " Changed files - -changes = -changes + 1. - _reduce_state -lstate ls_file-lstate. - _reduce_state -rstate ls_file-rstate. - ENDIF. - ENDIF. - - AT END OF obj_name. "obj_type + obj_name - IF -obj_type IS INITIAL. - -sortkey = c_sortkey-orphan. "Virtual objects - ENDIF. - ENDAT. - ENDLOOP. - - ENDMETHOD. "get_remote - -ENDCLASS. "lcl_repo_content_browser - -********************************************************************** -********************************************************************** - CLASS lcl_gui_view_repo_content DEFINITION FINAL INHERITING FROM lcl_gui_page_super. PUBLIC SECTION.