Commit 664ff342 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'master' into ce-to-ee-2017-12-12

parents 84c5f4e0 89d7678f
...@@ -9,6 +9,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -9,6 +9,7 @@ class MergeRequest < ActiveRecord::Base
include ManualInverseAssociation include ManualInverseAssociation
include EachBatch include EachBatch
include ThrottledTouch include ThrottledTouch
include Gitlab::Utils::StrongMemoize
ignore_column :locked_at, ignore_column :locked_at,
:ref_fetched :ref_fetched
...@@ -56,6 +57,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -56,6 +57,7 @@ class MergeRequest < ActiveRecord::Base
serialize :merge_params, Hash # rubocop:disable Cop/ActiveRecordSerialize serialize :merge_params, Hash # rubocop:disable Cop/ActiveRecordSerialize
after_create :ensure_merge_request_diff, unless: :importing? after_create :ensure_merge_request_diff, unless: :importing?
after_update :clear_memoized_shas
after_update :reload_diff_if_branch_changed after_update :reload_diff_if_branch_changed
# When this attribute is true some MR validation is ignored # When this attribute is true some MR validation is ignored
...@@ -404,13 +406,17 @@ class MergeRequest < ActiveRecord::Base ...@@ -404,13 +406,17 @@ class MergeRequest < ActiveRecord::Base
end end
def source_branch_head def source_branch_head
return unless source_project strong_memoize(:source_branch_head) do
if source_project && source_branch_ref
source_project.repository.commit(source_branch_ref) if source_branch_ref source_project.repository.commit(source_branch_ref)
end
end
end end
def target_branch_head def target_branch_head
target_project.repository.commit(target_branch_ref) strong_memoize(:target_branch_head) do
target_project.repository.commit(target_branch_ref)
end
end end
def branch_merge_base_commit def branch_merge_base_commit
...@@ -558,6 +564,13 @@ class MergeRequest < ActiveRecord::Base ...@@ -558,6 +564,13 @@ class MergeRequest < ActiveRecord::Base
end end
end end
def clear_memoized_shas
@target_branch_sha = @source_branch_sha = nil
clear_memoization(:source_branch_head)
clear_memoization(:target_branch_head)
end
def reload_diff_if_branch_changed def reload_diff_if_branch_changed
if (source_branch_changed? || target_branch_changed?) && if (source_branch_changed? || target_branch_changed?) &&
(source_branch_head && target_branch_head) (source_branch_head && target_branch_head)
......
...@@ -104,19 +104,19 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -104,19 +104,19 @@ class MergeRequestDiff < ActiveRecord::Base
def base_commit def base_commit
return unless base_commit_sha return unless base_commit_sha
project.commit(base_commit_sha) project.commit_by(oid: base_commit_sha)
end end
def start_commit def start_commit
return unless start_commit_sha return unless start_commit_sha
project.commit(start_commit_sha) project.commit_by(oid: start_commit_sha)
end end
def head_commit def head_commit
return unless head_commit_sha return unless head_commit_sha
project.commit(head_commit_sha) project.commit_by(oid: head_commit_sha)
end end
def commit_shas def commit_shas
......
---
title: Cache commits for MergeRequest diffs
merge_request:
author:
type: performance
...@@ -51,6 +51,10 @@ module Gitlab ...@@ -51,6 +51,10 @@ module Gitlab
#{config.root}/ee/app/helpers #{config.root}/ee/app/helpers
]) ])
# Rake tasks ignore the eager loading settings, so we need to set the
# autoload paths explicitly
config.autoload_paths = config.eager_load_paths.dup
# Only load the plugins named here, in the order given (default is alphabetical). # Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named. # :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ] # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
......
...@@ -19,6 +19,8 @@ module Gitlab ...@@ -19,6 +19,8 @@ module Gitlab
commit_message: commit_message || default_commit_message commit_message: commit_message || default_commit_message
} }
resolver.resolve_conflicts(user, files, args) resolver.resolve_conflicts(user, files, args)
ensure
@merge_request.clear_memoized_shas
end end
def files def files
......
...@@ -11,6 +11,8 @@ module Gitlab ...@@ -11,6 +11,8 @@ module Gitlab
# #
# We could write it like: # We could write it like:
# #
# include Gitlab::Utils::StrongMemoize
#
# def trigger_from_token # def trigger_from_token
# strong_memoize(:trigger) do # strong_memoize(:trigger) do
# Ci::Trigger.find_by_token(params[:token].to_s) # Ci::Trigger.find_by_token(params[:token].to_s)
...@@ -18,14 +20,22 @@ module Gitlab ...@@ -18,14 +20,22 @@ module Gitlab
# end # end
# #
def strong_memoize(name) def strong_memoize(name)
ivar_name = "@#{name}" if instance_variable_defined?(ivar(name))
instance_variable_get(ivar(name))
if instance_variable_defined?(ivar_name)
instance_variable_get(ivar_name)
else else
instance_variable_set(ivar_name, yield) instance_variable_set(ivar(name), yield)
end end
end end
def clear_memoization(name)
remove_instance_variable(ivar(name)) if instance_variable_defined?(ivar(name))
end
private
def ivar(name)
"@#{name}"
end
end end
end end
end end
require 'gitlab/geo'
require 'gitlab/geo/database_tasks'
require 'gitlab/geo/geo_tasks'
task spec: ['geo:db:test:prepare'] task spec: ['geo:db:test:prepare']
namespace :geo do namespace :geo do
...@@ -9,12 +5,12 @@ namespace :geo do ...@@ -9,12 +5,12 @@ namespace :geo do
namespace :db do |ns| namespace :db do |ns|
desc 'Drops the Geo tracking database from config/database_geo.yml for the current RAILS_ENV.' desc 'Drops the Geo tracking database from config/database_geo.yml for the current RAILS_ENV.'
task :drop do task drop: [:environment] do
Gitlab::Geo::DatabaseTasks.drop_current Gitlab::Geo::DatabaseTasks.drop_current
end end
desc 'Creates the Geo tracking database from config/database_geo.yml for the current RAILS_ENV.' desc 'Creates the Geo tracking database from config/database_geo.yml for the current RAILS_ENV.'
task :create do task create: [:environment] do
Gitlab::Geo::DatabaseTasks.create_current Gitlab::Geo::DatabaseTasks.create_current
end end
...@@ -60,7 +56,7 @@ namespace :geo do ...@@ -60,7 +56,7 @@ namespace :geo do
end end
desc 'Refresh Foreign Tables definition in Geo Secondary node' desc 'Refresh Foreign Tables definition in Geo Secondary node'
task :refresh_foreign_tables do task refresh_foreign_tables: [:environment] do
if Gitlab::Geo::GeoTasks.foreign_server_configured? if Gitlab::Geo::GeoTasks.foreign_server_configured?
print "\nRefreshing foreign tables for FDW: #{Gitlab::Geo::FDW_SCHEMA} ... " print "\nRefreshing foreign tables for FDW: #{Gitlab::Geo::FDW_SCHEMA} ... "
Gitlab::Geo::GeoTasks.refresh_foreign_tables! Gitlab::Geo::GeoTasks.refresh_foreign_tables!
...@@ -72,7 +68,7 @@ namespace :geo do ...@@ -72,7 +68,7 @@ namespace :geo do
end end
# IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false # IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false
task :_dump do task _dump: [:environment] do
if Gitlab::Geo::DatabaseTasks.dump_schema_after_migration? if Gitlab::Geo::DatabaseTasks.dump_schema_after_migration?
ns["schema:dump"].invoke ns["schema:dump"].invoke
end end
...@@ -156,7 +152,7 @@ namespace :geo do ...@@ -156,7 +152,7 @@ namespace :geo do
Gitlab::Geo::DatabaseTasks::Test.purge Gitlab::Geo::DatabaseTasks::Test.purge
end end
task :refresh_foreign_tables do task refresh_foreign_tables: [:environment] do
old_env = ActiveRecord::Tasks::DatabaseTasks.env old_env = ActiveRecord::Tasks::DatabaseTasks.env
ActiveRecord::Tasks::DatabaseTasks.env = 'test' ActiveRecord::Tasks::DatabaseTasks.env = 'test'
......
...@@ -49,4 +49,16 @@ describe Gitlab::Utils::StrongMemoize do ...@@ -49,4 +49,16 @@ describe Gitlab::Utils::StrongMemoize do
end end
end end
end end
describe '#clear_memoization' do
let(:value) { 'mepmep' }
it 'removes the instance variable' do
object.method_name
object.clear_memoization(:method_name)
expect(object.instance_variable_defined?(:@method_name)).to be(false)
end
end
end end
...@@ -124,6 +124,7 @@ describe MergeRequest do ...@@ -124,6 +124,7 @@ describe MergeRequest do
context 'when the target branch does not exist' do context 'when the target branch does not exist' do
before do before do
project.repository.rm_branch(subject.author, subject.target_branch) project.repository.rm_branch(subject.author, subject.target_branch)
subject.clear_memoized_shas
end end
it 'returns nil' do it 'returns nil' do
...@@ -809,30 +810,30 @@ describe MergeRequest do ...@@ -809,30 +810,30 @@ describe MergeRequest do
end end
describe '#can_remove_source_branch?' do describe '#can_remove_source_branch?' do
let(:user) { create(:user) } set(:user) { create(:user) }
let(:user2) { create(:user) } set(:merge_request) { create(:merge_request, :simple) }
before do subject { merge_request }
subject.source_project.team << [user, :master]
subject.source_branch = "feature" before do
subject.target_branch = "master" subject.source_project.add_master(user)
subject.save!
end end
it "can't be removed when its a protected branch" do it "can't be removed when its a protected branch" do
allow(ProtectedBranch).to receive(:protected?).and_return(true) allow(ProtectedBranch).to receive(:protected?).and_return(true)
expect(subject.can_remove_source_branch?(user)).to be_falsey expect(subject.can_remove_source_branch?(user)).to be_falsey
end end
it "can't remove a root ref" do it "can't remove a root ref" do
subject.source_branch = "master" subject.update(source_branch: 'master', target_branch: 'feature')
subject.target_branch = "feature"
expect(subject.can_remove_source_branch?(user)).to be_falsey expect(subject.can_remove_source_branch?(user)).to be_falsey
end end
it "is unable to remove the source branch for a project the user cannot push to" do it "is unable to remove the source branch for a project the user cannot push to" do
user2 = create(:user)
expect(subject.can_remove_source_branch?(user2)).to be_falsey expect(subject.can_remove_source_branch?(user2)).to be_falsey
end end
...@@ -843,6 +844,7 @@ describe MergeRequest do ...@@ -843,6 +844,7 @@ describe MergeRequest do
end end
it "cannot be removed if the last commit is not also the head of the source branch" do it "cannot be removed if the last commit is not also the head of the source branch" do
subject.clear_memoized_shas
subject.source_branch = "lfs" subject.source_branch = "lfs"
expect(subject.can_remove_source_branch?(user)).to be_falsey expect(subject.can_remove_source_branch?(user)).to be_falsey
...@@ -942,7 +944,7 @@ describe MergeRequest do ...@@ -942,7 +944,7 @@ describe MergeRequest do
before do before do
project.repository.raw_repository.delete_branch(subject.target_branch) project.repository.raw_repository.delete_branch(subject.target_branch)
subject.reload subject.clear_memoized_shas
end end
it 'does not crash' do it 'does not crash' do
...@@ -1633,6 +1635,16 @@ describe MergeRequest do ...@@ -1633,6 +1635,16 @@ describe MergeRequest do
subject.reload_diff subject.reload_diff
end end
context 'when using the after_update hook to update' do
context 'when the branches are updated' do
it 'uses the new heads to generate the diff' do
expect { subject.update!(source_branch: subject.target_branch, target_branch: subject.source_branch) }
.to change { subject.merge_request_diff.start_commit_sha }
.and change { subject.merge_request_diff.head_commit_sha }
end
end
end
end end
describe '#update_diff_discussion_positions' do describe '#update_diff_discussion_positions' do
...@@ -1895,6 +1907,7 @@ describe MergeRequest do ...@@ -1895,6 +1907,7 @@ describe MergeRequest do
context 'when the target branch does not exist' do context 'when the target branch does not exist' do
before do before do
subject.project.repository.rm_branch(subject.author, subject.target_branch) subject.project.repository.rm_branch(subject.author, subject.target_branch)
subject.clear_memoized_shas
end end
it 'returns nil' do it 'returns nil' do
......
require 'spec_helper' require 'spec_helper'
describe MergeRequests::MergeService do describe MergeRequests::MergeService do
let(:user) { create(:user) } set(:user) { create(:user) }
let(:user2) { create(:user) } set(:user2) { create(:user) }
let(:merge_request) { create(:merge_request, :simple, author: user2, assignee: user2) } let(:merge_request) { create(:merge_request, :simple, author: user2, assignee: user2) }
let(:project) { merge_request.project } let(:project) { merge_request.project }
before do before do
project.team << [user, :master] project.add_master(user)
project.team << [user2, :developer] project.add_developer(user2)
end end
describe '#execute' do describe '#execute' do
......
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