From 269c7cb1e6f45ac5b4b69946e8903f9f8f4d9f81 Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Tue, 11 Jan 2022 07:22:46 +0100 Subject: [PATCH] Adjust diff algorithm (#5251) * Adjust diff algorithm This implements a workaround for the kernel issue when determining diffs (see https://github.com/abapGit/abapGit/issues/4395 for background). Here's an example of the change. Before: After: * Lint + check * Add test * Ignore new tests Co-authored-by: Lars Hvam --- src/utils/zcl_abapgit_diff.clas.abap | 82 ++++++++++++ .../zcl_abapgit_diff.clas.testclasses.abap | 120 +++++++++++++++++- test/abap_transpile.json | 2 + 3 files changed, 201 insertions(+), 3 deletions(-) diff --git a/src/utils/zcl_abapgit_diff.clas.abap b/src/utils/zcl_abapgit_diff.clas.abap index c10f89373..5f3dade04 100644 --- a/src/utils/zcl_abapgit_diff.clas.abap +++ b/src/utils/zcl_abapgit_diff.clas.abap @@ -78,6 +78,7 @@ CLASS zcl_abapgit_diff DEFINITION RETURNING VALUE(rt_diff) TYPE zif_abapgit_definitions=>ty_diffs_tt. METHODS calculate_stats. + METHODS adjust_diff. ENDCLASS. @@ -85,6 +86,85 @@ ENDCLASS. CLASS zcl_abapgit_diff IMPLEMENTATION. + METHOD adjust_diff. + + " ABAP kernel diff traverses files from bottom up which leads to odd display of diffs + " SAP won't adjust this kernel service so we will do it here + " https://github.com/abapGit/abapGit/issues/4395 + + TYPES: + BEGIN OF ty_diff_block, + start TYPE i, + len TYPE i, + END OF ty_diff_block. + + DATA: + lv_block_begin TYPE i, + lv_block_end TYPE i, + ls_diff_block TYPE ty_diff_block, + lt_diff_block TYPE STANDARD TABLE OF ty_diff_block WITH DEFAULT KEY. + + FIELD-SYMBOLS: + LIKE LINE OF mt_diff, + LIKE LINE OF mt_diff, + LIKE LINE OF mt_diff. + + " Determine start and length of diff blocks + LOOP AT mt_diff ASSIGNING . + IF -result = zif_abapgit_definitions=>c_diff-insert OR + -result = zif_abapgit_definitions=>c_diff-delete. + IF ls_diff_block IS INITIAL. + ls_diff_block-start = sy-tabix. + ENDIF. + ls_diff_block-len = ls_diff_block-len + 1. + ELSEIF ls_diff_block-start IS NOT INITIAL. + APPEND ls_diff_block TO lt_diff_block. + CLEAR ls_diff_block. + ENDIF. + ENDLOOP. + + " For each diff block, check if beginning is same as end of block + " If yes, move diff block down + LOOP AT lt_diff_block INTO ls_diff_block. + DO ls_diff_block-len TIMES. + lv_block_begin = ls_diff_block-start + sy-index - 1. + READ TABLE mt_diff ASSIGNING INDEX lv_block_begin. + IF sy-subrc <> 0. + EXIT. + ENDIF. + lv_block_end = ls_diff_block-start + ls_diff_block-len + sy-index - 1. + READ TABLE mt_diff ASSIGNING INDEX lv_block_end. + IF sy-subrc <> 0. + EXIT. + ENDIF. + CASE -result. + WHEN zif_abapgit_definitions=>c_diff-insert. + IF -new = -new. + -old_num = -old_num. + -old = -old. + -result = -result. + CLEAR: -result, -old_num, -old. + ELSE. + EXIT. + ENDIF. + WHEN zif_abapgit_definitions=>c_diff-delete. + IF -old = -old. + -new_num = -new_num. + -new = -new. + -result = -result. + CLEAR: -result, -new_num, -new. + ELSE. + EXIT. + ENDIF. + WHEN OTHERS. + EXIT. + ENDCASE. + ENDDO. + ENDLOOP. + + ENDMETHOD. + + METHOD calculate_stats. FIELD-SYMBOLS: LIKE LINE OF mt_diff. @@ -197,6 +277,8 @@ CLASS zcl_abapgit_diff IMPLEMENTATION. mt_diff = compute_and_render( it_new = lt_new it_old = lt_old ). + adjust_diff( ). + calculate_stats( ). map_beacons( ). shortlist( ). diff --git a/src/utils/zcl_abapgit_diff.clas.testclasses.abap b/src/utils/zcl_abapgit_diff.clas.testclasses.abap index 996ad967d..1a57b1c68 100644 --- a/src/utils/zcl_abapgit_diff.clas.testclasses.abap +++ b/src/utils/zcl_abapgit_diff.clas.testclasses.abap @@ -15,7 +15,9 @@ CLASS ltcl_diff DEFINITION FOR TESTING iv_new TYPE zif_abapgit_definitions=>ty_diff-new iv_result TYPE zif_abapgit_definitions=>ty_diff-result iv_old_num TYPE zif_abapgit_definitions=>ty_diff-old_num - iv_old TYPE zif_abapgit_definitions=>ty_diff-old. + iv_old TYPE zif_abapgit_definitions=>ty_diff-old + iv_beacon TYPE zif_abapgit_definitions=>ty_diff-beacon + DEFAULT zcl_abapgit_diff=>co_starting_beacon. METHODS: setup. @@ -36,7 +38,9 @@ CLASS ltcl_diff DEFINITION FOR TESTING diff08 FOR TESTING, diff09 FOR TESTING, diff10 FOR TESTING, - diff11 FOR TESTING. + diff11 FOR TESTING, + diff12 FOR TESTING, + diff13 FOR TESTING. ENDCLASS. @@ -65,7 +69,7 @@ CLASS ltcl_diff IMPLEMENTATION. ls_expected-result = iv_result. ls_expected-old_num = iv_old_num. ls_expected-old = iv_old. - ls_expected-beacon = zcl_abapgit_diff=>co_starting_beacon. + ls_expected-beacon = iv_beacon. APPEND ls_expected TO mt_expected. ENDMETHOD. @@ -394,4 +398,114 @@ CLASS ltcl_diff IMPLEMENTATION. ENDMETHOD. + METHOD diff12. + + " adjusted diffs for insert (workaround for kernel issue) + add_new( iv_new = `REPORT zprog_diff.` ). + add_new( iv_new = `*` ). + add_new( iv_new = `FORM t_1.` ). + add_new( iv_new = `ENDFORM.` ). + add_new( iv_new = `FORM t_2.` ). + add_new( iv_new = `ENDFORM.` ). + + add_old( iv_old = `REPORT zprog_diff.` ). + add_old( iv_old = `FORM t_1.` ). + add_old( iv_old = `ENDFORM.` ). + + add_expected( iv_new_num = ' 1' + iv_new = `REPORT zprog_diff.` + iv_result = '' " no diff! + iv_old_num = ' 1' + iv_old = `REPORT zprog_diff.` + iv_beacon = 1 ). + add_expected( iv_new_num = ' 2' + iv_new = `*` + iv_result = 'I' + iv_old_num = ' ' + iv_old = `` + iv_beacon = 1 ). + add_expected( iv_new_num = ' 3' + iv_new = `FORM t_1.` + iv_result = '' " no diff! + iv_old_num = ' 2' + iv_old = `FORM t_1.` + iv_beacon = 2 ). + add_expected( iv_new_num = ' 4' + iv_new = `ENDFORM.` + iv_result = '' " no diff! + iv_old_num = ' 3' + iv_old = `ENDFORM.` + iv_beacon = 2 ). + add_expected( iv_new_num = ' 5' + iv_new = `FORM t_2.` + iv_result = 'I' + iv_old_num = ' ' + iv_old = `` + iv_beacon = 3 ). + add_expected( iv_new_num = ' 6' + iv_new = `ENDFORM.` + iv_result = 'I' + iv_old_num = ' ' + iv_old = `` + iv_beacon = 3 ). + + test( ). + + ENDMETHOD. + + METHOD diff13. + + " adjusted diffs for delete (workaround for kernel issue) + add_old( iv_old = `REPORT zprog_diff.` ). + add_old( iv_old = `*` ). + add_old( iv_old = `FORM t_1.` ). + add_old( iv_old = `ENDFORM.` ). + add_old( iv_old = `FORM t_2.` ). + add_old( iv_old = `ENDFORM.` ). + + add_new( iv_new = `REPORT zprog_diff.` ). + add_new( iv_new = `FORM t_1.` ). + add_new( iv_new = `ENDFORM.` ). + + add_expected( iv_old_num = ' 1' + iv_old = `REPORT zprog_diff.` + iv_result = '' " no diff! + iv_new_num = ' 1' + iv_new = `REPORT zprog_diff.` + iv_beacon = 1 ). + add_expected( iv_old_num = ' 2' + iv_old = `*` + iv_result = 'D' + iv_new_num = ' ' + iv_new = `` + iv_beacon = 1 ). + add_expected( iv_old_num = ' 3' + iv_old = `FORM t_1.` + iv_result = '' " no diff! + iv_new_num = ' 2' + iv_new = `FORM t_1.` + iv_beacon = 2 ). + add_expected( iv_old_num = ' 4' + iv_old = `ENDFORM.` + iv_result = '' " no diff! + iv_new_num = ' 3' + iv_new = `ENDFORM.` + iv_beacon = 2 ). + add_expected( iv_old_num = ' 5' + iv_old = `FORM t_2.` + iv_result = 'D' + iv_new_num = ' ' + iv_new = `` + iv_beacon = 2 ). + add_expected( iv_old_num = ' 6' + iv_old = `ENDFORM.` + iv_result = 'D' + iv_new_num = ' ' + iv_new = `` + iv_beacon = 2 ). + + test( ). + + ENDMETHOD. + ENDCLASS. diff --git a/test/abap_transpile.json b/test/abap_transpile.json index d642915e9..4e6decdab 100644 --- a/test/abap_transpile.json +++ b/test/abap_transpile.json @@ -239,6 +239,8 @@ {"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff09", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"}, {"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff10", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"}, {"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff11", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"}, + {"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff12", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"}, + {"object": "ZCL_ABAPGIT_DIFF", "class": "ltcl_diff", "method": "diff13", "note": "fm RS_CMP_COMPUTE_DELTA + Void type: RSWSOURCET"}, {"object": "ZCL_ABAPGIT_USER_RECORD", "class": "ltcl_user_record", "method": "test_invalid_user", "note": "Void type: BAPIADDR3"}, {"object": "ZCL_ABAPGIT_SERVICES_BASIS", "class": "ltcl_create_package", "method": "raise_error_if_package_exists", "note": "Void type: SCOMPKDTLN"}, {"object": "ZCL_ABAPGIT_SERVICES_BASIS", "class": "ltcl_create_package", "method": "package_given_in_popup", "note": "Void type: SCOMPKDTLN"},