diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..57649693e7f8debe199aa0a0023d92b335f7fad9 --- /dev/null +++ b/app/helpers/notes_helper.rb @@ -0,0 +1,28 @@ +module NotesHelper + def note_with_commit_reference(project, note) + return '' unless note.note + out = '' + + note.note.split(/([0-9a-zA-Z]{6,52})/).each do |m| + if m =~ /^[0-9a-zA-Z]{6,52}$/ + begin + commit = project.commit(m) + out += "[#{m}](#{project_commit_path(project,:id => commit.id)})" + rescue + out += m + end + else + out += m + end + end + preserve out + end + + def build_reference_link(project, note) + return '' unless note.reference? + case note.reference_type + when "Commit" + then project_commit_path(project,:id => note.reference_id) + end + end +end \ No newline at end of file diff --git a/app/models/issue.rb b/app/models/issue.rb index 632e6537aade46f66d52fb989c091a8718f16c16..f1508225366044073a4c71a2fb45ad009715f0dd 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -3,7 +3,7 @@ class Issue < ActiveRecord::Base belongs_to :author, :class_name => "User" belongs_to :assignee, :class_name => "User" has_many :notes, :as => :noteable, :dependent => :destroy - + attr_protected :author, :author_id, :project, :project_id attr_accessor :author_id_of_changes @@ -50,6 +50,7 @@ class Issue < ActiveRecord::Base def upvotes notes.select(&:upvote?).size end + end # == Schema Information # diff --git a/app/models/note.rb b/app/models/note.rb index cee726ea0e511ec44e5f70c93efb732c6c9b93ff..4d9192a04d2e230aa015536ff4361c3491a19c17 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -4,6 +4,7 @@ require 'file_size_validator' class Note < ActiveRecord::Base belongs_to :project belongs_to :noteable, :polymorphic => true + belongs_to :reference, :polymorphic => true belongs_to :author, :class_name => "User" @@ -35,6 +36,7 @@ class Note < ActiveRecord::Base scope :fresh, order("created_at DESC") scope :inc_author_project, includes(:project, :author) scope :inc_author, includes(:author) + scope :from_commit, where(:reference_type => "Commit") mount_uploader :attachment, AttachmentUploader @@ -87,6 +89,14 @@ class Note < ActiveRecord::Base rescue nil end + + def reference? + !reference_type.nil? && !reference_id.nil? + end + + def from_commit? + reference? && reference_type == "Commit" + end # Returns true if this is an upvote note, # otherwise false is returned @@ -108,5 +118,7 @@ end # project_id :integer # attachment :string(255) # line_code :string(255) +# reference_id :string(255) +# reference_type:string(255) # diff --git a/app/models/project.rb b/app/models/project.rb index 8811176170ed5e179b3d95ed8c07a3feb2b90105..8dc005a03d67c028b0b04846b0a99539ec9a9c56 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -76,6 +76,25 @@ class Project < ActiveRecord::Base :author_id => data[:user_id] ) end + + def update_issues(oldrev, newrev, ref, author_key_id) + user = Key.find_by_identifier(author_key_id).user + commits = self.commits_between(oldrev, newrev) + commits.each do |commit| + commit.message.scan(/(closes|fixes)?\s#([0-9]+)/mi).each do |m| + begin + issue = self.issues.find(m.last) + unless issue.notes.from_commit.where(:reference_id => commit.id).any? + note = self.build_issue_commit_reference(commit,issue) + note.author = user + note.save + end + issue.update_attributes(:closed => true, :author_id_of_changes => user.id) unless m.first.nil? + end + end + end + true + end def update_merge_requests(oldrev, newrev, ref, author_key_id) return true unless ref =~ /heads/ @@ -173,6 +192,10 @@ class Project < ActiveRecord::Base def commit_line_notes(commit) notes.where(:noteable_id => commit.id, :noteable_type => "Commit").where("line_code is not null") end + + def build_issue_commit_reference(commit,issue) + notes.new(:noteable => issue, :note => commit.safe_message, :reference_type => "Commit", :reference_id => commit.id) + end def has_commits? !!commit diff --git a/app/views/notes/_notes_list.html.haml b/app/views/notes/_notes_list.html.haml index 1e4a6bb2b2fe5f173851bb5bfc05388ef0377f40..6deec24748fdd531a40ee5f3df5448ed57aacc30 100644 --- a/app/views/notes/_notes_list.html.haml +++ b/app/views/notes/_notes_list.html.haml @@ -1,4 +1,7 @@ - @notes.each do |note| - next unless note.author - = render :partial => "notes/show", :locals => {:note => note} + - if note.reference? + = render :partial => "notes/reference_show", :locals => {:note => note} + - else + = render :partial => "notes/show", :locals => {:note => note} diff --git a/app/views/notes/_reference_show.html.haml b/app/views/notes/_reference_show.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..69c84ac9c3b1849c70c2717165e147a40f12d146 --- /dev/null +++ b/app/views/notes/_reference_show.html.haml @@ -0,0 +1,14 @@ +%li{:id => dom_id(note), :class => "note"} + = image_tag gravatar_icon(note.author.email), :class => "left", :width => 40, :style => "padding-right:5px;" + %div.note-author + %strong= note.author_name + referenced this + = note.noteable_type.downcase + from a + = note.reference_type.downcase + %cite.cgray + = time_ago_in_words(note.updated_at) + ago + %div.note-title + = markdown("[#{note.note}](#{build_reference_link(@project, note)})") + .clear \ No newline at end of file diff --git a/app/views/notes/_show.html.haml b/app/views/notes/_show.html.haml index 6da1d5904bf0a88dd45d470b15185acf51703381..2dd9d11e33ca2b4c9adad29d0b9ed774c1043134 100644 --- a/app/views/notes/_show.html.haml +++ b/app/views/notes/_show.html.haml @@ -9,7 +9,7 @@ %strong= link_to "Remove", [@project, note], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-note btn small" %div.note-title - = markdown(note.note) + = markdown(note_with_commit_reference(@project, note)) - if note.attachment.url .right %span.file diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 28216ec33da9ae0da9e5a29335980dbb987cfccc..0fc1057211101107f9bb71471dd04ed2a1a54a00 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -14,6 +14,9 @@ class PostReceive # Close merged MR project.update_merge_requests(oldrev, newrev, ref, author_key_id) + # Close referenced Issues + project.update_issues(oldrev, newrev, ref, author_key_id) + # Execute web hooks project.execute_web_hooks(oldrev, newrev, ref, author_key_id) end diff --git a/db/migrate/20120331034342_add_references_to_note.rb b/db/migrate/20120331034342_add_references_to_note.rb new file mode 100644 index 0000000000000000000000000000000000000000..112ec2af01195167b0783859f9c0db44d0186cd9 --- /dev/null +++ b/db/migrate/20120331034342_add_references_to_note.rb @@ -0,0 +1,9 @@ +class AddReferencesToNote < ActiveRecord::Migration + def up + add_column :notes, :reference_id, :string + add_column :notes, :reference_type, :string + end + + def down + end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index c76fd9b5d98701753bc8ad26f15d70a6231e279e..329f385cc29ef825fc01ce12ac5517cd2ec9617c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -77,6 +77,8 @@ ActiveRecord::Schema.define(:version => 20120323221339) do t.integer "project_id" t.string "attachment" t.string "line_code" + t.string "reference_id" + t.string "reference_type" end add_index "notes", ["noteable_id"], :name => "index_notes_on_noteable_id" diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 1f8133e7ff77ea58bb6754c08d45bdf135aaf30c..649e095b8719f49cd794c8ad02a727456dc7cffe 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -188,6 +188,23 @@ describe Project do @merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" end end + + describe :update_issues do + let(:project) { Factory :project } + + before do + @issue = Factory :issue, + :project => project, + :closed => false + @key = Factory :key, :user_id => project.owner.id + @commit = project.commit(ValidCommit::ID) + end + + it "should close issue if issue id is in commit message" do + @commit.message = "closes ##{@issue.id}" + @issue.closed.should be_true + end + end end # == Schema Information #