From 9c740133a3bb4e992ccd7e3801402e4eab537e29 Mon Sep 17 00:00:00 2001
From: Felipe Artur <felipefac@gmail.com>
Date: Thu, 17 Nov 2016 18:46:31 -0200
Subject: [PATCH] Allow JIRA references for project snippets

---
 app/models/concerns/mentionable.rb          |  2 +-
 app/models/project_services/jira_service.rb | 30 +++++-----
 app/models/snippet.rb                       |  1 +
 changelogs/unreleased/issue_24303.yml       |  4 ++
 spec/services/system_note_service_spec.rb   | 65 +++++++++++++++------
 5 files changed, 70 insertions(+), 32 deletions(-)
 create mode 100644 changelogs/unreleased/issue_24303.yml

diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index eb2ff0428f6..8ab0401d288 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -1,6 +1,6 @@
 # == Mentionable concern
 #
-# Contains functionality related to objects that can mention Users, Issues, MergeRequests, or Commits by
+# Contains functionality related to objects that can mention Users, Issues, MergeRequests, Commits or Snippets by
 # GFM references.
 #
 # Used by Issue, Note, MergeRequest, and Commit.
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 2caf6179ef8..aeded715893 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -128,15 +128,9 @@ class JiraService < IssueTrackerService
 
     return unless jira_issue.present?
 
-    project = self.project
-    noteable_name = noteable.model_name.singular
-    noteable_id = if noteable.is_a?(Commit)
-                    noteable.id
-                  else
-                    noteable.iid
-                  end
-
-    entity_url = build_entity_url(noteable_name.to_sym, noteable_id)
+    noteable_id   = noteable.respond_to?(:iid) ? noteable.iid : noteable.id
+    noteable_type = noteable_name(noteable)
+    entity_url    = build_entity_url(noteable_type, noteable_id)
 
     data = {
       user: {
@@ -144,11 +138,11 @@ class JiraService < IssueTrackerService
         url: resource_url(user_path(author)),
       },
       project: {
-        name: project.path_with_namespace,
-        url: resource_url(namespace_project_path(project.namespace, project))
+        name: self.project.path_with_namespace,
+        url: resource_url(namespace_project_path(project.namespace, self.project))
       },
       entity: {
-        name: noteable_name.humanize.downcase,
+        name: noteable_type.humanize.downcase,
         url: entity_url,
         title: noteable.title
       }
@@ -285,18 +279,26 @@ class JiraService < IssueTrackerService
     "#{Settings.gitlab.base_url.chomp("/")}#{resource}"
   end
 
-  def build_entity_url(entity_name, entity_id)
+  def build_entity_url(noteable_type, entity_id)
     polymorphic_url(
       [
         self.project.namespace.becomes(Namespace),
         self.project,
-        entity_name
+        noteable_type.to_sym
       ],
       id:   entity_id,
       host: Settings.gitlab.base_url
     )
   end
 
+  def noteable_name(noteable)
+    name = noteable.model_name.singular
+
+    # ProjectSnippet inherits from Snippet class so it causes
+    # routing error building the URL.
+    name == "project_snippet" ? "snippet" : name
+  end
+
   # Handle errors when doing JIRA API calls
   def jira_request
     yield
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 2373b445009..8ff4e7ae718 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -6,6 +6,7 @@ class Snippet < ActiveRecord::Base
   include Referable
   include Sortable
   include Awardable
+  include Mentionable
 
   cache_markdown_field :title, pipeline: :single_line
   cache_markdown_field :content
diff --git a/changelogs/unreleased/issue_24303.yml b/changelogs/unreleased/issue_24303.yml
new file mode 100644
index 00000000000..1f007712732
--- /dev/null
+++ b/changelogs/unreleased/issue_24303.yml
@@ -0,0 +1,4 @@
+---
+title: Fix JIRA references for project snippets
+merge_request: 
+author: 
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 150e21574a1..2a5709c6322 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -543,7 +543,10 @@ describe SystemNoteService, services: true do
     let(:comment_url)     { jira_api_comment_url(jira_issue.id) }
     let(:success_message) { "JiraService SUCCESS: Successfully posted to http://jira.example.net." }
 
-    before { stub_jira_urls(jira_issue.id) }
+    before do
+      stub_jira_urls(jira_issue.id)
+      jira_service_settings
+    end
 
     noteable_types = ["merge_requests", "commit"]
 
@@ -569,16 +572,16 @@ describe SystemNoteService, services: true do
       end
     end
 
-    context 'in JIRA issue tracker' do
-      before { jira_service_settings }
-
-      describe "new reference" do
-        subject { described_class.cross_reference(jira_issue, commit, author) }
+    describe "new reference" do
+      context 'for commits' do
+        it "creates comment" do
+          result = described_class.cross_reference(jira_issue, commit, author)
 
-        it { is_expected.to eq(success_message) }
+          expect(result).to eq(success_message)
+        end
 
         it "creates remote link" do
-          subject
+          described_class.cross_reference(jira_issue, commit, author)
 
           expect(WebMock).to have_requested(:post, jira_api_remote_link_url(jira_issue)).with(
             body: hash_including(
@@ -593,18 +596,18 @@ describe SystemNoteService, services: true do
           ).once
         end
       end
-    end
 
-    context 'in commit' do
-      context 'in JIRA issue tracker' do
-        before { jira_service_settings }
+      context 'for issues' do
+        let(:issue)           { create(:issue, project: project) }
 
-        subject { described_class.cross_reference(jira_issue, issue, author) }
+        it "creates comment" do
+          result = described_class.cross_reference(jira_issue, issue, author)
 
-        it { is_expected.to eq(success_message) }
+          expect(result).to eq(success_message)
+        end
 
         it "creates remote link" do
-          subject
+          described_class.cross_reference(jira_issue, issue, author)
 
           expect(WebMock).to have_requested(:post, jira_api_remote_link_url(jira_issue)).with(
             body: hash_including(
@@ -619,6 +622,32 @@ describe SystemNoteService, services: true do
           ).once
         end
       end
+
+      context 'for snippets' do
+        let(:snippet) { create(:snippet, project: project) }
+
+        it "creates comment" do
+          result = described_class.cross_reference(jira_issue, snippet, author)
+
+          expect(result).to eq(success_message)
+        end
+
+        it "creates remote link" do
+          described_class.cross_reference(jira_issue, snippet, author)
+
+          expect(WebMock).to have_requested(:post, jira_api_remote_link_url(jira_issue)).with(
+            body: hash_including(
+              GlobalID: "GitLab",
+              object: {
+                url: namespace_project_snippet_url(project.namespace, project, snippet),
+                title: "GitLab: Mentioned on snippet - #{snippet.title}",
+                icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
+                status: { resolved: false }
+              }
+            )
+          ).once
+        end
+      end
     end
 
     describe "existing reference" do
@@ -627,9 +656,11 @@ describe SystemNoteService, services: true do
         allow_any_instance_of(JIRA::Resource::Issue).to receive(:comments).and_return([OpenStruct.new(body: message)])
       end
 
-      subject { described_class.cross_reference(jira_issue, commit, author) }
+      it "does not return success message" do
+        result = described_class.cross_reference(jira_issue, commit, author)
 
-      it { is_expected.not_to eq(success_message) }
+        expect(result).not_to eq(success_message)
+      end
 
       it 'does not try to create comment and remote link' do
         subject
-- 
GitLab