BigW Consortium Gitlab

diff_refs.rb 2.21 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
module Gitlab
  module Diff
    class DiffRefs
      attr_reader :base_sha
      attr_reader :start_sha
      attr_reader :head_sha

      def initialize(base_sha:, start_sha: base_sha, head_sha:)
        @base_sha = base_sha
        @start_sha = start_sha
        @head_sha = head_sha
      end

      def ==(other)
        other.is_a?(self.class) &&
16 17 18
          shas_equal?(base_sha, other.base_sha) &&
          shas_equal?(start_sha, other.start_sha) &&
          shas_equal?(head_sha, other.head_sha)
19 20
      end

21 22 23 24 25 26
      alias_method :eql?, :==

      def hash
        [base_sha, start_sha, head_sha].hash
      end

27 28 29 30 31 32 33 34 35 36
      # There is only one case in which we will have `start_sha` and `head_sha`,
      # but not `base_sha`, which is when a diff is generated between an
      # orphaned branch and another branch, which means there _is_ no base, but
      # we're still able to highlight it, and to create diff notes, which are
      # the primary things `DiffRefs` are used for.
      # `DiffRefs` are "complete" when they have `start_sha` and `head_sha`,
      # because `base_sha` can always be derived from this, to return an actual
      # sha, or `nil`.
      # We have `base_sha` directly available on `DiffRefs` because it's faster#
      # than having to look it up in the repo every time.
37 38 39
      def complete?
        start_sha && head_sha
      end
40 41 42 43 44 45 46 47 48 49

      def compare_in(project)
        # We're at the initial commit, so just get that as we can't compare to anything.
        if Gitlab::Git.blank_ref?(start_sha)
          project.commit(head_sha)
        else
          straight = start_sha == base_sha
          CompareService.new(project, head_sha).execute(project, start_sha, straight: straight)
        end
      end
50 51 52 53 54 55 56 57 58 59

      private

      def shas_equal?(sha1, sha2)
        return true if sha1 == sha2
        return false if sha1.nil? || sha2.nil?
        return false unless sha1.class == sha2.class

        length = [sha1.length, sha2.length].min

60 61
        # If either of the shas is below the minimum length, we cannot be sure
        # that they actually refer to the same commit because of hash collision.
62 63 64 65
        return false if length < Commit::MIN_SHA_LENGTH

        sha1[0, length] == sha2[0, length]
      end
66 67 68
    end
  end
end