From 8681cb3137511e51e19f76aef9839be28f8fcd6a Mon Sep 17 00:00:00 2001
From: Nikita Verkhovin <vernik91@gmail.com>
Date: Sat, 7 Feb 2015 17:14:55 +0600
Subject: [PATCH] Add labels notes

---
 app/helpers/labels_helper.rb                  |  2 +-
 app/models/note.rb                            | 30 +++++++++++++++++++
 app/services/issuable_base_service.rb         |  5 ++++
 app/services/issues/update_service.rb         |  7 +++++
 app/services/merge_requests/update_service.rb | 10 +++++++
 lib/gitlab/markdown.rb                        | 18 +++++++++--
 lib/gitlab/reference_extractor.rb             | 11 +++++--
 spec/services/issues/update_service_spec.rb   | 11 ++++++-
 .../merge_requests/update_service_spec.rb     | 11 ++++++-
 9 files changed, 98 insertions(+), 7 deletions(-)

diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 19d688c4bb8..add0fef512e 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -7,7 +7,7 @@ module LabelsHelper
     label_color = label.color || Label::DEFAULT_COLOR
     text_color = text_color_for_bg(label_color)
 
-    content_tag :span, class: 'label color-label', style: "background:#{label_color};color:#{text_color}" do
+    content_tag :span, class: 'label color-label', style: "background-color:#{label_color};color:#{text_color}" do
       label.name
     end
   end
diff --git a/app/models/note.rb b/app/models/note.rb
index 39fe421fd7a..ccd9783e7d4 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -121,6 +121,36 @@ class Note < ActiveRecord::Base
       })
     end
 
+    def create_labels_change_note(noteable, project, author, added_labels, removed_labels)
+      labels_count = added_labels.count + removed_labels.count
+      added_labels = added_labels.map{ |label| "~#{label.id}" }.join(' ')
+      removed_labels = removed_labels.map{ |label| "~#{label.id}" }.join(' ')
+      message = ''
+
+      if added_labels.present?
+        message << "added #{added_labels}"
+      end
+
+      if added_labels.present? && removed_labels.present?
+        message << ' and '
+      end
+
+      if removed_labels.present?
+        message << "removed #{removed_labels}"
+      end
+
+      message << ' ' << 'label'.pluralize(labels_count)
+      body = "_#{message.capitalize}_"
+
+      create(
+        noteable: noteable,
+        project: project,
+        author: author,
+        note: body,
+        system: true
+      )
+    end
+
     def create_new_commits_note(noteable, project, author, commits)
       commits_text = ActionController::Base.helpers.pluralize(commits.size, 'new commit')
       body = "Added #{commits_text}:\n\n"
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index e3371ec3c1b..5e1906ad2ae 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -10,4 +10,9 @@ class IssuableBaseService < BaseService
     Note.create_milestone_change_note(
       issuable, issuable.project, current_user, issuable.milestone)
   end
+
+  def create_labels_note(issuable, added_labels, removed_labels)
+    Note.create_labels_change_note(
+      issuable, issuable.project, current_user, added_labels, removed_labels)
+  end
 end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 83e413d7248..c61d67a7893 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -14,10 +14,17 @@ module Issues
         issue.update_nth_task(params[:task_num].to_i, false)
       end
 
+      old_labels = issue.labels.to_a
+
       if params.present? && issue.update_attributes(params.except(:state_event,
                                                                   :task_num))
         issue.reset_events_cache
 
+        if issue.labels != old_labels
+          create_labels_note(
+            issue, issue.labels - old_labels, old_labels - issue.labels)
+        end
+
         if issue.previous_changes.include?('milestone_id')
           create_milestone_note(issue)
         end
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 10c401756eb..870b50bb60d 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -23,11 +23,21 @@ module MergeRequests
         merge_request.update_nth_task(params[:task_num].to_i, false)
       end
 
+      old_labels = merge_request.labels.to_a
+
       if params.present? && merge_request.update_attributes(
         params.except(:state_event, :task_num)
       )
         merge_request.reset_events_cache
 
+        if merge_request.labels != old_labels
+          create_labels_note(
+            merge_request,
+            merge_request.labels - old_labels,
+            old_labels - merge_request.labels
+          )
+        end
+
         if merge_request.previous_changes.include?('milestone_id')
           create_milestone_note(merge_request)
         end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 78627f413c2..fb0218a2778 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -92,7 +92,7 @@ module Gitlab
       allowed_tags = ActionView::Base.sanitized_allowed_tags
 
       sanitize text.html_safe,
-               attributes: allowed_attributes + %w(id class),
+               attributes: allowed_attributes + %w(id class style),
                tags: allowed_tags + %w(table tr td th)
     end
 
@@ -128,6 +128,7 @@ module Gitlab
       (?<prefix>\W)?                         # Prefix
       (                                      # Reference
          @(?<user>#{NAME_STR})               # User name
+        |~(?<label>\d+)                      # Label ID
         |(?<issue>([A-Z\-]+-)\d+)            # JIRA Issue ID
         |#{PROJ_STR}?\#(?<issue>([a-zA-Z\-]+-)?\d+) # Issue ID
         |#{PROJ_STR}?!(?<merge_request>\d+)  # MR ID
@@ -138,7 +139,7 @@ module Gitlab
       (?<suffix>\W)?                         # Suffix
     }x.freeze
 
-    TYPES = [:user, :issue, :merge_request, :snippet, :commit].freeze
+    TYPES = [:user, :issue, :label, :merge_request, :snippet, :commit].freeze
 
     def parse_references(text, project = @project)
       # parse reference links
@@ -214,6 +215,19 @@ module Gitlab
       end
     end
 
+    def reference_label(identifier, project = @project, _ = nil)
+      if label = project.labels.find_by(id: identifier)
+        options = html_options.merge(
+          class: "gfm gfm-label #{html_options[:class]}"
+        )
+        link_to(
+          render_colored_label(label),
+          project_issues_path(project, label_name: label.name),
+          options
+        )
+      end
+    end
+
     def reference_issue(identifier, project = @project, prefix_text = nil)
       if project.default_issues_tracker?
         if project.issue_exists? identifier
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 99165950aef..0b9177afa4f 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -1,12 +1,13 @@
 module Gitlab
   # Extract possible GFM references from an arbitrary String for further processing.
   class ReferenceExtractor
-    attr_accessor :users, :issues, :merge_requests, :snippets, :commits
+    attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits
 
     include Markdown
 
     def initialize
-      @users, @issues, @merge_requests, @snippets, @commits = [], [], [], [], []
+      @users, @labels, @issues, @merge_requests, @snippets, @commits =
+        [], [], [], [], [], []
     end
 
     def analyze(string, project)
@@ -22,6 +23,12 @@ module Gitlab
       end.reject(&:nil?)
     end
 
+    def labels_for(project = nil)
+      labels.map do |entry|
+        project.labels.where(id: entry[:id]).first
+      end.reject(&:nil?)
+    end
+
     def issues_for(project = nil)
       issues.map do |entry|
         if should_lookup?(project, entry[:project])
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 36030577835..964b3a707e4 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -5,6 +5,7 @@ describe Issues::UpdateService do
   let(:user) { create(:user) }
   let(:user2) { create(:user) }
   let(:issue) { create(:issue) }
+  let(:label) { create(:label) }
 
   before do
     project.team << [user, :master]
@@ -18,7 +19,8 @@ describe Issues::UpdateService do
           title: 'New title',
           description: 'Also please fix',
           assignee_id: user2.id,
-          state_event: 'close'
+          state_event: 'close',
+          label_ids: [label.id]
         }
 
         @issue = Issues::UpdateService.new(project, user, opts).execute(issue)
@@ -29,6 +31,8 @@ describe Issues::UpdateService do
       it { @issue.title.should == 'New title' }
       it { @issue.assignee.should == user2 }
       it { @issue.should be_closed }
+      it { @issue.labels.count.should == 1 }
+      it { @issue.labels.first.title.should == 'Bug' }
 
       it 'should send email to user2 about assign of new issue' do
         email = ActionMailer::Base.deliveries.last
@@ -40,6 +44,11 @@ describe Issues::UpdateService do
         note = @issue.notes.last
         note.note.should include "Reassigned to \@#{user2.username}"
       end
+
+      it 'should create system note about issue label edit' do
+        note = @issue.notes[1]
+        note.note.should include "Added ~#{label.id} label"
+      end
     end
   end
 end
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 0e60baae2c4..b27acb47711 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -5,6 +5,7 @@ describe MergeRequests::UpdateService do
   let(:user2) { create(:user) }
   let(:merge_request) { create(:merge_request, :simple) }
   let(:project) { merge_request.project }
+  let(:label) { create(:label) }
 
   before do
     project.team << [user, :master]
@@ -18,7 +19,8 @@ describe MergeRequests::UpdateService do
           title: 'New title',
           description: 'Also please fix',
           assignee_id: user2.id,
-          state_event: 'close'
+          state_event: 'close',
+          label_ids: [label.id]
         }
       end
 
@@ -35,6 +37,8 @@ describe MergeRequests::UpdateService do
       it { @merge_request.title.should == 'New title' }
       it { @merge_request.assignee.should == user2 }
       it { @merge_request.should be_closed }
+      it { @merge_request.labels.count.should == 1 }
+      it { @merge_request.labels.first.title.should == 'Bug' }
 
       it 'should execute hooks with update action' do
         expect(service).to have_received(:execute_hooks).
@@ -51,6 +55,11 @@ describe MergeRequests::UpdateService do
         note = @merge_request.notes.last
         note.note.should include "Reassigned to \@#{user2.username}"
       end
+
+      it 'should create system note about merge_request label edit' do
+        note = @merge_request.notes[1]
+        note.note.should include "Added ~#{label.id} label"
+      end
     end
   end
 end
-- 
GitLab