Commit 5a3f23f3 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Persist Merge Request diff. Auto merge request close on push

parent 27e36998
...@@ -41,13 +41,12 @@ class MergeRequestsController < ApplicationController ...@@ -41,13 +41,12 @@ class MergeRequestsController < ApplicationController
@note = @project.notes.new(:noteable => @merge_request) @note = @project.notes.new(:noteable => @merge_request)
@commits = @project.repo. # Get commits from repository
commits_between(@merge_request.target_branch, @merge_request.source_branch). # or from cache if already merged
map {|c| Commit.new(c)}. @commits = @merge_request.commits
sort_by(&:created_at).
reverse
render_full_content # Close MR if nothing to merge
#@merge_request.mark_as_merged! if @merge_request.probably_merged?
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -76,6 +75,8 @@ class MergeRequestsController < ApplicationController ...@@ -76,6 +75,8 @@ class MergeRequestsController < ApplicationController
respond_to do |format| respond_to do |format|
if @merge_request.save if @merge_request.save
@merge_request.reloaded_commits
@merge_request.reloaded_diffs
format.html { redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.' } format.html { redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.' }
format.json { render json: @merge_request, status: :created, location: @merge_request } format.json { render json: @merge_request, status: :created, location: @merge_request }
else else
......
...@@ -7,6 +7,7 @@ class Event < ActiveRecord::Base ...@@ -7,6 +7,7 @@ class Event < ActiveRecord::Base
Reopened = 4 Reopened = 4
Pushed = 5 Pushed = 5
Commented = 6 Commented = 6
Merged = 7
belongs_to :project belongs_to :project
belongs_to :target, :polymorphic => true belongs_to :target, :polymorphic => true
......
require File.join(Rails.root, "app/models/commit")
class MergeRequest < ActiveRecord::Base class MergeRequest < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :author, :class_name => "User" belongs_to :author, :class_name => "User"
belongs_to :assignee, :class_name => "User" belongs_to :assignee, :class_name => "User"
has_many :notes, :as => :noteable, :dependent => :destroy has_many :notes, :as => :noteable, :dependent => :destroy
serialize :st_commits
serialize :st_diffs
attr_protected :author, :author_id, :project, :project_id attr_protected :author, :author_id, :project, :project_id
attr_accessor :author_id_of_changes attr_accessor :author_id_of_changes
...@@ -32,7 +37,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -32,7 +37,6 @@ class MergeRequest < ActiveRecord::Base
scope :closed, where(:closed => true) scope :closed, where(:closed => true)
scope :assigned, lambda { |u| where(:assignee_id => u.id)} scope :assigned, lambda { |u| where(:assignee_id => u.id)}
def validate_branches def validate_branches
if target_branch == source_branch if target_branch == source_branch
errors.add :base, "You can not use same branch for source and target branches" errors.add :base, "You can not use same branch for source and target branches"
...@@ -44,18 +48,65 @@ class MergeRequest < ActiveRecord::Base ...@@ -44,18 +48,65 @@ class MergeRequest < ActiveRecord::Base
end end
def diffs def diffs
st_diffs || []
end
def reloaded_diffs
if open? && unmerged_diffs.any?
self.st_diffs = unmerged_diffs
save
end
diffs
end
def unmerged_diffs
commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)}
diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue []
end end
def last_commit def last_commit
project.commit(source_branch) commits.first
end end
# Return the number of +1 comments (upvotes) # Return the number of +1 comments (upvotes)
def upvotes def upvotes
notes.select(&:upvote?).size notes.select(&:upvote?).size
end end
def commits
st_commits || []
end
def probably_merged?
unmerged_commits.empty? &&
commits.any? && open?
end
def open?
!closed
end
def mark_as_merged!
self.merged = true
self.closed = true
save
end
def reloaded_commits
if open? && unmerged_commits.any?
self.st_commits = unmerged_commits
save
end
commits
end
def unmerged_commits
self.project.repo.
commits_between(self.target_branch, self.source_branch).
map {|c| Commit.new(c)}.
sort_by(&:created_at).
reverse
end
end end
# == Schema Information # == Schema Information
# #
......
...@@ -73,6 +73,40 @@ class Project < ActiveRecord::Base ...@@ -73,6 +73,40 @@ class Project < ActiveRecord::Base
) )
end end
def update_merge_requests(oldrev, newrev, ref, author_key_id)
return true unless ref =~ /heads/
branch_name = ref.gsub("refs/heads/", "")
key = Key.find_by_identifier(author_key_id)
user = key.user
c_ids = self.commits_between(oldrev, newrev).map(&:id)
# update commits & diffs for existing MR
mrs = self.merge_requests.opened.where(:source_branch => branch_name).all
mrs.each do |merge_request|
merge_request.reloaded_commits
merge_request.reloaded_diffs
end
# Close merge requests
mrs = self.merge_requests.opened.where(:target_branch => branch_name).all
mrs.each do |merge_request|
next unless merge_request.last_commit
# Mark as merged & create event if merged
if c_ids.include?(merge_request.last_commit.id)
merge_request.mark_as_merged!
Event.create(
:project => self,
:action => Event::Merged,
:data => {:merge_request_id => merge_request.id},
:author_id => user.id
)
end
end
true
end
def execute_web_hooks(oldrev, newrev, ref, author_key_id) def execute_web_hooks(oldrev, newrev, ref, author_key_id)
ref_parts = ref.split('/') ref_parts = ref.split('/')
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
.ui-box .ui-box
%h5 Commits %h5 Commits
.merge-request-commits .merge-request-commits
%ul.unstyled= render @commits %ul.unstyled
- @commits.each do |commit|
= render "commits/commit", :commit => commit
- else - else
%h5 %h5
......
...@@ -11,9 +11,7 @@ ...@@ -11,9 +11,7 @@
%span.right %span.right
- if can?(current_user, :modify_merge_request, @merge_request) - if can?(current_user, :modify_merge_request, @merge_request)
- if @merge_request.closed - if @merge_request.open?
= link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "btn"
- else
= link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "btn", :title => "Close merge request" = link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "btn", :title => "Close merge request"
= link_to edit_project_merge_request_path(@project, @merge_request), :class => "btn" do = link_to edit_project_merge_request_path(@project, @merge_request), :class => "btn" do
Edit Edit
......
...@@ -8,7 +8,13 @@ class PostReceive ...@@ -8,7 +8,13 @@ class PostReceive
# Ignore push from non-gitlab users # Ignore push from non-gitlab users
return false unless Key.find_by_identifier(author_key_id) return false unless Key.find_by_identifier(author_key_id)
# Create push event
project.observe_push(oldrev, newrev, ref, author_key_id) project.observe_push(oldrev, newrev, ref, author_key_id)
# Close merged MR
project.update_merge_requests(oldrev, newrev, ref, author_key_id)
# Execute web hooks
project.execute_web_hooks(oldrev, newrev, ref, author_key_id) project.execute_web_hooks(oldrev, newrev, ref, author_key_id)
end end
end end
class AddCommitsDiffStoreToMergeRequest < ActiveRecord::Migration
def change
add_column :merge_requests, :st_commits, :text, :null => true
add_column :merge_requests, :st_diffs, :text, :null => true
end
end
class AddMergedToMergeRequest < ActiveRecord::Migration
def change
add_column :merge_requests, :merged, :true, :null => false, :default => false
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20120307095918) do ActiveRecord::Schema.define(:version => 20120315132931) do
create_table "events", :force => true do |t| create_table "events", :force => true do |t|
t.string "target_type" t.string "target_type"
...@@ -50,19 +50,8 @@ ActiveRecord::Schema.define(:version => 20120307095918) do ...@@ -50,19 +50,8 @@ ActiveRecord::Schema.define(:version => 20120307095918) do
t.integer "project_id" t.integer "project_id"
end end
create_table "merge_requests", :force => true do |t| # Could not dump table "merge_requests" because of following StandardError
t.string "target_branch", :null => false # Unknown type 'true' for column 'merged'
t.string "source_branch", :null => false
t.integer "project_id", :null => false
t.integer "author_id"
t.integer "assignee_id"
t.string "title"
t.boolean "closed", :default => false, :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id"
create_table "notes", :force => true do |t| create_table "notes", :force => true do |t|
t.text "note" t.text "note"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment