diff --git a/app/models/job.rb b/app/models/job.rb index d647a97..c6c1477 100644 --- a/app/models/job.rb +++ b/app/models/job.rb @@ -49,10 +49,41 @@ def details result.to_unified_diff end + def normalize_zipnote_diffs(diff) + normalize_diff_details(diff) + diff + end + + def normalize_diff_details(detail) + detail["details"]&.each { |subdetail| normalize_diff_details(subdetail) } + + return unless detail["unified_diff"].present? + return unless [detail["source1"], detail["source2"]].compact.any? { |source| source.include?("zipnote") } + + detail["unified_diff"] = sort_zipnote_filename_diff(detail["unified_diff"]) + end + + def sort_zipnote_filename_diff(diff) + filename_lines, other_lines = diff.lines.partition do |line| + line.start_with?("-Filename: ") || line.start_with?("+Filename: ") + end + + removed = filename_lines.select { |line| line.start_with?("-Filename: ") }.sort_by { |line| zipnote_sort_key(line) } + added = filename_lines.select { |line| line.start_with?("+Filename: ") }.sort_by { |line| zipnote_sort_key(line) } + + return diff if removed.empty? || added.empty? || removed.length != added.length + + removed.zip(added).flat_map { |old_line, new_line| [old_line, new_line] }.join + other_lines.join + end + + def zipnote_sort_key(line) + line.sub(/^[+-]Filename: /, '').sub(%r{^[^/]+/}, '') + end + def generate_diff result = Diffoscope.compare(url_1, url_2, new_file: true) update!( - results: { diff: result.to_h }, + results: { diff: normalize_zipnote_diffs(result.to_h) }, status: 'complete', sha256_1: result.sha256_1, sha256_2: result.sha256_2 diff --git a/test/models/job_test.rb b/test/models/job_test.rb index c7cdf7d..65631ba 100644 --- a/test/models/job_test.rb +++ b/test/models/job_test.rb @@ -22,6 +22,22 @@ class JobTest < ActiveSupport::TestCase @job.generate_diff_async end + test 'normalize_zipnote_diffs sorts zipnote filename entries recursively' do + diff = { + "details" => [ + { + "source1" => "zipnote {}", + "source2" => "zipnote {}", + "unified_diff" => "-Filename: pkg@v1/z.yml\n+Filename: pkg@v2/a.yml\n-Filename: pkg@v1/a.yml\n+Filename: pkg@v2/z.yml\n Comment:\n" + } + ] + } + + @job.normalize_zipnote_diffs(diff) + + assert_equal "-Filename: pkg@v1/a.yml\n+Filename: pkg@v2/a.yml\n-Filename: pkg@v1/z.yml\n+Filename: pkg@v2/z.yml\n Comment:\n", diff["details"].first["unified_diff"] + end + test 'generate_diff' do result = mock result.stubs(:to_h).returns({ "source1" => "a", "source2" => "b" })