From 6b4f0a66d3eaec9a194b382d92d4b188fb14f6d3 Mon Sep 17 00:00:00 2001 From: Marc Bernard Date: Mon, 28 Apr 2025 13:48:45 +0000 Subject: [PATCH 1/2] Refactor: Data loss check - Table comparison I finally found some time to tackle #1284 (from 2018). This change removes the popups that ask from confirmation of potential data loss when changing a table (or structure contained in a table) from the deserialize process to the preceeding check phase. The table comparison is now done upfront. If you select a table in the pull dialog and the changes could lead to data loss, for example if a field is removed, then a second popup will be shown. You will have to confirm overwriting the table. If not, the table remains unchanged. Closes #1284 It should fix #6746 as well since the check does not depend on the local/remote state anymore (@larshp). PS: Although this introduces a new popup, the change moves it to the UI layer. This paves the way for refactoring the pull process into a HTML page. This page will show the results of the deserialize check with checkboxes. You select objects to process and confirm to trigger the import. --- .../core/zcl_abapgit_objects_check.clas.abap | 211 +++++++++++++----- .../zcl_abapgit_objects_compare.clas.abap | 114 ++++++++++ .../core/zcl_abapgit_objects_compare.clas.xml | 16 ++ .../tabl/zcl_abapgit_object_tabl.clas.abap | 20 +- .../zcl_abapgit_object_tabl_compar.clas.abap | 60 ++--- src/objects/zcl_abapgit_objects.clas.abap | 88 -------- src/objects/zif_abapgit_comparator.intf.abap | 1 + src/objects/zif_abapgit_objects.intf.abap | 1 + .../zcl_abapgit_services_repo.clas.abap | 77 +++++++ src/zif_abapgit_definitions.intf.abap | 1 + 10 files changed, 400 insertions(+), 189 deletions(-) create mode 100644 src/objects/core/zcl_abapgit_objects_compare.clas.abap create mode 100644 src/objects/core/zcl_abapgit_objects_compare.clas.xml diff --git a/src/objects/core/zcl_abapgit_objects_check.clas.abap b/src/objects/core/zcl_abapgit_objects_check.clas.abap index 0bfee4e8e..5ef89cd00 100644 --- a/src/objects/core/zcl_abapgit_objects_check.clas.abap +++ b/src/objects/core/zcl_abapgit_objects_check.clas.abap @@ -1,17 +1,19 @@ CLASS zcl_abapgit_objects_check DEFINITION PUBLIC - CREATE PUBLIC . + CREATE PUBLIC. PUBLIC SECTION. + CLASS-METHODS class_constructor. + CLASS-METHODS deserialize_checks IMPORTING !ii_repo TYPE REF TO zif_abapgit_repo RETURNING VALUE(rs_checks) TYPE zif_abapgit_definitions=>ty_deserialize_checks RAISING - zcx_abapgit_exception . - CLASS-METHODS class_constructor. + zcx_abapgit_exception. + CLASS-METHODS checks_adjust IMPORTING !ii_repo TYPE REF TO zif_abapgit_repo @@ -19,11 +21,22 @@ CLASS zcl_abapgit_objects_check DEFINITION CHANGING !ct_results TYPE zif_abapgit_definitions=>ty_results_tt RAISING - zcx_abapgit_exception . - PROTECTED SECTION. + zcx_abapgit_exception. + PROTECTED SECTION. PRIVATE SECTION. - CLASS-DATA: gi_exit TYPE REF TO zif_abapgit_exit. + + CLASS-DATA gi_exit TYPE REF TO zif_abapgit_exit. + + CLASS-METHODS adjust_result + IMPORTING + !iv_txt TYPE string + !it_overwrite_old TYPE zif_abapgit_definitions=>ty_overwrite_tt + !it_overwrite_new TYPE zif_abapgit_definitions=>ty_overwrite_tt + CHANGING + !ct_results TYPE zif_abapgit_definitions=>ty_results_tt + RAISING + zcx_abapgit_exception. CLASS-METHODS warning_overwrite_adjust IMPORTING @@ -32,11 +45,13 @@ CLASS zcl_abapgit_objects_check DEFINITION !ct_results TYPE zif_abapgit_definitions=>ty_results_tt RAISING zcx_abapgit_exception. + CLASS-METHODS warning_overwrite_find IMPORTING !it_results TYPE zif_abapgit_definitions=>ty_results_tt RETURNING VALUE(rt_overwrite) TYPE zif_abapgit_definitions=>ty_overwrite_tt. + CLASS-METHODS warning_package_adjust IMPORTING !ii_repo TYPE REF TO zif_abapgit_repo @@ -45,6 +60,7 @@ CLASS zcl_abapgit_objects_check DEFINITION !ct_results TYPE zif_abapgit_definitions=>ty_results_tt RAISING zcx_abapgit_exception. + CLASS-METHODS warning_package_find IMPORTING !it_results TYPE zif_abapgit_definitions=>ty_results_tt @@ -53,17 +69,38 @@ CLASS zcl_abapgit_objects_check DEFINITION VALUE(rt_overwrite) TYPE zif_abapgit_definitions=>ty_overwrite_tt RAISING zcx_abapgit_exception. + + CLASS-METHODS warning_data_loss_adjust + IMPORTING + !ii_repo TYPE REF TO zif_abapgit_repo + !it_overwrite TYPE zif_abapgit_definitions=>ty_overwrite_tt + CHANGING + !ct_results TYPE zif_abapgit_definitions=>ty_results_tt + RAISING + zcx_abapgit_exception. + + CLASS-METHODS warning_data_loss_find + IMPORTING + !ii_repo TYPE REF TO zif_abapgit_repo + !it_results TYPE zif_abapgit_definitions=>ty_results_tt + RETURNING + VALUE(rt_overwrite) TYPE zif_abapgit_definitions=>ty_overwrite_tt + RAISING + zcx_abapgit_exception. + CLASS-METHODS determine_transport_request IMPORTING ii_repo TYPE REF TO zif_abapgit_repo iv_transport_type TYPE zif_abapgit_definitions=>ty_transport_type RETURNING VALUE(rv_transport_request) TYPE trkorr. + CLASS-METHODS check_multiple_files IMPORTING !it_results TYPE zif_abapgit_definitions=>ty_results_tt RAISING zcx_abapgit_exception. + ENDCLASS. @@ -71,8 +108,36 @@ ENDCLASS. CLASS zcl_abapgit_objects_check IMPLEMENTATION. + METHOD adjust_result. + + DATA ls_overwrite TYPE zif_abapgit_definitions=>ty_overwrite. + + FIELD-SYMBOLS TYPE zif_abapgit_definitions=>ty_overwrite. + + LOOP AT it_overwrite_new ASSIGNING . + + READ TABLE it_overwrite_old INTO ls_overwrite WITH TABLE KEY object_type_and_name + COMPONENTS obj_type = -obj_type obj_name = -obj_name. + IF sy-subrc <> 0 OR ls_overwrite-decision IS INITIAL. + zcx_abapgit_exception=>raise( |{ iv_txt } { -obj_type } { -obj_name } undecided| ). + ENDIF. + + IF ls_overwrite-decision = zif_abapgit_definitions=>c_no. + DELETE ct_results WHERE obj_type = -obj_type AND obj_name = -obj_name. + ASSERT sy-subrc = 0. + ENDIF. + + ENDLOOP. + + ENDMETHOD. + + METHOD checks_adjust. + " Make sure to get the current status, as something might have changed in the meanwhile + " - Remove objects from results that were deselected in confirmation popup + " - Raise exception if an object has no decision of what to do + warning_overwrite_adjust( EXPORTING it_overwrite = is_checks-overwrite @@ -86,6 +151,13 @@ CLASS zcl_abapgit_objects_check IMPLEMENTATION. CHANGING ct_results = ct_results ). + warning_data_loss_adjust( + EXPORTING + ii_repo = ii_repo + it_overwrite = is_checks-data_loss + CHANGING + ct_results = ct_results ). + ENDMETHOD. @@ -144,6 +216,10 @@ CLASS zcl_abapgit_objects_check IMPLEMENTATION. ii_repo = ii_repo it_results = lt_results ). + rs_checks-data_loss = warning_data_loss_find( + ii_repo = ii_repo + it_results = lt_results ). + IF lines( lt_results ) > 0. li_package = zcl_abapgit_factory=>get_sap_package( ii_repo->get_package( ) ). rs_checks-transport-required = li_package->are_changes_recorded_in_tr_req( ). @@ -174,33 +250,62 @@ CLASS zcl_abapgit_objects_check IMPLEMENTATION. ENDMETHOD. - METHOD warning_overwrite_adjust. + METHOD warning_data_loss_adjust. - DATA: lt_overwrite LIKE it_overwrite, - ls_overwrite LIKE LINE OF lt_overwrite. + DATA lt_overwrite LIKE it_overwrite. - FIELD-SYMBOLS: LIKE LINE OF lt_overwrite. + lt_overwrite = warning_data_loss_find( + it_results = ct_results + ii_repo = ii_repo ). + + adjust_result( + EXPORTING + iv_txt = 'Potential data loss for' + it_overwrite_old = it_overwrite + it_overwrite_new = lt_overwrite + CHANGING + ct_results = ct_results ). + + ENDMETHOD. -* make sure to get the current status, as something might have changed in the meanwhile - lt_overwrite = warning_overwrite_find( ct_results ). + METHOD warning_data_loss_find. - LOOP AT lt_overwrite ASSIGNING . + DATA: + ls_item TYPE zif_abapgit_definitions=>ty_item, + li_comparator TYPE REF TO zif_abapgit_comparator, + lv_result TYPE string. - READ TABLE it_overwrite INTO ls_overwrite - WITH TABLE KEY object_type_and_name - COMPONENTS obj_type = -obj_type - obj_name = -obj_name. - IF sy-subrc <> 0 OR ls_overwrite-decision IS INITIAL. - zcx_abapgit_exception=>raise( |Overwrite { -obj_type } { - -obj_name } undecided| ). + FIELD-SYMBOLS: + LIKE LINE OF it_results, + LIKE LINE OF rt_overwrite. + + " For optimal performance, we limit here by object type since we know that only TABL has a comparator + " If there are other object types in the future, extend the where clause or remove the check on object type. + LOOP AT it_results ASSIGNING WHERE match IS INITIAL AND filename CP '*.xml' + AND obj_type ='TABL' ##PRIMKEY[SEC_KEY]. + + CLEAR ls_item. + MOVE-CORRESPONDING TO ls_item. + + li_comparator = zcl_abapgit_objects_compare=>get_comparator( ls_item ). + IF NOT li_comparator IS BOUND. + RETURN. ENDIF. - IF ls_overwrite-decision = zif_abapgit_definitions=>c_no. - DELETE ct_results WHERE - obj_type = -obj_type AND - obj_name = -obj_name. - ASSERT sy-subrc = 0. + lv_result = zcl_abapgit_objects_compare=>get_result( + ii_comparator = li_comparator + iv_filename = -filename + it_local = ii_repo->get_files_local( ) + it_remote = ii_repo->get_files_remote( iv_ignore_files = abap_true ) ). + + IF lv_result IS NOT INITIAL. + APPEND INITIAL LINE TO rt_overwrite ASSIGNING . + MOVE-CORRESPONDING TO . + -devclass = -package. + -action = zif_abapgit_objects=>c_deserialize_action-data_loss. + -icon = icon_warning. + -text = lv_result. ENDIF. ENDLOOP. @@ -208,6 +313,23 @@ CLASS zcl_abapgit_objects_check IMPLEMENTATION. ENDMETHOD. + METHOD warning_overwrite_adjust. + + DATA lt_overwrite LIKE it_overwrite. + + lt_overwrite = warning_overwrite_find( ct_results ). + + adjust_result( + EXPORTING + iv_txt = 'Overwrite of object' + it_overwrite_old = it_overwrite + it_overwrite_new = lt_overwrite + CHANGING + ct_results = ct_results ). + + ENDMETHOD. + + METHOD warning_overwrite_find. DATA: @@ -301,36 +423,19 @@ CLASS zcl_abapgit_objects_check IMPLEMENTATION. METHOD warning_package_adjust. - DATA: lt_overwrite LIKE it_overwrite, - ls_overwrite LIKE LINE OF lt_overwrite. + DATA lt_overwrite LIKE it_overwrite. - FIELD-SYMBOLS: LIKE LINE OF lt_overwrite. - - -* make sure to get the current status, as something might have changed in the meanwhile lt_overwrite = warning_package_find( - it_results = ct_results - ii_repo = ii_repo ). + it_results = ct_results + ii_repo = ii_repo ). - LOOP AT lt_overwrite ASSIGNING . - - READ TABLE it_overwrite INTO ls_overwrite - WITH TABLE KEY object_type_and_name - COMPONENTS obj_type = -obj_type - obj_name = -obj_name. - IF sy-subrc <> 0 OR ls_overwrite-decision IS INITIAL. - zcx_abapgit_exception=>raise( |Overwrite of package { -obj_type } { - -obj_name } undecided| ). - ENDIF. - - IF ls_overwrite-decision = zif_abapgit_definitions=>c_no. - DELETE ct_results WHERE - obj_type = -obj_type AND - obj_name = -obj_name. - ASSERT sy-subrc = 0. - ENDIF. - - ENDLOOP. + adjust_result( + EXPORTING + iv_txt = 'Overwrite of package' + it_overwrite_old = it_overwrite + it_overwrite_new = lt_overwrite + CHANGING + ct_results = ct_results ). ENDMETHOD. @@ -361,7 +466,7 @@ CLASS zcl_abapgit_objects_check IMPLEMENTATION. iv_obj_name = -obj_name ). IF NOT ls_tadir IS INITIAL AND ls_tadir-devclass <> lv_package. -* overwriting object from different package than expected + " overwriting object from different package than expected CLEAR ls_overwrite. CONCATENATE -lstate -rstate INTO ls_overwrite-state RESPECTING BLANKS. REPLACE ALL OCCURRENCES OF ` ` IN ls_overwrite-state WITH '_'. diff --git a/src/objects/core/zcl_abapgit_objects_compare.clas.abap b/src/objects/core/zcl_abapgit_objects_compare.clas.abap new file mode 100644 index 000000000..28571c4b8 --- /dev/null +++ b/src/objects/core/zcl_abapgit_objects_compare.clas.abap @@ -0,0 +1,114 @@ +CLASS zcl_abapgit_objects_compare DEFINITION + PUBLIC + FINAL + CREATE PUBLIC. + + PUBLIC SECTION. + + CLASS-METHODS get_comparator + IMPORTING + is_item TYPE zif_abapgit_definitions=>ty_item + RETURNING + VALUE(ri_comparator) TYPE REF TO zif_abapgit_comparator. + + CLASS-METHODS get_result + IMPORTING + ii_comparator TYPE REF TO zif_abapgit_comparator + iv_filename TYPE string + it_local TYPE zif_abapgit_definitions=>ty_files_item_tt + it_remote TYPE zif_abapgit_git_definitions=>ty_files_tt + RETURNING + VALUE(rv_result) TYPE string + RAISING + zcx_abapgit_exception. + + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS zcl_abapgit_objects_compare IMPLEMENTATION. + + + METHOD get_comparator. + + DATA lv_class_name TYPE seoclsname. + + CONCATENATE 'ZCL_ABAPGIT_OBJECT_' is_item-obj_type '_COMPAR' INTO lv_class_name. + + IF zcl_abapgit_factory=>get_environment( )->is_merged( ) = abap_true. + " Prevent accidental usage of object handlers in the developer version + lv_class_name = |\\PROGRAM={ sy-repid }\\CLASS={ lv_class_name }|. + ENDIF. + + TRY. + CREATE OBJECT ri_comparator TYPE (lv_class_name) + EXPORTING + is_item = is_item. + CATCH cx_sy_create_object_error ##NO_HANDLER. + " No instance, no comparator for this object type + ENDTRY. + + ENDMETHOD. + + + METHOD get_result. + + " this method is used for comparing local with remote objects + " before pull, this is useful eg. when overwriting a TABL object. + " only the main XML file is used for comparison + + DATA: + ls_remote_file TYPE zif_abapgit_git_definitions=>ty_file, + ls_local_file TYPE zif_abapgit_definitions=>ty_file_item, + li_remote_version TYPE REF TO zif_abapgit_xml_input, + li_local_version TYPE REF TO zif_abapgit_xml_input, + li_log TYPE REF TO zif_abapgit_log, + ls_msg TYPE zif_abapgit_log=>ty_log_out, + lt_msg TYPE zif_abapgit_log=>ty_log_outs, + ls_result TYPE zif_abapgit_comparator=>ty_result. + + " REMOTE + " if file does not exist in remote, we don't need to validate + READ TABLE it_remote WITH KEY file COMPONENTS filename = iv_filename INTO ls_remote_file. + IF sy-subrc <> 0. + RETURN. + ENDIF. + + CREATE OBJECT li_remote_version TYPE zcl_abapgit_xml_input + EXPORTING + iv_xml = zcl_abapgit_convert=>xstring_to_string_utf8( ls_remote_file-data ) + iv_filename = iv_filename. + + " LOCAL + " if file does not exist locally, we don't need to validate + READ TABLE it_local WITH KEY file-filename = iv_filename INTO ls_local_file. + IF sy-subrc <> 0. + RETURN. + ENDIF. + + CREATE OBJECT li_local_version TYPE zcl_abapgit_xml_input + EXPORTING + iv_xml = zcl_abapgit_convert=>xstring_to_string_utf8( ls_local_file-file-data ) + iv_filename = iv_filename. + + " COMPARE + CREATE OBJECT li_log TYPE zcl_abapgit_log. + + ls_result = ii_comparator->compare( + ii_local = li_local_version + ii_remote = li_remote_version + ii_log = li_log ). + + rv_result = ls_result-text. + + " To keep it simple, append the log messages to the result + lt_msg = li_log->get_messages( ). + + LOOP AT lt_msg INTO ls_msg. + rv_result = |{ rv_result }, { ls_msg-text }|. + ENDLOOP. + + ENDMETHOD. +ENDCLASS. diff --git a/src/objects/core/zcl_abapgit_objects_compare.clas.xml b/src/objects/core/zcl_abapgit_objects_compare.clas.xml new file mode 100644 index 000000000..facaed18b --- /dev/null +++ b/src/objects/core/zcl_abapgit_objects_compare.clas.xml @@ -0,0 +1,16 @@ + + + + + + ZCL_ABAPGIT_OBJECTS_COMPARE + E + abapGit - Objects Comparator + 1 + X + X + X + + + + diff --git a/src/objects/tabl/zcl_abapgit_object_tabl.clas.abap b/src/objects/tabl/zcl_abapgit_object_tabl.clas.abap index b5b099665..701092d2e 100644 --- a/src/objects/tabl/zcl_abapgit_object_tabl.clas.abap +++ b/src/objects/tabl/zcl_abapgit_object_tabl.clas.abap @@ -850,24 +850,8 @@ CLASS zcl_abapgit_object_tabl IMPLEMENTATION. METHOD zif_abapgit_object~get_comparator. - - DATA: li_local_version_output TYPE REF TO zif_abapgit_xml_output, - li_local_version_input TYPE REF TO zif_abapgit_xml_input. - - - CREATE OBJECT li_local_version_output TYPE zcl_abapgit_xml_output. - - zif_abapgit_object~serialize( li_local_version_output ). - - CREATE OBJECT li_local_version_input - TYPE zcl_abapgit_xml_input - EXPORTING - iv_xml = li_local_version_output->render( ). - - CREATE OBJECT ri_comparator TYPE zcl_abapgit_object_tabl_compar - EXPORTING - ii_local = li_local_version_input. - + " Moved to zcl_abapgit_objects_compare + RETURN. ENDMETHOD. diff --git a/src/objects/tabl/zcl_abapgit_object_tabl_compar.clas.abap b/src/objects/tabl/zcl_abapgit_object_tabl_compar.clas.abap index 3a5bccd54..79cb39e1c 100644 --- a/src/objects/tabl/zcl_abapgit_object_tabl_compar.clas.abap +++ b/src/objects/tabl/zcl_abapgit_object_tabl_compar.clas.abap @@ -1,24 +1,25 @@ CLASS zcl_abapgit_object_tabl_compar DEFINITION PUBLIC - CREATE PUBLIC . + CREATE PUBLIC. PUBLIC SECTION. - INTERFACES zif_abapgit_comparator . + INTERFACES zif_abapgit_comparator. METHODS constructor IMPORTING - !ii_local TYPE REF TO zif_abapgit_xml_input. + !is_item TYPE zif_abapgit_definitions=>ty_item. + PROTECTED SECTION. TYPES: ty_founds TYPE STANDARD TABLE OF rsfindlst - WITH NON-UNIQUE DEFAULT KEY . + WITH NON-UNIQUE DEFAULT KEY. TYPES: ty_seu_obj TYPE STANDARD TABLE OF seu_obj - WITH NON-UNIQUE DEFAULT KEY . + WITH NON-UNIQUE DEFAULT KEY. - DATA mi_local TYPE REF TO zif_abapgit_xml_input. + DATA ms_item TYPE zif_abapgit_definitions=>ty_item. METHODS get_where_used_recursive IMPORTING @@ -29,14 +30,16 @@ CLASS zcl_abapgit_object_tabl_compar DEFINITION RETURNING VALUE(rt_founds_all) TYPE ty_founds RAISING - zcx_abapgit_exception . + zcx_abapgit_exception. + METHODS is_structure_used_in_db_table IMPORTING !iv_object_name TYPE dd02v-tabname RETURNING VALUE(rv_is_structure_used_in_db_tab) TYPE abap_bool RAISING - zcx_abapgit_exception . + zcx_abapgit_exception. + METHODS validate IMPORTING !ii_remote_version TYPE REF TO zif_abapgit_xml_input @@ -45,19 +48,19 @@ CLASS zcl_abapgit_object_tabl_compar DEFINITION RETURNING VALUE(rv_message) TYPE string RAISING - zcx_abapgit_exception . - PRIVATE SECTION. + zcx_abapgit_exception. + PRIVATE SECTION. ENDCLASS. -CLASS ZCL_ABAPGIT_OBJECT_TABL_COMPAR IMPLEMENTATION. +CLASS zcl_abapgit_object_tabl_compar IMPLEMENTATION. METHOD constructor. - mi_local = ii_local. + ms_item = is_item. ENDMETHOD. @@ -152,7 +155,6 @@ CLASS ZCL_ABAPGIT_OBJECT_TABL_COMPAR IMPLEMENTATION. lt_current_table_fields TYPE TABLE OF dd03p, ls_current_table_field LIKE LINE OF lt_current_table_fields, ls_dd02v TYPE dd02v, - ls_item TYPE zif_abapgit_definitions=>ty_item, lv_inconsistent TYPE abap_bool. FIELD-SYMBOLS TYPE abap_bool. @@ -176,18 +178,15 @@ CLASS ZCL_ABAPGIT_OBJECT_TABL_COMPAR IMPLEMENTATION. ii_remote_version->read( EXPORTING - iv_name = 'DD03P_TABLE' + iv_name = 'DD03P_TABLE' CHANGING - cg_data = lt_previous_table_fields ). + cg_data = lt_previous_table_fields ). ii_local_version->read( EXPORTING - iv_name = 'DD03P_TABLE' + iv_name = 'DD03P_TABLE' CHANGING - cg_data = lt_current_table_fields ). - - ls_item-obj_name = ls_dd02v-tabname. - ls_item-obj_type = 'TABL'. + cg_data = lt_current_table_fields ). LOOP AT lt_previous_table_fields INTO ls_previous_table_field. READ TABLE lt_current_table_fields WITH KEY fieldname = ls_previous_table_field-fieldname @@ -199,37 +198,34 @@ CLASS ZCL_ABAPGIT_OBJECT_TABL_COMPAR IMPLEMENTATION. iv_msg = |Field { ls_previous_table_field-fieldname }: | & |Data element changed from { ls_previous_table_field-rollname } | & |to { ls_current_table_field-rollname }| - is_item = ls_item ). + is_item = ms_item ). ELSEIF ls_current_table_field-rollname IS NOT INITIAL. ii_log->add_info( iv_msg = |Field { ls_previous_table_field-fieldname }: | & |Data type changed from internal type | & |{ ls_previous_table_field-inttype }(length { ls_previous_table_field-intlen }) | & |to data element { ls_current_table_field-rollname }| - is_item = ls_item ). + is_item = ms_item ). ELSEIF ls_previous_table_field-rollname IS NOT INITIAL. ii_log->add_info( iv_msg = |Field { ls_previous_table_field-fieldname }: | & |Data type changed from date element { ls_previous_table_field-rollname } | & |to internal type | & |{ ls_current_table_field-inttype }(length { ls_current_table_field-intlen })| - is_item = ls_item ). + is_item = ms_item ). ENDIF. "TODO: perform several other checks, e.g. field length truncated, ... lv_inconsistent = abap_true. ENDIF. ELSE. ii_log->add_info( iv_msg = |Field { ls_previous_table_field-fieldname } removed| - is_item = ls_item ). + is_item = ms_item ). lv_inconsistent = abap_true. ENDIF. ENDLOOP. - IF lv_inconsistent = abap_true. - rv_message = |Database Table { ls_dd02v-tabname }: Fields were changed. This may lead to inconsistencies!|. - ENDIF. - IF NOT rv_message IS INITIAL. - rv_message = |Database Table { ls_dd02v-tabname }: { rv_message }|. + IF lv_inconsistent = abap_true. + rv_message = 'Fields were changed!'. ENDIF. ENDMETHOD. @@ -237,9 +233,13 @@ CLASS ZCL_ABAPGIT_OBJECT_TABL_COMPAR IMPLEMENTATION. METHOD zif_abapgit_comparator~compare. + IF zcl_abapgit_objects=>exists( ms_item ) = abap_false. + RETURN. + ENDIF. + rs_result-text = validate( ii_remote_version = ii_remote - ii_local_version = mi_local + ii_local_version = ii_local ii_log = ii_log ). ENDMETHOD. diff --git a/src/objects/zcl_abapgit_objects.clas.abap b/src/objects/zcl_abapgit_objects.clas.abap index de2088479..afb5e7c52 100644 --- a/src/objects/zcl_abapgit_objects.clas.abap +++ b/src/objects/zcl_abapgit_objects.clas.abap @@ -120,14 +120,6 @@ CLASS zcl_abapgit_objects DEFINITION !iv_transport TYPE trkorr RAISING zcx_abapgit_exception . - CLASS-METHODS compare_remote_to_local - IMPORTING - !ii_object TYPE REF TO zif_abapgit_object - !it_remote TYPE zif_abapgit_git_definitions=>ty_files_tt - !is_result TYPE zif_abapgit_definitions=>ty_result - !ii_log TYPE REF TO zif_abapgit_log - RAISING - zcx_abapgit_exception . CLASS-METHODS deserialize_steps IMPORTING !it_steps TYPE zif_abapgit_objects=>ty_step_data_tt @@ -386,80 +378,6 @@ CLASS zcl_abapgit_objects IMPLEMENTATION. ENDMETHOD. - METHOD compare_remote_to_local. -* this method is used for comparing local with remote objects -* before pull, this is useful eg. when overwriting a TABL object. -* only the main XML file is used for comparison - - DATA: ls_remote_file TYPE zif_abapgit_git_definitions=>ty_file, - li_remote_version TYPE REF TO zif_abapgit_xml_input, - lv_count TYPE i, - ls_result TYPE zif_abapgit_comparator=>ty_result, - lv_answer TYPE string, - li_comparator TYPE REF TO zif_abapgit_comparator, - ls_item TYPE zif_abapgit_definitions=>ty_item. - - FIND ALL OCCURRENCES OF '.' IN is_result-filename MATCH COUNT lv_count. - - IF is_result-filename CS '.XML' AND lv_count = 2. - IF ii_object->exists( ) = abap_false. - RETURN. - ENDIF. - - READ TABLE it_remote WITH KEY file - COMPONENTS filename = is_result-filename INTO ls_remote_file. - IF sy-subrc <> 0. "if file does not exist in remote, we don't need to validate - RETURN. - ENDIF. - - li_comparator = ii_object->get_comparator( ). - IF NOT li_comparator IS BOUND. - RETURN. - ENDIF. - - CREATE OBJECT li_remote_version - TYPE zcl_abapgit_xml_input - EXPORTING - iv_xml = zcl_abapgit_convert=>xstring_to_string_utf8( ls_remote_file-data ) - iv_filename = ls_remote_file-filename. - - ls_result = li_comparator->compare( ii_remote = li_remote_version - ii_log = ii_log ). - IF ls_result-text IS INITIAL. - RETURN. - ENDIF. - - "log comparison result - ls_item-obj_type = is_result-obj_type. - ls_item-obj_name = is_result-obj_name. - ii_log->add_warning( iv_msg = ls_result-text - is_item = ls_item ). - - "continue or abort? - IF zcl_abapgit_ui_factory=>get_frontend_services( )->gui_is_available( ) = abap_true. - lv_answer = zcl_abapgit_ui_factory=>get_popups( )->popup_to_confirm( - iv_titlebar = 'Warning' - iv_text_question = ls_result-text - iv_text_button_1 = 'Pull Anyway' - iv_icon_button_1 = 'ICON_OKAY' - iv_text_button_2 = 'Cancel' - iv_icon_button_2 = 'ICON_CANCEL' - iv_default_button = '2' - iv_display_cancel_button = abap_false ). - - IF lv_answer = '2'. - zcx_abapgit_exception=>raise( |Deserialization for object { is_result-obj_name } | & - |(type { is_result-obj_type }) aborted by user| ). - ENDIF. - ELSE. - zcx_abapgit_exception=>raise( |Deserialization for object { is_result-obj_name } | & - |(type { is_result-obj_type }) aborted, user decision required| ). - ENDIF. - ENDIF. - - ENDMETHOD. - - METHOD create_object. DATA: lv_class_name TYPE string, @@ -803,12 +721,6 @@ CLASS zcl_abapgit_objects IMPLEMENTATION. io_files = lo_files io_i18n_params = lo_i18n_params ). - compare_remote_to_local( - ii_object = li_obj - it_remote = lt_remote - is_result = - ii_log = ii_log ). - "get required steps for deserialize the object lt_steps_id = li_obj->get_deserialize_steps( ). diff --git a/src/objects/zif_abapgit_comparator.intf.abap b/src/objects/zif_abapgit_comparator.intf.abap index 3cdfda38b..5856e4805 100644 --- a/src/objects/zif_abapgit_comparator.intf.abap +++ b/src/objects/zif_abapgit_comparator.intf.abap @@ -9,6 +9,7 @@ INTERFACE zif_abapgit_comparator METHODS compare IMPORTING + !ii_local TYPE REF TO zif_abapgit_xml_input !ii_remote TYPE REF TO zif_abapgit_xml_input !ii_log TYPE REF TO zif_abapgit_log RETURNING diff --git a/src/objects/zif_abapgit_objects.intf.abap b/src/objects/zif_abapgit_objects.intf.abap index e20f4bd19..0218ba397 100644 --- a/src/objects/zif_abapgit_objects.intf.abap +++ b/src/objects/zif_abapgit_objects.intf.abap @@ -43,6 +43,7 @@ INTERFACE zif_abapgit_objects PUBLIC. delete TYPE i VALUE 4, delete_add TYPE i VALUE 5, packmove TYPE i VALUE 6, + data_loss TYPE i VALUE 7, END OF c_deserialize_action. ENDINTERFACE. diff --git a/src/ui/routing/zcl_abapgit_services_repo.clas.abap b/src/ui/routing/zcl_abapgit_services_repo.clas.abap index f1ba5bc58..21e7a294c 100644 --- a/src/ui/routing/zcl_abapgit_services_repo.clas.abap +++ b/src/ui/routing/zcl_abapgit_services_repo.clas.abap @@ -106,6 +106,13 @@ CLASS zcl_abapgit_services_repo DEFINITION !ct_overwrite TYPE zif_abapgit_definitions=>ty_overwrite_tt RAISING zcx_abapgit_exception . + CLASS-METHODS popup_data_loss_overwrite + IMPORTING + !it_overwrite TYPE zif_abapgit_definitions=>ty_overwrite_tt + CHANGING + !ct_data_loss TYPE zif_abapgit_definitions=>ty_overwrite_tt + RAISING + zcx_abapgit_exception . CLASS-METHODS popup_package_overwrite CHANGING !ct_overwrite TYPE zif_abapgit_definitions=>ty_overwrite_tt @@ -441,6 +448,69 @@ CLASS zcl_abapgit_services_repo IMPLEMENTATION. ENDMETHOD. + METHOD popup_data_loss_overwrite. + + DATA: lt_columns TYPE zif_abapgit_popups=>ty_alv_column_tt, + lt_selected LIKE ct_data_loss, + li_popups TYPE REF TO zif_abapgit_popups. + DATA lt_preselected_rows TYPE zif_abapgit_popups=>ty_rows. + + FIELD-SYMBOLS: LIKE LINE OF it_overwrite, + LIKE LINE OF ct_data_loss, + TYPE zif_abapgit_popups=>ty_alv_column. + + LOOP AT it_overwrite ASSIGNING WHERE decision <> zif_abapgit_definitions=>c_yes. + DELETE ct_data_loss WHERE obj_type = -obj_type AND obj_name = -obj_name. + ENDLOOP. + + IF lines( ct_data_loss ) = 0. + RETURN. + ENDIF. + + APPEND INITIAL LINE TO lt_columns ASSIGNING . + -name = 'OBJ_TYPE'. + APPEND INITIAL LINE TO lt_columns ASSIGNING . + -name = 'OBJ_NAME'. + APPEND INITIAL LINE TO lt_columns ASSIGNING . + -name = 'ICON'. + -text = 'Action'. + -show_icon = abap_true. + -length = 5. + APPEND INITIAL LINE TO lt_columns ASSIGNING . + -name = 'TEXT'. + -text = 'Description'. + + LOOP AT ct_data_loss ASSIGNING WHERE decision = zif_abapgit_definitions=>c_yes. + INSERT sy-tabix INTO TABLE lt_preselected_rows. + ENDLOOP. + + li_popups = zcl_abapgit_ui_factory=>get_popups( ). + li_popups->popup_to_select_from_list( + EXPORTING + it_list = ct_data_loss + iv_header_text = |Changes to the following objects could lead to DATA LOSS!| + && | Select the objects which should be changed to the remote version, anyway.| + iv_select_column_text = 'Overwrite?' + it_columns_to_display = lt_columns + it_preselected_rows = lt_preselected_rows + IMPORTING + et_list = lt_selected ). + + LOOP AT ct_data_loss ASSIGNING . + READ TABLE lt_selected WITH TABLE KEY object_type_and_name + COMPONENTS obj_type = -obj_type + obj_name = -obj_name + TRANSPORTING NO FIELDS. + IF sy-subrc = 0. + -decision = zif_abapgit_definitions=>c_yes. + ELSE. + -decision = zif_abapgit_definitions=>c_no. + ENDIF. + ENDLOOP. + + ENDMETHOD. + + METHOD popup_decisions. DATA: @@ -479,6 +549,13 @@ CLASS zcl_abapgit_services_repo IMPLEMENTATION. ENDIF. popup_objects_overwrite( CHANGING ct_overwrite = lt_decision ). + + popup_data_loss_overwrite( + EXPORTING + it_overwrite = lt_decision + CHANGING + ct_data_loss = cs_checks-data_loss ). + popup_package_overwrite( CHANGING ct_overwrite = cs_checks-warning_package ). IF cs_checks-transport-required = abap_true AND cs_checks-transport-transport IS INITIAL. diff --git a/src/zif_abapgit_definitions.intf.abap b/src/zif_abapgit_definitions.intf.abap index 3efdfc247..9fd937dd1 100644 --- a/src/zif_abapgit_definitions.intf.abap +++ b/src/zif_abapgit_definitions.intf.abap @@ -78,6 +78,7 @@ INTERFACE zif_abapgit_definitions BEGIN OF ty_deserialize_checks, overwrite TYPE ty_overwrite_tt, warning_package TYPE ty_overwrite_tt, + data_loss TYPE ty_overwrite_tt, requirements TYPE ty_requirements, dependencies TYPE ty_dependencies, transport TYPE ty_transport, From 8363b0b314120f313132ff00d6a3694cc8513f2b Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Mon, 28 Apr 2025 15:58:06 +0200 Subject: [PATCH 2/2] lint --- src/objects/core/zcl_abapgit_objects_check.clas.abap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/core/zcl_abapgit_objects_check.clas.abap b/src/objects/core/zcl_abapgit_objects_check.clas.abap index 5ef89cd00..72f47f327 100644 --- a/src/objects/core/zcl_abapgit_objects_check.clas.abap +++ b/src/objects/core/zcl_abapgit_objects_check.clas.abap @@ -283,7 +283,7 @@ CLASS zcl_abapgit_objects_check IMPLEMENTATION. " For optimal performance, we limit here by object type since we know that only TABL has a comparator " If there are other object types in the future, extend the where clause or remove the check on object type. LOOP AT it_results ASSIGNING WHERE match IS INITIAL AND filename CP '*.xml' - AND obj_type ='TABL' ##PRIMKEY[SEC_KEY]. + AND obj_type = 'TABL' ##PRIMKEY[SEC_KEY]. CLEAR ls_item. MOVE-CORRESPONDING TO ls_item.