From d09fdfd6c72e544fa3156a13cad59a791e977dce Mon Sep 17 00:00:00 2001
From: Stan Hu <stanhu@gmail.com>
Date: Wed, 25 Jan 2017 23:13:09 -0800
Subject: [PATCH] Fix Error 500 when repositories contain annotated tags
 pointing to blobs

In repositories such as https://github.com/git/git.git, annotated tags can
point to blobs, not necessarily to commits. `Repository` attempts to
return the tags in the order of the commit date, but if a commit is not
available the previous implementation would error due to a `nil` target.
This change modifies the code to use the current time if a commit
is not associated with the given tag.

Closes #27228
---
 app/models/repository.rb                      | 13 +++++++++-
 ...sh-fix-annotated-tags-pointing-to-blob.yml |  4 ++++
 spec/models/repository_spec.rb                | 24 +++++++++++++++++++
 3 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 changelogs/unreleased/sh-fix-annotated-tags-pointing-to-blob.yml

diff --git a/app/models/repository.rb b/app/models/repository.rb
index 43dba86e5ed..d77b7692d75 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1188,7 +1188,18 @@ class Repository
   end
 
   def tags_sorted_by_committed_date
-    tags.sort_by { |tag| tag.dereferenced_target.committed_date }
+    tags.sort_by do |tag|
+      # Annotated tags can point to any object (e.g. a blob), but generally
+      # tags point to a commit. If we don't have a commit, then just default
+      # to putting the tag at the end of the list.
+      target = tag.dereferenced_target
+
+      if target
+        target.committed_date
+      else
+        Time.now
+      end
+    end
   end
 
   def keep_around_ref_name(sha)
diff --git a/changelogs/unreleased/sh-fix-annotated-tags-pointing-to-blob.yml b/changelogs/unreleased/sh-fix-annotated-tags-pointing-to-blob.yml
new file mode 100644
index 00000000000..ff2b38f21f2
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-annotated-tags-pointing-to-blob.yml
@@ -0,0 +1,4 @@
+---
+title: Fix Error 500 when repositories contain annotated tags pointing to blobs
+merge_request:
+author:
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 99ca53938c8..b91fbc1a845 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -90,6 +90,30 @@ describe Repository, models: true do
 
         it { is_expected.to eq(['v1.1.0', 'v1.0.0']) }
       end
+
+      context 'annotated tag pointing to a blob' do
+        let(:annotated_tag_name) { 'annotated-tag' }
+
+        subject { repository.tags_sorted_by('updated_asc').map(&:name) }
+
+        before do
+          options = { message: 'test tag message\n',
+                      tagger: { name: 'John Smith', email: 'john@gmail.com' } }
+          repository.rugged.tags.create(annotated_tag_name, 'a48e4fc218069f68ef2e769dd8dfea3991362175', options)
+
+          double_first = double(committed_date: Time.now - 1.second)
+          double_last = double(committed_date: Time.now)
+
+          allow(tag_a).to receive(:dereferenced_target).and_return(double_last)
+          allow(tag_b).to receive(:dereferenced_target).and_return(double_first)
+        end
+
+        it { is_expected.to eq(['v1.1.0', 'v1.0.0', annotated_tag_name]) }
+
+        after do
+          repository.rugged.tags.delete(annotated_tag_name)
+        end
+      end
     end
   end
 
-- 
GitLab