Commit ee2e5751 authored by Vasilii Iakliushin's avatar Vasilii Iakliushin

Add feature flag `improved_merge_diff_highlighting`

* Provide `project` instance to Feature.enabled?
* Use old or new highlighting implementations based on the FF
* Generate a versioned cache based on FF
parent 8dcd64a2
---
title: Improve highlighting for merge diffs
merge_request: 52499
author:
type: added
---
name: improved_merge_diff_highlighting
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52499
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/299884
milestone: '13.9'
type: development
group: group::source code
default_enabled: false
...@@ -3,12 +3,13 @@ ...@@ -3,12 +3,13 @@
module Gitlab module Gitlab
module Diff module Diff
class Highlight class Highlight
attr_reader :diff_file, :diff_lines, :raw_lines, :repository attr_reader :diff_file, :diff_lines, :raw_lines, :repository, :project
delegate :old_path, :new_path, :old_sha, :new_sha, to: :diff_file, prefix: :diff delegate :old_path, :new_path, :old_sha, :new_sha, to: :diff_file, prefix: :diff
def initialize(diff_lines, repository: nil) def initialize(diff_lines, repository: nil)
@repository = repository @repository = repository
@project = repository&.project
if diff_lines.is_a?(Gitlab::Diff::File) if diff_lines.is_a?(Gitlab::Diff::File)
@diff_file = diff_lines @diff_file = diff_lines
...@@ -66,7 +67,7 @@ module Gitlab ...@@ -66,7 +67,7 @@ module Gitlab
end end
def inline_diffs def inline_diffs
@inline_diffs ||= InlineDiff.for_lines(@raw_lines) @inline_diffs ||= InlineDiff.for_lines(@raw_lines, project: project)
end end
def old_lines def old_lines
......
...@@ -8,6 +8,7 @@ module Gitlab ...@@ -8,6 +8,7 @@ module Gitlab
EXPIRATION = 1.week EXPIRATION = 1.week
VERSION = 1 VERSION = 1
NEXT_VERSION = 2
delegate :diffable, to: :@diff_collection delegate :diffable, to: :@diff_collection
delegate :diff_options, to: :@diff_collection delegate :diff_options, to: :@diff_collection
...@@ -69,12 +70,20 @@ module Gitlab ...@@ -69,12 +70,20 @@ module Gitlab
def key def key
strong_memoize(:redis_key) do strong_memoize(:redis_key) do
['highlighted-diff-files', diffable.cache_key, VERSION, diff_options].join(":") ['highlighted-diff-files', diffable.cache_key, version, diff_options].join(":")
end end
end end
private private
def version
if Feature.enabled?(:improved_merge_diff_highlighting, diffable.project)
NEXT_VERSION
else
VERSION
end
end
def set_highlighted_diff_lines(diff_file, content) def set_highlighted_diff_lines(diff_file, content)
diff_file.highlighted_diff_lines = content.map do |line| diff_file.highlighted_diff_lines = content.map do |line|
Gitlab::Diff::Line.safe_init_from_hash(line) Gitlab::Diff::Line.safe_init_from_hash(line)
......
...@@ -27,15 +27,19 @@ module Gitlab ...@@ -27,15 +27,19 @@ module Gitlab
@offset = offset @offset = offset
end end
def inline_diffs def inline_diffs(project: nil)
# Skip inline diff if empty line was replaced with content # Skip inline diff if empty line was replaced with content
return if old_line == "" return if old_line == ""
if Feature.enabled?(:improved_merge_diff_highlighting, project)
CharDiff.new(old_line, new_line).changed_ranges(offset: offset) CharDiff.new(old_line, new_line).changed_ranges(offset: offset)
else
deprecated_diff
end
end end
class << self class << self
def for_lines(lines) def for_lines(lines, project: nil)
changed_line_pairs = find_changed_line_pairs(lines) changed_line_pairs = find_changed_line_pairs(lines)
inline_diffs = [] inline_diffs = []
...@@ -44,7 +48,7 @@ module Gitlab ...@@ -44,7 +48,7 @@ module Gitlab
old_line = lines[old_index] old_line = lines[old_index]
new_line = lines[new_index] new_line = lines[new_index]
old_diffs, new_diffs = new(old_line, new_line, offset: 1).inline_diffs old_diffs, new_diffs = new(old_line, new_line, offset: 1).inline_diffs(project: project)
inline_diffs[old_index] = old_diffs inline_diffs[old_index] = old_diffs
inline_diffs[new_index] = new_diffs inline_diffs[new_index] = new_diffs
...@@ -84,6 +88,24 @@ module Gitlab ...@@ -84,6 +88,24 @@ module Gitlab
private private
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/299884
def deprecated_diff
lcp = longest_common_prefix(old_line, new_line)
lcs = longest_common_suffix(old_line[lcp..-1], new_line[lcp..-1])
lcp += offset
old_length = old_line.length + offset
new_length = new_line.length + offset
old_diff_range = lcp..(old_length - lcs - 1)
new_diff_range = lcp..(new_length - lcs - 1)
old_diffs = [old_diff_range] if old_diff_range.begin <= old_diff_range.end
new_diffs = [new_diff_range] if new_diff_range.begin <= new_diff_range.end
[old_diffs, new_diffs]
end
def longest_common_prefix(a, b) # rubocop:disable Naming/UncommunicativeMethodParamName def longest_common_prefix(a, b) # rubocop:disable Naming/UncommunicativeMethodParamName
max_length = [a.length, b.length].max max_length = [a.length, b.length].max
......
...@@ -233,4 +233,22 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do ...@@ -233,4 +233,22 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
cache.write_if_empty cache.write_if_empty
end end
end end
describe '#key' do
subject { cache.key }
it 'returns the next version of the cache' do
is_expected.to start_with("highlighted-diff-files:#{cache.diffable.cache_key}:2")
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(improved_merge_diff_highlighting: false)
end
it 'returns the original version of the cache' do
is_expected.to start_with("highlighted-diff-files:#{cache.diffable.cache_key}:1")
end
end
end
end end
...@@ -52,6 +52,17 @@ RSpec.describe Gitlab::Diff::InlineDiff do ...@@ -52,6 +52,17 @@ RSpec.describe Gitlab::Diff::InlineDiff do
expect(subject[0]).to eq([3..6]) expect(subject[0]).to eq([3..6])
expect(subject[1]).to eq([3..3, 17..22]) expect(subject[1]).to eq([3..3, 17..22])
end end
context 'when feature flag is disabled' do
before do
stub_feature_flags(improved_merge_diff_highlighting: false)
end
it 'finds all inline diffs' do
expect(subject[0]).to eq([3..19])
expect(subject[1]).to eq([3..22])
end
end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment