From a431ca0f8b7f8967e89a35caddf1e41e53eee290 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski <ayufan@ayufan.eu> Date: Wed, 2 Nov 2016 11:39:12 +0100 Subject: [PATCH 01/78] Don't execute git hooks if you create branch as part of other change Currently, our procedure for adding a commit requires us to execute `CreateBranchService` before file creation. It's OK, but also we do execute `git hooks` (the `PostReceive` sidekiq job) as part of this process. However, this hook is execute before the file is actually committed, so the ref is updated. Secondly, we do execute a `git hooks` after committing file and updating ref. This results in duplicate `PostReceive` jobs, where the first one is completely invalid. This change makes the branch creation, something that is intermediate step of bigger process (file creation or update, commit cherry pick or revert) to not execute git hooks. --- app/models/repository.rb | 8 ++++++-- app/services/commits/change_service.rb | 2 +- app/services/create_branch_service.rb | 4 ++-- app/services/files/base_service.rb | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 30be7262438..0776c7ccc5d 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -160,14 +160,18 @@ class Repository tags.find { |tag| tag.name == name } end - def add_branch(user, branch_name, target) + def add_branch(user, branch_name, target, with_hooks: true) oldrev = Gitlab::Git::BLANK_SHA ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name target = commit(target).try(:id) return false unless target - GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do + if with_hooks + GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do + update_ref!(ref, target, oldrev) + end + else update_ref!(ref, target, oldrev) end diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 1c82599c579..2d4c9788d02 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -55,7 +55,7 @@ module Commits return success if repository.find_branch(new_branch) result = CreateBranchService.new(@project, current_user) - .execute(new_branch, @target_branch, source_project: @source_project) + .execute(new_branch, @target_branch, source_project: @source_project, with_hooks: false) if result[:status] == :error raise ChangeError, "There was an error creating the source branch: #{result[:message]}" diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index 757fc35a78f..a6a3461e17b 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -1,7 +1,7 @@ require_relative 'base_service' class CreateBranchService < BaseService - def execute(branch_name, ref, source_project: @project) + def execute(branch_name, ref, source_project: @project, with_hooks: true) valid_branch = Gitlab::GitRefValidator.validate(branch_name) unless valid_branch @@ -26,7 +26,7 @@ class CreateBranchService < BaseService repository.find_branch(branch_name) else - repository.add_branch(current_user, branch_name, ref) + repository.add_branch(current_user, branch_name, ref, with_hooks: with_hooks) end if new_branch diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 9bd4bd464f7..1802b932e03 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -74,7 +74,7 @@ module Files end def create_target_branch - result = CreateBranchService.new(project, current_user).execute(@target_branch, @source_branch, source_project: @source_project) + result = CreateBranchService.new(project, current_user).execute(@target_branch, @source_branch, source_project: @source_project, with_hooks: false) unless result[:status] == :success raise_error("Something went wrong when we tried to create #{@target_branch} for you: #{result[:message]}") -- GitLab From 92aa402882cb9e2badc8213dd88913ad21b49857 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Sat, 5 Nov 2016 02:48:58 +0800 Subject: [PATCH 02/78] Add a test to make sure hooks are fire only once when updating a file to a different branch. --- spec/services/files/update_service_spec.rb | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb index d3c37c7820f..6fadee9304b 100644 --- a/spec/services/files/update_service_spec.rb +++ b/spec/services/files/update_service_spec.rb @@ -6,7 +6,10 @@ describe Files::UpdateService do let(:project) { create(:project) } let(:user) { create(:user) } let(:file_path) { 'files/ruby/popen.rb' } - let(:new_contents) { "New Content" } + let(:new_contents) { 'New Content' } + let(:target_branch) { project.default_branch } + let(:last_commit_sha) { nil } + let(:commit_params) do { file_path: file_path, @@ -16,7 +19,7 @@ describe Files::UpdateService do last_commit_sha: last_commit_sha, source_project: project, source_branch: project.default_branch, - target_branch: project.default_branch, + target_branch: target_branch } end @@ -54,18 +57,6 @@ describe Files::UpdateService do end context "when the last_commit_sha is not supplied" do - let(:commit_params) do - { - file_path: file_path, - commit_message: "Update File", - file_content: new_contents, - file_content_encoding: "text", - source_project: project, - source_branch: project.default_branch, - target_branch: project.default_branch, - } - end - it "returns a hash with the :success status " do results = subject.execute @@ -80,5 +71,15 @@ describe Files::UpdateService do expect(results.data).to eq(new_contents) end end + + context 'when target branch is different than source branch' do + let(:target_branch) { "#{project.default_branch}-new" } + + it 'fires hooks only once' do + expect(GitHooksService).to receive(:new).once.and_call_original + + subject.execute + end + end end end -- GitLab From 3128641f7eb93fec0930ebfb83a93dfa5e0b343a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 01:41:14 +0800 Subject: [PATCH 03/78] Revert "Don't execute git hooks if you create branch as part of other change" This reverts commit a431ca0f8b7f8967e89a35caddf1e41e53eee290. --- app/models/repository.rb | 8 ++------ app/services/commits/change_service.rb | 2 +- app/services/create_branch_service.rb | 4 ++-- app/services/files/base_service.rb | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index feaaacd02a9..063dc74021d 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -162,18 +162,14 @@ class Repository tags.find { |tag| tag.name == name } end - def add_branch(user, branch_name, target, with_hooks: true) + def add_branch(user, branch_name, target) oldrev = Gitlab::Git::BLANK_SHA ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name target = commit(target).try(:id) return false unless target - if with_hooks - GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do - update_ref!(ref, target, oldrev) - end - else + GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do update_ref!(ref, target, oldrev) end diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 2d4c9788d02..1c82599c579 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -55,7 +55,7 @@ module Commits return success if repository.find_branch(new_branch) result = CreateBranchService.new(@project, current_user) - .execute(new_branch, @target_branch, source_project: @source_project, with_hooks: false) + .execute(new_branch, @target_branch, source_project: @source_project) if result[:status] == :error raise ChangeError, "There was an error creating the source branch: #{result[:message]}" diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index a6a3461e17b..757fc35a78f 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -1,7 +1,7 @@ require_relative 'base_service' class CreateBranchService < BaseService - def execute(branch_name, ref, source_project: @project, with_hooks: true) + def execute(branch_name, ref, source_project: @project) valid_branch = Gitlab::GitRefValidator.validate(branch_name) unless valid_branch @@ -26,7 +26,7 @@ class CreateBranchService < BaseService repository.find_branch(branch_name) else - repository.add_branch(current_user, branch_name, ref, with_hooks: with_hooks) + repository.add_branch(current_user, branch_name, ref) end if new_branch diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 1802b932e03..9bd4bd464f7 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -74,7 +74,7 @@ module Files end def create_target_branch - result = CreateBranchService.new(project, current_user).execute(@target_branch, @source_branch, source_project: @source_project, with_hooks: false) + result = CreateBranchService.new(project, current_user).execute(@target_branch, @source_branch, source_project: @source_project) unless result[:status] == :success raise_error("Something went wrong when we tried to create #{@target_branch} for you: #{result[:message]}") -- GitLab From 0b5a2eef8fa5ff4976f97883b631ec28f0553f6a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 04:02:10 +0800 Subject: [PATCH 04/78] Add `source_branch` option for various git operations If `source_branch` option is passed, and target branch cannot be found, `Repository#update_branch_with_hooks` would try to create a new branch from `source_branch`. This way, we could make changes in the new branch while only firing the hooks once for the changes. Previously, we can only create a new branch first then make changes to the new branch, firing hooks twice. This behaviour is bad for CI. Fixes #7237 --- app/models/repository.rb | 98 +++++++++++++++------ app/services/commits/change_service.rb | 10 +-- app/services/create_branch_service.rb | 22 ++--- app/services/files/base_service.rb | 11 ++- app/services/files/create_dir_service.rb | 9 +- app/services/files/create_service.rb | 11 ++- app/services/files/delete_service.rb | 9 +- app/services/files/multi_service.rb | 3 +- app/services/files/update_service.rb | 3 +- app/services/validate_new_branch_service.rb | 22 +++++ 10 files changed, 145 insertions(+), 53 deletions(-) create mode 100644 app/services/validate_new_branch_service.rb diff --git a/app/models/repository.rb b/app/models/repository.rb index 063dc74021d..b6581486983 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -786,8 +786,12 @@ class Repository @root_ref ||= cache.fetch(:root_ref) { raw_repository.root_ref } end - def commit_dir(user, path, message, branch, author_email: nil, author_name: nil) - update_branch_with_hooks(user, branch) do |ref| + def commit_dir(user, path, message, branch, + author_email: nil, author_name: nil, source_branch: nil) + update_branch_with_hooks( + user, + branch, + source_branch: source_branch) do |ref| options = { commit: { branch: ref, @@ -802,8 +806,12 @@ class Repository end end - def commit_file(user, path, content, message, branch, update, author_email: nil, author_name: nil) - update_branch_with_hooks(user, branch) do |ref| + def commit_file(user, path, content, message, branch, update, + author_email: nil, author_name: nil, source_branch: nil) + update_branch_with_hooks( + user, + branch, + source_branch: source_branch) do |ref| options = { commit: { branch: ref, @@ -823,8 +831,13 @@ class Repository end end - def update_file(user, path, content, branch:, previous_path:, message:, author_email: nil, author_name: nil) - update_branch_with_hooks(user, branch) do |ref| + def update_file(user, path, content, + branch:, previous_path:, message:, + author_email: nil, author_name: nil, source_branch: nil) + update_branch_with_hooks( + user, + branch, + source_branch: source_branch) do |ref| options = { commit: { branch: ref, @@ -849,8 +862,12 @@ class Repository end end - def remove_file(user, path, message, branch, author_email: nil, author_name: nil) - update_branch_with_hooks(user, branch) do |ref| + def remove_file(user, path, message, branch, + author_email: nil, author_name: nil, source_branch: nil) + update_branch_with_hooks( + user, + branch, + source_branch: source_branch) do |ref| options = { commit: { branch: ref, @@ -868,17 +885,18 @@ class Repository end end - def multi_action(user:, branch:, message:, actions:, author_email: nil, author_name: nil) - update_branch_with_hooks(user, branch) do |ref| + def multi_action(user:, branch:, message:, actions:, + author_email: nil, author_name: nil, source_branch: nil) + update_branch_with_hooks( + user, + branch, + source_branch: source_branch) do |ref| index = rugged.index parents = [] - branch = find_branch(ref) - if branch - last_commit = branch.dereferenced_target - index.read_tree(last_commit.raw_commit.tree) - parents = [last_commit.sha] - end + last_commit = find_branch(ref).dereferenced_target + index.read_tree(last_commit.raw_commit.tree) + parents = [last_commit.sha] actions.each do |action| case action[:action] @@ -967,7 +985,10 @@ class Repository return false unless revert_tree_id - update_branch_with_hooks(user, base_branch) do + update_branch_with_hooks( + user, + base_branch, + source_branch: revert_tree_id) do committer = user_to_committer(user) source_sha = Rugged::Commit.create(rugged, message: commit.revert_message, @@ -984,7 +1005,10 @@ class Repository return false unless cherry_pick_tree_id - update_branch_with_hooks(user, base_branch) do + update_branch_with_hooks( + user, + base_branch, + source_branch: cherry_pick_tree_id) do committer = user_to_committer(user) source_sha = Rugged::Commit.create(rugged, message: commit.message, @@ -1082,11 +1106,11 @@ class Repository fetch_ref(path_to_repo, ref, ref_path) end - def update_branch_with_hooks(current_user, branch) + def update_branch_with_hooks(current_user, branch, source_branch: nil) update_autocrlf_option ref = Gitlab::Git::BRANCH_REF_PREFIX + branch - target_branch = find_branch(branch) + target_branch, new_branch_added = raw_ensure_branch(branch, source_branch) was_empty = empty? # Make commit @@ -1096,7 +1120,7 @@ class Repository raise CommitError.new('Failed to create commit') end - if rugged.lookup(newrev).parent_ids.empty? || target_branch.nil? + if rugged.lookup(newrev).parent_ids.empty? oldrev = Gitlab::Git::BLANK_SHA else oldrev = rugged.merge_base(newrev, target_branch.dereferenced_target.sha) @@ -1105,11 +1129,9 @@ class Repository GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do update_ref!(ref, newrev, oldrev) - if was_empty || !target_branch - # If repo was empty expire cache - after_create if was_empty - after_create_branch - end + # If repo was empty expire cache + after_create if was_empty + after_create_branch if was_empty || new_branch_added end newrev @@ -1169,4 +1191,28 @@ class Repository def repository_event(event, tags = {}) Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags)) end + + def raw_ensure_branch(branch_name, source_branch) + old_branch = find_branch(branch_name) + + if old_branch + [old_branch, false] + elsif source_branch + oldrev = Gitlab::Git::BLANK_SHA + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name + target = commit(source_branch).try(:id) + + unless target + raise CommitError.new( + "Cannot find branch #{branch_name} nor #{source_branch}") + end + + update_ref!(ref, target, oldrev) + + [find_branch(branch_name), true] + else + raise CommitError.new( + "Cannot find branch #{branch_name} and source_branch is not set") + end + end end diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 1c82599c579..04b28cfaed8 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -29,7 +29,7 @@ module Commits tree_id = repository.public_send("check_#{action}_content", @commit, @target_branch) if tree_id - create_target_branch(into) if @create_merge_request + validate_target_branch(into) if @create_merge_request repository.public_send(action, current_user, @commit, into, tree_id) success @@ -50,12 +50,12 @@ module Commits true end - def create_target_branch(new_branch) + def validate_target_branch(new_branch) # Temporary branch exists and contains the change commit - return success if repository.find_branch(new_branch) + return if repository.find_branch(new_branch) - result = CreateBranchService.new(@project, current_user) - .execute(new_branch, @target_branch, source_project: @source_project) + result = ValidateNewBranchService.new(@project, current_user). + execute(new_branch) if result[:status] == :error raise ChangeError, "There was an error creating the source branch: #{result[:message]}" diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index 757fc35a78f..f4270a09928 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -2,18 +2,9 @@ require_relative 'base_service' class CreateBranchService < BaseService def execute(branch_name, ref, source_project: @project) - valid_branch = Gitlab::GitRefValidator.validate(branch_name) + failure = validate_new_branch(branch_name) - unless valid_branch - return error('Branch name is invalid') - end - - repository = project.repository - existing_branch = repository.find_branch(branch_name) - - if existing_branch - return error('Branch already exists') - end + return failure if failure new_branch = if source_project != @project repository.fetch_ref( @@ -41,4 +32,13 @@ class CreateBranchService < BaseService def success(branch) super().merge(branch: branch) end + + private + + def validate_new_branch(branch_name) + result = ValidateNewBranchService.new(project, current_user). + execute(branch_name) + + error(result[:message]) if result[:status] == :error + end end diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 9bd4bd464f7..6779bd2818a 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -23,9 +23,7 @@ module Files validate # Create new branch if it different from source_branch - if different_branch? - create_target_branch - end + validate_target_branch if different_branch? result = commit if result @@ -73,10 +71,11 @@ module Files end end - def create_target_branch - result = CreateBranchService.new(project, current_user).execute(@target_branch, @source_branch, source_project: @source_project) + def validate_target_branch + result = ValidateNewBranchService.new(project, current_user). + execute(@target_branch) - unless result[:status] == :success + if result[:status] == :error raise_error("Something went wrong when we tried to create #{@target_branch} for you: #{result[:message]}") end end diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb index d00d78cee7e..c59b3f8c70c 100644 --- a/app/services/files/create_dir_service.rb +++ b/app/services/files/create_dir_service.rb @@ -3,7 +3,14 @@ require_relative "base_service" module Files class CreateDirService < Files::BaseService def commit - repository.commit_dir(current_user, @file_path, @commit_message, @target_branch, author_email: @author_email, author_name: @author_name) + repository.commit_dir( + current_user, + @file_path, + @commit_message, + @target_branch, + author_email: @author_email, + author_name: @author_name, + source_branch: @source_branch) end def validate diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index bf127843d55..6d0a0f2629d 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -3,7 +3,16 @@ require_relative "base_service" module Files class CreateService < Files::BaseService def commit - repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch, false, author_email: @author_email, author_name: @author_name) + repository.commit_file( + current_user, + @file_path, + @file_content, + @commit_message, + @target_branch, + false, + author_email: @author_email, + author_name: @author_name, + source_branch: @source_branch) end def validate diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb index 8b27ad51789..79d592731e9 100644 --- a/app/services/files/delete_service.rb +++ b/app/services/files/delete_service.rb @@ -3,7 +3,14 @@ require_relative "base_service" module Files class DeleteService < Files::BaseService def commit - repository.remove_file(current_user, @file_path, @commit_message, @target_branch, author_email: @author_email, author_name: @author_name) + repository.remove_file( + current_user, + @file_path, + @commit_message, + @target_branch, + author_email: @author_email, + author_name: @author_name, + source_branch: @source_branch) end end end diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb index d28912e1301..0550dec15a6 100644 --- a/app/services/files/multi_service.rb +++ b/app/services/files/multi_service.rb @@ -11,7 +11,8 @@ module Files message: @commit_message, actions: params[:actions], author_email: @author_email, - author_name: @author_name + author_name: @author_name, + source_branch: @source_branch ) end diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index c17fdb8d1f1..f3a766ed9fd 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -10,7 +10,8 @@ module Files previous_path: @previous_path, message: @commit_message, author_email: @author_email, - author_name: @author_name) + author_name: @author_name, + source_branch: @source_branch) end private diff --git a/app/services/validate_new_branch_service.rb b/app/services/validate_new_branch_service.rb new file mode 100644 index 00000000000..2f61be184ce --- /dev/null +++ b/app/services/validate_new_branch_service.rb @@ -0,0 +1,22 @@ +require_relative 'base_service' + +class ValidateNewBranchService < BaseService + def execute(branch_name) + valid_branch = Gitlab::GitRefValidator.validate(branch_name) + + unless valid_branch + return error('Branch name is invalid') + end + + repository = project.repository + existing_branch = repository.find_branch(branch_name) + + if existing_branch + return error('Branch already exists') + end + + success + rescue GitHooksService::PreReceiveError => ex + error(ex.message) + end +end -- GitLab From 92a438263fafdd7c4163f09e63815dc805cb8d12 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 04:27:21 +0800 Subject: [PATCH 05/78] Fix issues found by rubocop --- app/models/repository.rb | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index b6581486983..beafe9060bf 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -786,7 +786,8 @@ class Repository @root_ref ||= cache.fetch(:root_ref) { raw_repository.root_ref } end - def commit_dir(user, path, message, branch, + def commit_dir( + user, path, message, branch, author_email: nil, author_name: nil, source_branch: nil) update_branch_with_hooks( user, @@ -806,7 +807,9 @@ class Repository end end - def commit_file(user, path, content, message, branch, update, + # rubocop:disable Metrics/ParameterLists + def commit_file( + user, path, content, message, branch, update, author_email: nil, author_name: nil, source_branch: nil) update_branch_with_hooks( user, @@ -830,8 +833,11 @@ class Repository Gitlab::Git::Blob.commit(raw_repository, options) end end + # rubocop:enable Metrics/ParameterLists - def update_file(user, path, content, + # rubocop:disable Metrics/ParameterLists + def update_file( + user, path, content, branch:, previous_path:, message:, author_email: nil, author_name: nil, source_branch: nil) update_branch_with_hooks( @@ -861,8 +867,10 @@ class Repository end end end + # rubocop:enable Metrics/ParameterLists - def remove_file(user, path, message, branch, + def remove_file( + user, path, message, branch, author_email: nil, author_name: nil, source_branch: nil) update_branch_with_hooks( user, @@ -885,14 +893,14 @@ class Repository end end - def multi_action(user:, branch:, message:, actions:, + def multi_action( + user:, branch:, message:, actions:, author_email: nil, author_name: nil, source_branch: nil) update_branch_with_hooks( user, branch, source_branch: source_branch) do |ref| index = rugged.index - parents = [] last_commit = find_branch(ref).dereferenced_target index.read_tree(last_commit.raw_commit.tree) -- GitLab From 8fca786bdee6fa23a5e000bf23e65b153fc1bf73 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 04:46:54 +0800 Subject: [PATCH 06/78] They're never referred --- app/models/repository.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index beafe9060bf..b2b5d528840 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -998,7 +998,7 @@ class Repository base_branch, source_branch: revert_tree_id) do committer = user_to_committer(user) - source_sha = Rugged::Commit.create(rugged, + Rugged::Commit.create(rugged, message: commit.revert_message, author: committer, committer: committer, @@ -1018,7 +1018,7 @@ class Repository base_branch, source_branch: cherry_pick_tree_id) do committer = user_to_committer(user) - source_sha = Rugged::Commit.create(rugged, + Rugged::Commit.create(rugged, message: commit.message, author: { email: commit.author_email, -- GitLab From 30d7b5c32cfb97d7c1e57fb8874069077097c89d Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 05:29:24 +0800 Subject: [PATCH 07/78] Fix the case when it's a whole new branch --- app/models/repository.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index b2b5d528840..5e7bb309967 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1128,7 +1128,7 @@ class Repository raise CommitError.new('Failed to create commit') end - if rugged.lookup(newrev).parent_ids.empty? + if rugged.lookup(newrev).parent_ids.empty? || target_branch.nil? oldrev = Gitlab::Git::BLANK_SHA else oldrev = rugged.merge_base(newrev, target_branch.dereferenced_target.sha) @@ -1219,8 +1219,7 @@ class Repository [find_branch(branch_name), true] else - raise CommitError.new( - "Cannot find branch #{branch_name} and source_branch is not set") + [nil, true] # Empty branch end end end -- GitLab From eddee5fe8770d79c80fdb0d91731f866c14c9b8d Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 06:01:54 +0800 Subject: [PATCH 08/78] Make sure we create target branch for cherry/revert --- app/models/repository.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 5e7bb309967..0f3e98db420 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -988,7 +988,8 @@ class Repository end def revert(user, commit, base_branch, revert_tree_id = nil) - source_sha = find_branch(base_branch).dereferenced_target.sha + source_sha = raw_ensure_branch(base_branch, source_commit: commit). + first.dereferenced_target.sha revert_tree_id ||= check_revert_content(commit, base_branch) return false unless revert_tree_id @@ -1008,7 +1009,8 @@ class Repository end def cherry_pick(user, commit, base_branch, cherry_pick_tree_id = nil) - source_sha = find_branch(base_branch).dereferenced_target.sha + source_sha = raw_ensure_branch(base_branch, source_commit: commit). + first.dereferenced_target.sha cherry_pick_tree_id ||= check_cherry_pick_content(commit, base_branch) return false unless cherry_pick_tree_id @@ -1118,7 +1120,8 @@ class Repository update_autocrlf_option ref = Gitlab::Git::BRANCH_REF_PREFIX + branch - target_branch, new_branch_added = raw_ensure_branch(branch, source_branch) + target_branch, new_branch_added = + raw_ensure_branch(branch, source_branch: source_branch) was_empty = empty? # Make commit @@ -1200,19 +1203,19 @@ class Repository Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags)) end - def raw_ensure_branch(branch_name, source_branch) + def raw_ensure_branch(branch_name, source_commit: nil, source_branch: nil) old_branch = find_branch(branch_name) if old_branch [old_branch, false] - elsif source_branch + elsif source_commit || source_branch oldrev = Gitlab::Git::BLANK_SHA ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name - target = commit(source_branch).try(:id) + target = (source_commit || commit(source_branch)).try(:sha) unless target raise CommitError.new( - "Cannot find branch #{branch_name} nor #{source_branch}") + "Cannot find branch #{branch_name} nor #{source_commit.try(:sha) ||source_branch}") end update_ref!(ref, target, oldrev) -- GitLab From 30bcc3de41d86e02c27940e0e8e4a1a82183520e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 06:18:24 +0800 Subject: [PATCH 09/78] Add missing space due to Sublime Text It's Sublime Text's fault. Its word wrapping is not code friendly --- app/models/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 0f3e98db420..89293fa8b4d 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1215,7 +1215,7 @@ class Repository unless target raise CommitError.new( - "Cannot find branch #{branch_name} nor #{source_commit.try(:sha) ||source_branch}") + "Cannot find branch #{branch_name} nor #{source_commit.try(:sha) || source_branch}") end update_ref!(ref, target, oldrev) -- GitLab From 5de74551ace7b6df9fdb2a3c8aa30c836d693728 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 06:55:54 +0800 Subject: [PATCH 10/78] Branch could be nil if it's an empty repo --- app/models/repository.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 89293fa8b4d..c4bdc84348e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -901,10 +901,15 @@ class Repository branch, source_branch: source_branch) do |ref| index = rugged.index - - last_commit = find_branch(ref).dereferenced_target - index.read_tree(last_commit.raw_commit.tree) - parents = [last_commit.sha] + branch_commit = find_branch(ref) + + parents = if branch_commit + last_commit = branch_commit.dereferenced_target + index.read_tree(last_commit.raw_commit.tree) + [last_commit.sha] + else + [] + end actions.each do |action| case action[:action] -- GitLab From d8fe2fac7e681ddbff3c7a5338f939eb2d540e38 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 07:22:50 +0800 Subject: [PATCH 11/78] Make sure we have the branch on the other project --- app/models/project.rb | 11 +++++++++++ app/services/create_branch_service.rb | 10 +--------- app/services/files/base_service.rb | 10 +++++++++- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 94aabafce20..1208e5da6fa 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -988,6 +988,17 @@ class Project < ActiveRecord::Base Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.path) end + def fetch_ref(source_project, branch_name, ref) + repository.fetch_ref( + source_project.repository.path_to_repo, + "refs/heads/#{ref}", + "refs/heads/#{branch_name}" + ) + + repository.after_create_branch + repository.find_branch(branch_name) + end + # Expires various caches before a project is renamed. def expire_caches_before_rename(old_path) repo = Repository.new(old_path, self) diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index f4270a09928..ecb5994fab8 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -7,15 +7,7 @@ class CreateBranchService < BaseService return failure if failure new_branch = if source_project != @project - repository.fetch_ref( - source_project.repository.path_to_repo, - "refs/heads/#{ref}", - "refs/heads/#{branch_name}" - ) - - repository.after_create_branch - - repository.find_branch(branch_name) + @project.fetch_ref(source_project, branch_name, ref) else repository.add_branch(current_user, branch_name, ref) end diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 6779bd2818a..fd62246eddb 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -23,7 +23,7 @@ module Files validate # Create new branch if it different from source_branch - validate_target_branch if different_branch? + ensure_target_branch if different_branch? result = commit if result @@ -71,6 +71,14 @@ module Files end end + def ensure_target_branch + validate_target_branch + + if @source_project != project + @project.fetch_ref(@source_project, @target_branch, @source_branch) + end + end + def validate_target_branch result = ValidateNewBranchService.new(project, current_user). execute(@target_branch) -- GitLab From a68a62011d03c15d6116dc1e6dcb9514040a51f5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 07:53:36 +0800 Subject: [PATCH 12/78] Don't pass source_branch if it doesn't exist --- app/controllers/concerns/creates_commit.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index dacb5679dd3..643b61af1b2 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,9 +4,10 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables + source_branch = @ref if @repository.find_branch(@ref) commit_params = @commit_params.merge( source_project: @project, - source_branch: @ref, + source_branch: source_branch, target_branch: @target_branch ) -- GitLab From 39d83f72e7af78d503ef278e22eda25f90322f4b Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 08:10:32 +0800 Subject: [PATCH 13/78] Add a few comments to explain implementation detail --- app/models/repository.rb | 2 ++ app/services/files/base_service.rb | 3 +++ 2 files changed, 5 insertions(+) diff --git a/app/models/repository.rb b/app/models/repository.rb index c4bdc84348e..4e3e70192ab 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1121,6 +1121,8 @@ class Repository fetch_ref(path_to_repo, ref, ref_path) end + # Whenever `source_branch` is passed, if `branch` doesn't exist, it would + # be created from `source_branch`. def update_branch_with_hooks(current_user, branch, source_branch: nil) update_autocrlf_option diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index fd62246eddb..8689c83d40e 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -75,6 +75,9 @@ module Files validate_target_branch if @source_project != project + # Make sure we have the source_branch in target project, + # and use source_branch as target_branch directly to avoid + # unnecessary source branch in target project. @project.fetch_ref(@source_project, @target_branch, @source_branch) end end -- GitLab From cd22fdd531c151cf1bbc307e52c565e86070fe3b Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 08:21:16 +0800 Subject: [PATCH 14/78] @ref might not exist --- app/controllers/concerns/creates_commit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 643b61af1b2..5d11f286e9a 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,7 +4,7 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - source_branch = @ref if @repository.find_branch(@ref) + source_branch = @ref if @ref && @repository.find_branch(@ref) commit_params = @commit_params.merge( source_project: @project, source_branch: source_branch, -- GitLab From 3e69c716f0b81b2c3b863d3c8a5e6346b9978fc1 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 15 Nov 2016 20:03:18 +0800 Subject: [PATCH 15/78] Try if branch_exists? would work, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_18424135 --- app/controllers/concerns/creates_commit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 5d11f286e9a..e5c40446314 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,7 +4,7 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - source_branch = @ref if @ref && @repository.find_branch(@ref) + source_branch = @ref if @ref && @repository.branch_exists?(@ref) commit_params = @commit_params.merge( source_project: @project, source_branch: source_branch, -- GitLab From b82f415f09dd67da010a8c08397a13499e70efeb Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 22 Nov 2016 18:14:41 +0800 Subject: [PATCH 16/78] Move all branch creation to raw_ensure_branch, and keep it only called in update_branch_with_hooks. --- app/models/project.rb | 11 ---- app/models/repository.rb | 85 ++++++++++++++++++++------- app/services/create_branch_service.rb | 8 +-- app/services/files/base_service.rb | 13 +--- app/services/files/update_service.rb | 1 + 5 files changed, 69 insertions(+), 49 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 5346e18b051..f8a54324341 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -998,17 +998,6 @@ class Project < ActiveRecord::Base Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.path) end - def fetch_ref(source_project, branch_name, ref) - repository.fetch_ref( - source_project.repository.path_to_repo, - "refs/heads/#{ref}", - "refs/heads/#{branch_name}" - ) - - repository.after_create_branch - repository.find_branch(branch_name) - end - # Expires various caches before a project is renamed. def expire_caches_before_rename(old_path) repo = Repository.new(old_path, self) diff --git a/app/models/repository.rb b/app/models/repository.rb index a029993db7f..9162f494a60 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -784,13 +784,16 @@ class Repository @tags ||= raw_repository.tags end + # rubocop:disable Metrics/ParameterLists def commit_dir( user, path, message, branch, - author_email: nil, author_name: nil, source_branch: nil) + author_email: nil, author_name: nil, + source_branch: nil, source_project: project) update_branch_with_hooks( user, branch, - source_branch: source_branch) do |ref| + source_branch: source_branch, + source_project: source_project) do |ref| options = { commit: { branch: ref, @@ -804,15 +807,18 @@ class Repository raw_repository.mkdir(path, options) end end + # rubocop:enable Metrics/ParameterLists # rubocop:disable Metrics/ParameterLists def commit_file( user, path, content, message, branch, update, - author_email: nil, author_name: nil, source_branch: nil) + author_email: nil, author_name: nil, + source_branch: nil, source_project: project) update_branch_with_hooks( user, branch, - source_branch: source_branch) do |ref| + source_branch: source_branch, + source_project: source_project) do |ref| options = { commit: { branch: ref, @@ -837,11 +843,13 @@ class Repository def update_file( user, path, content, branch:, previous_path:, message:, - author_email: nil, author_name: nil, source_branch: nil) + author_email: nil, author_name: nil, + source_branch: nil, source_project: project) update_branch_with_hooks( user, branch, - source_branch: source_branch) do |ref| + source_branch: source_branch, + source_project: source_project) do |ref| options = { commit: { branch: ref, @@ -867,13 +875,16 @@ class Repository end # rubocop:enable Metrics/ParameterLists + # rubocop:disable Metrics/ParameterLists def remove_file( user, path, message, branch, - author_email: nil, author_name: nil, source_branch: nil) + author_email: nil, author_name: nil, + source_branch: nil, source_project: project) update_branch_with_hooks( user, branch, - source_branch: source_branch) do |ref| + source_branch: source_branch, + source_project: source_project) do |ref| options = { commit: { branch: ref, @@ -890,14 +901,18 @@ class Repository Gitlab::Git::Blob.remove(raw_repository, options) end end + # rubocop:enable Metrics/ParameterLists + # rubocop:disable Metrics/ParameterLists def multi_action( user:, branch:, message:, actions:, - author_email: nil, author_name: nil, source_branch: nil) + author_email: nil, author_name: nil, + source_branch: nil, source_project: project) update_branch_with_hooks( user, branch, - source_branch: source_branch) do |ref| + source_branch: source_branch, + source_project: source_project) do |ref| index = rugged.index branch_commit = find_branch(ref) @@ -942,6 +957,7 @@ class Repository Rugged::Commit.create(rugged, options) end end + # rubocop:enable Metrics/ParameterLists def get_committer_and_author(user, email: nil, name: nil) committer = user_to_committer(user) @@ -991,8 +1007,6 @@ class Repository end def revert(user, commit, base_branch, revert_tree_id = nil) - source_sha = raw_ensure_branch(base_branch, source_commit: commit). - first.dereferenced_target.sha revert_tree_id ||= check_revert_content(commit, base_branch) return false unless revert_tree_id @@ -1000,8 +1014,11 @@ class Repository update_branch_with_hooks( user, base_branch, - source_branch: revert_tree_id) do + source_commit: commit) do + + source_sha = find_branch(base_branch).dereferenced_target.sha committer = user_to_committer(user) + Rugged::Commit.create(rugged, message: commit.revert_message, author: committer, @@ -1012,8 +1029,6 @@ class Repository end def cherry_pick(user, commit, base_branch, cherry_pick_tree_id = nil) - source_sha = raw_ensure_branch(base_branch, source_commit: commit). - first.dereferenced_target.sha cherry_pick_tree_id ||= check_cherry_pick_content(commit, base_branch) return false unless cherry_pick_tree_id @@ -1021,8 +1036,11 @@ class Repository update_branch_with_hooks( user, base_branch, - source_branch: cherry_pick_tree_id) do + source_commit: commit) do + + source_sha = find_branch(base_branch).dereferenced_target.sha committer = user_to_committer(user) + Rugged::Commit.create(rugged, message: commit.message, author: { @@ -1130,12 +1148,19 @@ class Repository # Whenever `source_branch` is passed, if `branch` doesn't exist, it would # be created from `source_branch`. - def update_branch_with_hooks(current_user, branch, source_branch: nil) + def update_branch_with_hooks( + current_user, branch, + source_branch: nil, source_commit: nil, source_project: project) update_autocrlf_option - ref = Gitlab::Git::BRANCH_REF_PREFIX + branch target_branch, new_branch_added = - raw_ensure_branch(branch, source_branch: source_branch) + raw_ensure_branch( + branch, + source_branch: source_branch, + source_project: source_project + ) + + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch was_empty = empty? # Make commit @@ -1244,11 +1269,31 @@ class Repository Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags)) end - def raw_ensure_branch(branch_name, source_commit: nil, source_branch: nil) + def raw_ensure_branch( + branch_name, source_commit: nil, source_branch: nil, source_project: nil) old_branch = find_branch(branch_name) + if source_commit && source_branch + raise ArgumentError, + 'Should only pass either :source_branch or :source_commit, not both' + end + if old_branch [old_branch, false] + elsif project != source_project + unless source_branch + raise ArgumentError, + 'Should also pass :source_branch if' + + ' :source_project is different from current project' + end + + fetch_ref( + source_project.repository.path_to_repo, + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch}", + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch}" + ) + + [find_branch(branch_name), true] elsif source_commit || source_branch oldrev = Gitlab::Git::BLANK_SHA ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index ecb5994fab8..b2bc3626c0f 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -1,16 +1,12 @@ require_relative 'base_service' class CreateBranchService < BaseService - def execute(branch_name, ref, source_project: @project) + def execute(branch_name, ref) failure = validate_new_branch(branch_name) return failure if failure - new_branch = if source_project != @project - @project.fetch_ref(source_project, branch_name, ref) - else - repository.add_branch(current_user, branch_name, ref) - end + new_branch = repository.add_branch(current_user, branch_name, ref) if new_branch success(new_branch) diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 8689c83d40e..6779bd2818a 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -23,7 +23,7 @@ module Files validate # Create new branch if it different from source_branch - ensure_target_branch if different_branch? + validate_target_branch if different_branch? result = commit if result @@ -71,17 +71,6 @@ module Files end end - def ensure_target_branch - validate_target_branch - - if @source_project != project - # Make sure we have the source_branch in target project, - # and use source_branch as target_branch directly to avoid - # unnecessary source branch in target project. - @project.fetch_ref(@source_project, @target_branch, @source_branch) - end - end - def validate_target_branch result = ValidateNewBranchService.new(project, current_user). execute(@target_branch) diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index f3a766ed9fd..14e5af4d8c6 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -11,6 +11,7 @@ module Files message: @commit_message, author_email: @author_email, author_name: @author_name, + source_project: @source_project, source_branch: @source_branch) end -- GitLab From 6cd2256c84c9a785a6b15864ab170084fdebf45f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 24 Nov 2016 17:56:26 +0800 Subject: [PATCH 17/78] Should also pass source_commit to raw_ensure_branch --- app/models/repository.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/repository.rb b/app/models/repository.rb index 9162f494a60..276d8829873 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1157,6 +1157,7 @@ class Repository raw_ensure_branch( branch, source_branch: source_branch, + source_commit: source_commit, source_project: source_project ) -- GitLab From e866985be81f54002667117e03dae6680829a462 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 24 Nov 2016 23:35:28 +0800 Subject: [PATCH 18/78] Fix local name from branch to branch_name --- app/models/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 276d8829873..6abe498ebde 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1291,7 +1291,7 @@ class Repository fetch_ref( source_project.repository.path_to_repo, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch}", - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch}" + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch_name}" ) [find_branch(branch_name), true] -- GitLab From c916f293cecf3d112f0338aec0a9dc9e3577f17e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 25 Nov 2016 15:07:27 +0800 Subject: [PATCH 19/78] Add some explanation to Repository#update_branch_with_hooks --- app/models/repository.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 6abe498ebde..09e8cc060c7 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1146,8 +1146,11 @@ class Repository fetch_ref(path_to_repo, ref, ref_path) end - # Whenever `source_branch` is passed, if `branch` doesn't exist, it would - # be created from `source_branch`. + # Whenever `source_branch` or `source_commit` is passed, if `branch` + # doesn't exist, it would be created from `source_branch` or + # `source_commit`. Should only pass one of them, not both. + # If `source_project` is passed, and the branch doesn't exist, + # it would try to find the source from it instead of current repository. def update_branch_with_hooks( current_user, branch, source_branch: nil, source_commit: nil, source_project: project) -- GitLab From a52dc7cec70ef97b2755fb9cef7d6b489062310c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 6 Dec 2016 03:13:15 +0800 Subject: [PATCH 20/78] Introduce GitOperationService and wrap every git operation inside GitHooksService. Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19210942 TODO: Fix tests for update_branch_with_hooks --- app/models/repository.rb | 174 ++++---------------------- app/services/git_operation_service.rb | 168 +++++++++++++++++++++++++ spec/models/repository_spec.rb | 12 +- 3 files changed, 197 insertions(+), 157 deletions(-) create mode 100644 app/services/git_operation_service.rb diff --git a/app/models/repository.rb b/app/models/repository.rb index 6bfa24f6329..491d2ab69b2 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -5,7 +5,7 @@ class Repository attr_accessor :path_with_namespace, :project - class CommitError < StandardError; end + CommitError = Class.new(StandardError) # Methods that cache data from the Git repository. # @@ -64,10 +64,6 @@ class Repository @raw_repository ||= Gitlab::Git::Repository.new(path_to_repo) end - def update_autocrlf_option - raw_repository.autocrlf = :input if raw_repository.autocrlf != :input - end - # Return absolute path to repository def path_to_repo @path_to_repo ||= File.expand_path( @@ -172,54 +168,39 @@ class Repository tags.find { |tag| tag.name == name } end - def add_branch(user, branch_name, target) - oldrev = Gitlab::Git::BLANK_SHA - ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name - target = commit(target).try(:id) + def add_branch(user, branch_name, ref) + newrev = commit(ref).try(:sha) - return false unless target + return false unless newrev - GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do - update_ref!(ref, target, oldrev) - end + GitOperationService.new(user, self).add_branch(branch_name, newrev) after_create_branch find_branch(branch_name) end def add_tag(user, tag_name, target, message = nil) - oldrev = Gitlab::Git::BLANK_SHA - ref = Gitlab::Git::TAG_REF_PREFIX + tag_name - target = commit(target).try(:id) - - return false unless target - + newrev = commit(target).try(:id) options = { message: message, tagger: user_to_committer(user) } if message - GitHooksService.new.execute(user, path_to_repo, oldrev, target, ref) do |service| - raw_tag = rugged.tags.create(tag_name, target, options) - service.newrev = raw_tag.target_id - end + return false unless newrev + + GitOperationService.new(user, self).add_tag(tag_name, newrev, options) find_tag(tag_name) end def rm_branch(user, branch_name) before_remove_branch - branch = find_branch(branch_name) - oldrev = branch.try(:dereferenced_target).try(:id) - newrev = Gitlab::Git::BLANK_SHA - ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name - GitHooksService.new.execute(user, path_to_repo, oldrev, newrev, ref) do - update_ref!(ref, newrev, oldrev) - end + GitOperationService.new(user, self).rm_branch(branch) after_remove_branch true end + # TODO: why we don't pass user here? def rm_tag(tag_name) before_remove_tag @@ -245,21 +226,6 @@ class Repository false end - def update_ref!(name, newrev, oldrev) - # We use 'git update-ref' because libgit2/rugged currently does not - # offer 'compare and swap' ref updates. Without compare-and-swap we can - # (and have!) accidentally reset the ref to an earlier state, clobbering - # commits. See also https://github.com/libgit2/libgit2/issues/1534. - command = %W(#{Gitlab.config.git.bin_path} update-ref --stdin -z) - _, status = Gitlab::Popen.popen(command, path_to_repo) do |stdin| - stdin.write("update #{name}\x00#{newrev}\x00#{oldrev}\x00") - end - - return if status.zero? - - raise CommitError.new("Could not update branch #{name.sub('refs/heads/', '')}. Please refresh and try again.") - end - # Makes sure a commit is kept around when Git garbage collection runs. # Git GC will delete commits from the repository that are no longer in any # branches or tags, but we want to keep some of these commits around, for @@ -783,8 +749,7 @@ class Repository user, path, message, branch, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - update_branch_with_hooks( - user, + GitOperationService.new(user, self).with_branch( branch, source_branch: source_branch, source_project: source_project) do |ref| @@ -808,8 +773,7 @@ class Repository user, path, content, message, branch, update, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - update_branch_with_hooks( - user, + GitOperationService.new(user, self).with_branch( branch, source_branch: source_branch, source_project: source_project) do |ref| @@ -839,8 +803,7 @@ class Repository branch:, previous_path:, message:, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - update_branch_with_hooks( - user, + GitOperationService.new(user, self).with_branch( branch, source_branch: source_branch, source_project: source_project) do |ref| @@ -874,8 +837,7 @@ class Repository user, path, message, branch, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - update_branch_with_hooks( - user, + GitOperationService.new(user, self).with_branch( branch, source_branch: source_branch, source_project: source_project) do |ref| @@ -902,8 +864,7 @@ class Repository user:, branch:, message:, actions:, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - update_branch_with_hooks( - user, + GitOperationService.new(user, self).with_branch( branch, source_branch: source_branch, source_project: source_project) do |ref| @@ -964,7 +925,7 @@ class Repository end def user_to_committer(user) - Gitlab::Git::committer_hash(email: user.email, name: user.name) + Gitlab::Git.committer_hash(email: user.email, name: user.name) end def can_be_merged?(source_sha, target_branch) @@ -988,7 +949,8 @@ class Repository merge_index = rugged.merge_commits(our_commit, their_commit) return false if merge_index.conflicts? - update_branch_with_hooks(user, merge_request.target_branch) do + GitOperationService.new(user, self).with_branch( + merge_request.target_branch) do actual_options = options.merge( parents: [our_commit, their_commit], tree: merge_index.write_tree(rugged), @@ -1005,8 +967,7 @@ class Repository return false unless revert_tree_id - update_branch_with_hooks( - user, + GitOperationService.new(user, self).with_branch( base_branch, source_commit: commit) do @@ -1027,8 +988,7 @@ class Repository return false unless cherry_pick_tree_id - update_branch_with_hooks( - user, + GitOperationService.new(user, self).with_branch( base_branch, source_commit: commit) do @@ -1048,8 +1008,8 @@ class Repository end end - def resolve_conflicts(user, branch, params) - update_branch_with_hooks(user, branch) do + def resolve_conflicts(user, branch_name, params) + GitOperationService.new(user, self).with_branch(branch_name) do committer = user_to_committer(user) Rugged::Commit.create(rugged, params.merge(author: committer, committer: committer)) @@ -1140,51 +1100,6 @@ class Repository fetch_ref(path_to_repo, ref, ref_path) end - # Whenever `source_branch` or `source_commit` is passed, if `branch` - # doesn't exist, it would be created from `source_branch` or - # `source_commit`. Should only pass one of them, not both. - # If `source_project` is passed, and the branch doesn't exist, - # it would try to find the source from it instead of current repository. - def update_branch_with_hooks( - current_user, branch, - source_branch: nil, source_commit: nil, source_project: project) - update_autocrlf_option - - target_branch, new_branch_added = - raw_ensure_branch( - branch, - source_branch: source_branch, - source_commit: source_commit, - source_project: source_project - ) - - ref = Gitlab::Git::BRANCH_REF_PREFIX + branch - was_empty = empty? - - # Make commit - newrev = yield(ref) - - unless newrev - raise CommitError.new('Failed to create commit') - end - - if rugged.lookup(newrev).parent_ids.empty? || target_branch.nil? - oldrev = Gitlab::Git::BLANK_SHA - else - oldrev = rugged.merge_base(newrev, target_branch.dereferenced_target.sha) - end - - GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do - update_ref!(ref, newrev, oldrev) - - # If repo was empty expire cache - after_create if was_empty - after_create_branch if was_empty || new_branch_added - end - - newrev - end - def ls_files(ref) actual_ref = ref || root_ref raw_repository.ls_files(actual_ref) @@ -1266,47 +1181,4 @@ class Repository def repository_event(event, tags = {}) Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags)) end - - def raw_ensure_branch( - branch_name, source_commit: nil, source_branch: nil, source_project: nil) - old_branch = find_branch(branch_name) - - if source_commit && source_branch - raise ArgumentError, - 'Should only pass either :source_branch or :source_commit, not both' - end - - if old_branch - [old_branch, false] - elsif project != source_project - unless source_branch - raise ArgumentError, - 'Should also pass :source_branch if' + - ' :source_project is different from current project' - end - - fetch_ref( - source_project.repository.path_to_repo, - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch}", - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch_name}" - ) - - [find_branch(branch_name), true] - elsif source_commit || source_branch - oldrev = Gitlab::Git::BLANK_SHA - ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name - target = (source_commit || commit(source_branch)).try(:sha) - - unless target - raise CommitError.new( - "Cannot find branch #{branch_name} nor #{source_commit.try(:sha) || source_branch}") - end - - update_ref!(ref, target, oldrev) - - [find_branch(branch_name), true] - else - [nil, true] # Empty branch - end - end end diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb new file mode 100644 index 00000000000..88175c6931d --- /dev/null +++ b/app/services/git_operation_service.rb @@ -0,0 +1,168 @@ + +GitOperationService = Struct.new(:user, :repository) do + def add_branch(branch_name, newrev) + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name + oldrev = Gitlab::Git::BLANK_SHA + + with_hooks_and_update_ref(ref, oldrev, newrev) + end + + def rm_branch(branch) + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch.name + oldrev = branch.dereferenced_target.id + newrev = Gitlab::Git::BLANK_SHA + + with_hooks_and_update_ref(ref, oldrev, newrev) + end + + def add_tag(tag_name, newrev, options = {}) + ref = Gitlab::Git::TAG_REF_PREFIX + tag_name + oldrev = Gitlab::Git::BLANK_SHA + + with_hooks(ref, oldrev, newrev) do |service| + raw_tag = repository.rugged.tags.create(tag_name, newrev, options) + service.newrev = raw_tag.target_id + end + end + + # Whenever `source_branch` or `source_commit` is passed, if `branch` + # doesn't exist, it would be created from `source_branch` or + # `source_commit`. Should only pass one of them, not both. + # If `source_project` is passed, and the branch doesn't exist, + # it would try to find the source from it instead of current repository. + def with_branch( + branch_name, + source_branch: nil, + source_commit: nil, + source_project: repository.project) + + if source_commit && source_branch + raise ArgumentError, 'Should pass only :source_branch or :source_commit' + end + + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name + oldrev = Gitlab::Git::BLANK_SHA + + if repository.branch_exists?(branch_name) + oldrev = newrev = repository.commit(branch_name).sha + + elsif repository.project != source_project + unless source_branch + raise ArgumentError, + 'Should also pass :source_branch if' + + ' :source_project is different from current project' + end + + newrev = source_project.repository.commit(source_branch).try(:sha) + + unless newrev + raise Repository::CommitError.new( + "Cannot find branch #{branch_name} nor" \ + " #{source_branch} from" \ + " #{source_project.path_with_namespace}") + end + + elsif source_commit || source_branch + newrev = (source_commit || repository.commit(source_branch)).try(:sha) + + unless newrev + raise Repository::CommitError.new( + "Cannot find branch #{branch_name} nor" \ + " #{source_commit.try(:sha) || source_branch} from" \ + " #{repository.project.path_with_namespace}") + end + + else # we want an orphan empty branch + newrev = Gitlab::Git::BLANK_SHA + end + + commit_with_hooks(ref, oldrev, newrev) do + if repository.project != source_project + repository.fetch_ref( + source_project.repository.path_to_repo, + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch}", + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch_name}" + ) + end + + yield(ref) + end + end + + private + + def commit_with_hooks(ref, oldrev, newrev) + with_hooks_and_update_ref(ref, oldrev, newrev) do |service| + was_empty = repository.empty? + + # Make commit + nextrev = yield(ref) + + unless nextrev + raise Repository::CommitError.new('Failed to create commit') + end + + service.newrev = nextrev + + update_ref!(ref, nextrev, newrev) + + # If repo was empty expire cache + repository.after_create if was_empty + repository.after_create_branch if was_empty || + oldrev == Gitlab::Git::BLANK_SHA + + nextrev + end + end + + def with_hooks_and_update_ref(ref, oldrev, newrev) + with_hooks(ref, oldrev, newrev) do |service| + update_ref!(ref, newrev, oldrev) + + yield(service) if block_given? + end + end + + def with_hooks(ref, oldrev, newrev) + update_autocrlf_option + + result = nil + + GitHooksService.new.execute( + user, + repository.path_to_repo, + oldrev, + newrev, + ref) do |service| + + result = yield(service) if block_given? + end + + result + end + + def update_ref!(name, newrev, oldrev) + # We use 'git update-ref' because libgit2/rugged currently does not + # offer 'compare and swap' ref updates. Without compare-and-swap we can + # (and have!) accidentally reset the ref to an earlier state, clobbering + # commits. See also https://github.com/libgit2/libgit2/issues/1534. + command = %W[#{Gitlab.config.git.bin_path} update-ref --stdin -z] + _, status = Gitlab::Popen.popen( + command, + repository.path_to_repo) do |stdin| + stdin.write("update #{name}\x00#{newrev}\x00#{oldrev}\x00") + end + + unless status.zero? + raise Repository::CommitError.new( + "Could not update branch #{name.sub('refs/heads/', '')}." \ + " Please refresh and try again.") + end + end + + def update_autocrlf_option + if repository.raw_repository.autocrlf != :input + repository.raw_repository.autocrlf = :input + end + end +end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index b797d19161d..3ce3c4dec2a 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -667,7 +667,7 @@ describe Repository, models: true do allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, '']) expect do - repository.rm_branch(user, 'new_feature') + repository.rm_branch(user, 'feature') end.to raise_error(GitHooksService::PreReceiveError) end @@ -682,7 +682,7 @@ describe Repository, models: true do end end - describe '#update_branch_with_hooks' do + xdescribe '#update_branch_with_hooks' do let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature let(:new_rev) { 'a74ae73c1ccde9b974a70e82b901588071dc142a' } # commit whose parent is old_rev @@ -848,7 +848,7 @@ describe Repository, models: true do end it 'sets autocrlf to :input' do - repository.update_autocrlf_option + GitOperationService.new(nil, repository).send(:update_autocrlf_option) expect(repository.raw_repository.autocrlf).to eq(:input) end @@ -863,7 +863,7 @@ describe Repository, models: true do expect(repository.raw_repository).not_to receive(:autocrlf=). with(:input) - repository.update_autocrlf_option + GitOperationService.new(nil, repository).send(:update_autocrlf_option) end end end @@ -1429,14 +1429,14 @@ describe Repository, models: true do describe '#update_ref!' do it 'can create a ref' do - repository.update_ref!('refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA) + GitOperationService.new(nil, repository).send(:update_ref!, 'refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA) expect(repository.find_branch('foobar')).not_to be_nil end it 'raises CommitError when the ref update fails' do expect do - repository.update_ref!('refs/heads/master', 'refs/heads/master', Gitlab::Git::BLANK_SHA) + GitOperationService.new(nil, repository).send(:update_ref!, 'refs/heads/master', 'refs/heads/master', Gitlab::Git::BLANK_SHA) end.to raise_error(Repository::CommitError) end end -- GitLab From 444da6f47ed77172471a27386b969e6401d7cf84 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 6 Dec 2016 15:20:50 +0800 Subject: [PATCH 21/78] Fix update_ref! call in the test --- spec/workers/git_garbage_collect_worker_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index e471a68a49a..2b31efbf631 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -107,7 +107,8 @@ describe GitGarbageCollectWorker do tree: old_commit.tree, parents: [old_commit], ) - project.repository.update_ref!( + GitOperationService.new(nil, project.repository).send( + :update_ref!, "refs/heads/#{SecureRandom.hex(6)}", new_commit_sha, Gitlab::Git::BLANK_SHA -- GitLab From 65806ec632f2ea1e2087b7cdc64f13e6db49c88a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Tue, 6 Dec 2016 18:47:24 +0800 Subject: [PATCH 22/78] Re-enable tests for update_branch_with_hooks and Add back check if we're losing commits in a merge. --- app/services/git_operation_service.rb | 15 ++++++-- spec/models/repository_spec.rb | 50 ++++++++++++++++++++------- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 88175c6931d..c34d4bde150 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -102,9 +102,20 @@ GitOperationService = Struct.new(:user, :repository) do raise Repository::CommitError.new('Failed to create commit') end - service.newrev = nextrev + branch = + repository.find_branch(ref[Gitlab::Git::BRANCH_REF_PREFIX.size..-1]) + + prevrev = if branch && + !repository.rugged.lookup(nextrev).parent_ids.empty? + repository.rugged.merge_base( + nextrev, branch.dereferenced_target.sha) + else + newrev + end - update_ref!(ref, nextrev, newrev) + update_ref!(ref, nextrev, prevrev) + + service.newrev = nextrev # If repo was empty expire cache repository.after_create if was_empty diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 3ce3c4dec2a..e3ec4c85a74 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -682,33 +682,48 @@ describe Repository, models: true do end end - xdescribe '#update_branch_with_hooks' do + describe '#update_branch_with_hooks' do let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature let(:new_rev) { 'a74ae73c1ccde9b974a70e82b901588071dc142a' } # commit whose parent is old_rev context 'when pre hooks were successful' do before do - expect_any_instance_of(GitHooksService).to receive(:execute). - with(user, repository.path_to_repo, old_rev, new_rev, 'refs/heads/feature'). - and_yield.and_return(true) + service = GitHooksService.new + expect(GitHooksService).to receive(:new).and_return(service) + expect(service).to receive(:execute). + with( + user, + repository.path_to_repo, + old_rev, + old_rev, + 'refs/heads/feature'). + and_yield(service).and_return(true) end it 'runs without errors' do expect do - repository.update_branch_with_hooks(user, 'feature') { new_rev } + GitOperationService.new(user, repository).with_branch('feature') do + new_rev + end end.not_to raise_error end it 'ensures the autocrlf Git option is set to :input' do - expect(repository).to receive(:update_autocrlf_option) + service = GitOperationService.new(user, repository) + + expect(service).to receive(:update_autocrlf_option) - repository.update_branch_with_hooks(user, 'feature') { new_rev } + service.with_branch('feature') { new_rev } end context "when the branch wasn't empty" do it 'updates the head' do expect(repository.find_branch('feature').dereferenced_target.id).to eq(old_rev) - repository.update_branch_with_hooks(user, 'feature') { new_rev } + + GitOperationService.new(user, repository).with_branch('feature') do + new_rev + end + expect(repository.find_branch('feature').dereferenced_target.id).to eq(new_rev) end end @@ -727,7 +742,11 @@ describe Repository, models: true do branch = 'feature-ff-target' repository.add_branch(user, branch, old_rev) - expect { repository.update_branch_with_hooks(user, branch) { new_rev } }.not_to raise_error + expect do + GitOperationService.new(user, repository).with_branch(branch) do + new_rev + end + end.not_to raise_error end end @@ -742,7 +761,9 @@ describe Repository, models: true do # Updating 'master' to new_rev would lose the commits on 'master' that # are not contained in new_rev. This should not be allowed. expect do - repository.update_branch_with_hooks(user, branch) { new_rev } + GitOperationService.new(user, repository).with_branch(branch) do + new_rev + end end.to raise_error(Repository::CommitError) end end @@ -752,7 +773,9 @@ describe Repository, models: true do allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, '']) expect do - repository.update_branch_with_hooks(user, 'feature') { new_rev } + GitOperationService.new(user, repository).with_branch('feature') do + new_rev + end end.to raise_error(GitHooksService::PreReceiveError) end end @@ -770,7 +793,10 @@ describe Repository, models: true do expect(repository).to receive(:expire_branches_cache) expect(repository).to receive(:expire_has_visible_content_cache) - repository.update_branch_with_hooks(user, 'new-feature') { new_rev } + GitOperationService.new(user, repository). + with_branch('new-feature') do + new_rev + end end end -- GitLab From 6ae1a73cfdad4b98176bb99846042d4378119de2 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 7 Dec 2016 19:50:08 +0800 Subject: [PATCH 23/78] Pass source_branch properly for cherry-pick/revert Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237/diffs#note_19210818 --- app/models/repository.rb | 12 ++++++++---- app/services/commits/change_service.rb | 9 ++++++++- app/services/git_operation_service.rb | 16 +++++----------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 491d2ab69b2..36cbb0d051e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -962,14 +962,16 @@ class Repository end end - def revert(user, commit, base_branch, revert_tree_id = nil) + def revert( + user, commit, base_branch, revert_tree_id = nil, + source_branch: nil, source_project: project) revert_tree_id ||= check_revert_content(commit, base_branch) return false unless revert_tree_id GitOperationService.new(user, self).with_branch( base_branch, - source_commit: commit) do + source_branch: source_branch, source_project: source_project) do source_sha = find_branch(base_branch).dereferenced_target.sha committer = user_to_committer(user) @@ -983,14 +985,16 @@ class Repository end end - def cherry_pick(user, commit, base_branch, cherry_pick_tree_id = nil) + def cherry_pick( + user, commit, base_branch, cherry_pick_tree_id = nil, + source_branch: nil, source_project: project) cherry_pick_tree_id ||= check_cherry_pick_content(commit, base_branch) return false unless cherry_pick_tree_id GitOperationService.new(user, self).with_branch( base_branch, - source_commit: commit) do + source_branch: source_branch, source_project: source_project) do source_sha = find_branch(base_branch).dereferenced_target.sha committer = user_to_committer(user) diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 04b28cfaed8..5458f7a6790 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -31,7 +31,14 @@ module Commits if tree_id validate_target_branch(into) if @create_merge_request - repository.public_send(action, current_user, @commit, into, tree_id) + repository.public_send( + action, + current_user, + @commit, + into, + tree_id, + source_branch: @target_branch) + success else error_msg = "Sorry, we cannot #{action.to_s.dasherize} this #{@commit.change_type_title} automatically. diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index c34d4bde150..c9e2c21737a 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -25,21 +25,15 @@ GitOperationService = Struct.new(:user, :repository) do end end - # Whenever `source_branch` or `source_commit` is passed, if `branch` - # doesn't exist, it would be created from `source_branch` or - # `source_commit`. Should only pass one of them, not both. + # Whenever `source_branch` is passed, if `branch` doesn't exist, + # it would be created from `source_branch`. # If `source_project` is passed, and the branch doesn't exist, # it would try to find the source from it instead of current repository. def with_branch( branch_name, source_branch: nil, - source_commit: nil, source_project: repository.project) - if source_commit && source_branch - raise ArgumentError, 'Should pass only :source_branch or :source_commit' - end - ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name oldrev = Gitlab::Git::BLANK_SHA @@ -62,13 +56,13 @@ GitOperationService = Struct.new(:user, :repository) do " #{source_project.path_with_namespace}") end - elsif source_commit || source_branch - newrev = (source_commit || repository.commit(source_branch)).try(:sha) + elsif source_branch + newrev = repository.commit(source_branch).try(:sha) unless newrev raise Repository::CommitError.new( "Cannot find branch #{branch_name} nor" \ - " #{source_commit.try(:sha) || source_branch} from" \ + " #{source_branch} from" \ " #{repository.project.path_with_namespace}") end -- GitLab From 5ecd0c81af85476c2328d3836cc68b17ebd5a8a6 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 7 Dec 2016 22:37:43 +0800 Subject: [PATCH 24/78] Commit outside the hooks if possible: So we still commit outside the hooks, and only update ref inside the hooks. There are only two exceptions: * Whenever it's adding a tag. We can't add a tag without committing, unfortunately. See !7700 * Whenever source project is in another repository. We'll need to fetch ref otherwise commits can't be made. See the whole discussion starting from: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19210942 --- app/models/repository.rb | 16 +++- app/services/git_operation_service.rb | 111 ++++++++++++-------------- spec/models/repository_spec.rb | 2 +- 3 files changed, 65 insertions(+), 64 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 36cbb0d051e..9393d6b461e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -973,7 +973,8 @@ class Repository base_branch, source_branch: source_branch, source_project: source_project) do - source_sha = find_branch(base_branch).dereferenced_target.sha + source_sha = source_project.repository.find_source_sha( + source_branch || base_branch) committer = user_to_committer(user) Rugged::Commit.create(rugged, @@ -996,7 +997,8 @@ class Repository base_branch, source_branch: source_branch, source_project: source_project) do - source_sha = find_branch(base_branch).dereferenced_target.sha + source_sha = source_project.repository.find_source_sha( + source_branch || base_branch) committer = user_to_committer(user) Rugged::Commit.create(rugged, @@ -1162,6 +1164,16 @@ class Repository end end + protected + + def find_source_sha(branch_name) + if branch_exists?(branch_name) + find_branch(branch_name).dereferenced_target.sha + else + Gitlab::Git::BLANK_SHA + end + end + private def refs_directory_exists? diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index c9e2c21737a..3a102a9276b 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -34,43 +34,10 @@ GitOperationService = Struct.new(:user, :repository) do source_branch: nil, source_project: repository.project) - ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name - oldrev = Gitlab::Git::BLANK_SHA + check_with_branch_arguments!(branch_name, source_branch, source_project) - if repository.branch_exists?(branch_name) - oldrev = newrev = repository.commit(branch_name).sha - - elsif repository.project != source_project - unless source_branch - raise ArgumentError, - 'Should also pass :source_branch if' + - ' :source_project is different from current project' - end - - newrev = source_project.repository.commit(source_branch).try(:sha) - - unless newrev - raise Repository::CommitError.new( - "Cannot find branch #{branch_name} nor" \ - " #{source_branch} from" \ - " #{source_project.path_with_namespace}") - end - - elsif source_branch - newrev = repository.commit(source_branch).try(:sha) - - unless newrev - raise Repository::CommitError.new( - "Cannot find branch #{branch_name} nor" \ - " #{source_branch} from" \ - " #{repository.project.path_with_namespace}") - end - - else # we want an orphan empty branch - newrev = Gitlab::Git::BLANK_SHA - end - - commit_with_hooks(ref, oldrev, newrev) do + update_branch_with_hooks( + branch_name, source_branch, source_project) do |ref| if repository.project != source_project repository.fetch_ref( source_project.repository.path_to_repo, @@ -85,39 +52,37 @@ GitOperationService = Struct.new(:user, :repository) do private - def commit_with_hooks(ref, oldrev, newrev) - with_hooks_and_update_ref(ref, oldrev, newrev) do |service| - was_empty = repository.empty? - - # Make commit - nextrev = yield(ref) - - unless nextrev - raise Repository::CommitError.new('Failed to create commit') - end + def update_branch_with_hooks(branch_name, source_branch, source_project) + update_autocrlf_option - branch = - repository.find_branch(ref[Gitlab::Git::BRANCH_REF_PREFIX.size..-1]) + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name + oldrev = Gitlab::Git::BLANK_SHA + was_empty = repository.empty? - prevrev = if branch && - !repository.rugged.lookup(nextrev).parent_ids.empty? - repository.rugged.merge_base( - nextrev, branch.dereferenced_target.sha) - else - newrev - end + # Make commit + newrev = yield(ref) - update_ref!(ref, nextrev, prevrev) + unless newrev + raise Repository::CommitError.new('Failed to create commit') + end - service.newrev = nextrev + branch = repository.find_branch(branch_name) + oldrev = if repository.rugged.lookup(newrev).parent_ids.empty? || + branch.nil? + Gitlab::Git::BLANK_SHA + else + repository.rugged.merge_base( + newrev, branch.dereferenced_target.sha) + end + with_hooks_and_update_ref(ref, oldrev, newrev) do # If repo was empty expire cache repository.after_create if was_empty repository.after_create_branch if was_empty || oldrev == Gitlab::Git::BLANK_SHA - - nextrev end + + newrev end def with_hooks_and_update_ref(ref, oldrev, newrev) @@ -129,8 +94,6 @@ GitOperationService = Struct.new(:user, :repository) do end def with_hooks(ref, oldrev, newrev) - update_autocrlf_option - result = nil GitHooksService.new.execute( @@ -170,4 +133,30 @@ GitOperationService = Struct.new(:user, :repository) do repository.raw_repository.autocrlf = :input end end + + def check_with_branch_arguments!(branch_name, source_branch, source_project) + return if repository.branch_exists?(branch_name) + + if repository.project != source_project + unless source_branch + raise ArgumentError, + 'Should also pass :source_branch if' + + ' :source_project is different from current project' + end + + unless source_project.repository.commit(source_branch).try(:sha) + raise Repository::CommitError.new( + "Cannot find branch #{branch_name} nor" \ + " #{source_branch} from" \ + " #{source_project.path_with_namespace}") + end + elsif source_branch + unless repository.commit(source_branch).try(:sha) + raise Repository::CommitError.new( + "Cannot find branch #{branch_name} nor" \ + " #{source_branch} from" \ + " #{repository.project.path_with_namespace}") + end + end + end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index e3ec4c85a74..ebd05c946cc 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -695,7 +695,7 @@ describe Repository, models: true do user, repository.path_to_repo, old_rev, - old_rev, + new_rev, 'refs/heads/feature'). and_yield(service).and_return(true) end -- GitLab From 5ba468efde94ed823aaccabf2405e63cecfbf9d6 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 7 Dec 2016 23:03:58 +0800 Subject: [PATCH 25/78] Not sure why rubocop prefers this but anyway --- app/models/repository.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 9393d6b461e..038ab5e104a 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -974,7 +974,7 @@ class Repository source_branch: source_branch, source_project: source_project) do source_sha = source_project.repository.find_source_sha( - source_branch || base_branch) + source_branch || base_branch) committer = user_to_committer(user) Rugged::Commit.create(rugged, @@ -998,7 +998,7 @@ class Repository source_branch: source_branch, source_project: source_project) do source_sha = source_project.repository.find_source_sha( - source_branch || base_branch) + source_branch || base_branch) committer = user_to_committer(user) Rugged::Commit.create(rugged, -- GitLab From fff3c5262857ee8c8dbf4ba7159032f836eba1bd Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 7 Dec 2016 23:33:33 +0800 Subject: [PATCH 26/78] Use multi_action to commit which doesn't need to have the branch existed upfront. That is, `Rugged::Commit.create` rather than `Gitlab::Git::Blob.commit` which the former doesn't need to have the branch but the latter needs. --- app/models/repository.rb | 99 +++++++++++++++------------------------- 1 file changed, 36 insertions(+), 63 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 038ab5e104a..c05cfb271c7 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -773,27 +773,17 @@ class Repository user, path, content, message, branch, update, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - GitOperationService.new(user, self).with_branch( - branch, + multi_action( + user: user, + branch: branch, + message: message, + author_email: author_email, + author_name: author_name, source_branch: source_branch, - source_project: source_project) do |ref| - options = { - commit: { - branch: ref, - message: message, - update_ref: false - }, - file: { - content: content, - path: path, - update: update - } - } - - options.merge!(get_committer_and_author(user, email: author_email, name: author_name)) - - Gitlab::Git::Blob.commit(raw_repository, options) - end + source_project: source_project, + actions: [{action: :create, + file_path: path, + content: content}]) end # rubocop:enable Metrics/ParameterLists @@ -803,32 +793,24 @@ class Repository branch:, previous_path:, message:, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - GitOperationService.new(user, self).with_branch( - branch, + action = if previous_path && previous_path != path + :move + else + :update + end + + multi_action( + user: user, + branch: branch, + message: message, + author_email: author_email, + author_name: author_name, source_branch: source_branch, - source_project: source_project) do |ref| - options = { - commit: { - branch: ref, - message: message, - update_ref: false - }, - file: { - content: content, - path: path, - update: true - } - } - - options.merge!(get_committer_and_author(user, email: author_email, name: author_name)) - - if previous_path && previous_path != path - options[:file][:previous_path] = previous_path - Gitlab::Git::Blob.rename(raw_repository, options) - else - Gitlab::Git::Blob.commit(raw_repository, options) - end - end + source_project: source_project, + actions: [{action: action, + file_path: path, + content: content, + previous_path: previous_path}]) end # rubocop:enable Metrics/ParameterLists @@ -837,25 +819,16 @@ class Repository user, path, message, branch, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - GitOperationService.new(user, self).with_branch( - branch, + multi_action( + user: user, + branch: branch, + message: message, + author_email: author_email, + author_name: author_name, source_branch: source_branch, - source_project: source_project) do |ref| - options = { - commit: { - branch: ref, - message: message, - update_ref: false - }, - file: { - path: path - } - } - - options.merge!(get_committer_and_author(user, email: author_email, name: author_name)) - - Gitlab::Git::Blob.remove(raw_repository, options) - end + source_project: source_project, + actions: [{action: :delete, + file_path: path}]) end # rubocop:enable Metrics/ParameterLists -- GitLab From a51f26e5142d6c5f40984cd374f0dea7580a4235 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 01:12:49 +0800 Subject: [PATCH 27/78] Use commit_file for commit_dir --- app/models/repository.rb | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index c05cfb271c7..6246630300c 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -749,22 +749,32 @@ class Repository user, path, message, branch, author_email: nil, author_name: nil, source_branch: nil, source_project: project) - GitOperationService.new(user, self).with_branch( + if branch_exists?(branch) + # tree_entry is private + entry = raw_repository.send(:tree_entry, commit(branch), path) + + if entry + if entry[:type] == :blob + raise Gitlab::Git::Repository::InvalidBlobName.new( + "Directory already exists as a file") + else + raise Gitlab::Git::Repository::InvalidBlobName.new( + "Directory already exists") + end + end + end + + commit_file( + user, + "#{Gitlab::Git::PathHelper.normalize_path(path)}/.gitkeep", + '', + message, branch, + false, + author_email: author_email, + author_name: author_name, source_branch: source_branch, - source_project: source_project) do |ref| - options = { - commit: { - branch: ref, - message: message, - update_ref: false - } - } - - options.merge!(get_committer_and_author(user, email: author_email, name: author_name)) - - raw_repository.mkdir(path, options) - end + source_project: source_project) end # rubocop:enable Metrics/ParameterLists -- GitLab From e76173038b03c660a498d9f38b07797b453f1e7f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 01:13:16 +0800 Subject: [PATCH 28/78] Restore the check for update in commit_file --- app/models/repository.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/models/repository.rb b/app/models/repository.rb index 6246630300c..8a94fbf3ecc 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -783,6 +783,14 @@ class Repository user, path, content, message, branch, update, author_email: nil, author_name: nil, source_branch: nil, source_project: project) + if branch_exists?(branch) && update == false + # tree_entry is private + if raw_repository.send(:tree_entry, commit(branch), path) + raise Gitlab::Git::Repository::InvalidBlobName.new( + "Filename already exists; update not allowed") + end + end + multi_action( user: user, branch: branch, -- GitLab From 4b3c18ce5cbd88156423d89f26b0869f45e2225e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 01:13:33 +0800 Subject: [PATCH 29/78] Use branch_name to find the branch rather than ref --- app/models/repository.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 8a94fbf3ecc..4d74ac6f585 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -858,9 +858,9 @@ class Repository GitOperationService.new(user, self).with_branch( branch, source_branch: source_branch, - source_project: source_project) do |ref| + source_project: source_project) do index = rugged.index - branch_commit = find_branch(ref) + branch_commit = find_branch(branch) parents = if branch_commit last_commit = branch_commit.dereferenced_target -- GitLab From e36088dd98c1c00a8884684158d47f479940346e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 01:30:10 +0800 Subject: [PATCH 30/78] We need to normalize the path for all actions --- app/models/repository.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 4d74ac6f585..cf2c08f618e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -766,7 +766,7 @@ class Repository commit_file( user, - "#{Gitlab::Git::PathHelper.normalize_path(path)}/.gitkeep", + "#{path}/.gitkeep", '', message, branch, @@ -871,12 +871,14 @@ class Repository end actions.each do |action| + path = Gitlab::Git::PathHelper.normalize_path(action[:file_path]).to_s + case action[:action] when :create, :update, :move mode = case action[:action] when :update - index.get(action[:file_path])[:mode] + index.get(path)[:mode] when :move index.get(action[:previous_path])[:mode] end @@ -887,9 +889,9 @@ class Repository content = action[:encoding] == 'base64' ? Base64.decode64(action[:content]) : action[:content] oid = rugged.write(content, :blob) - index.add(path: action[:file_path], oid: oid, mode: mode) + index.add(path: path, oid: oid, mode: mode) when :delete - index.remove(action[:file_path]) + index.remove(path) end end -- GitLab From 56e0dcab97f43e14ae88a66031e3cd71cd062b23 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 02:15:09 +0800 Subject: [PATCH 31/78] Spaces around hash braces --- app/models/repository.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index cf2c08f618e..4d350f937a6 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -799,9 +799,9 @@ class Repository author_name: author_name, source_branch: source_branch, source_project: source_project, - actions: [{action: :create, - file_path: path, - content: content}]) + actions: [{ action: :create, + file_path: path, + content: content }]) end # rubocop:enable Metrics/ParameterLists @@ -825,10 +825,10 @@ class Repository author_name: author_name, source_branch: source_branch, source_project: source_project, - actions: [{action: action, - file_path: path, - content: content, - previous_path: previous_path}]) + actions: [{ action: action, + file_path: path, + content: content, + previous_path: previous_path }]) end # rubocop:enable Metrics/ParameterLists @@ -845,8 +845,8 @@ class Repository author_name: author_name, source_branch: source_branch, source_project: source_project, - actions: [{action: :delete, - file_path: path}]) + actions: [{ action: :delete, + file_path: path }]) end # rubocop:enable Metrics/ParameterLists -- GitLab From cdb598f3973bb7643d8d7f85f6109d84aea759ec Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 14:15:50 +0800 Subject: [PATCH 32/78] We probably don't need this anymore, not sure why --- app/controllers/concerns/creates_commit.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index e5c40446314..dacb5679dd3 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,10 +4,9 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - source_branch = @ref if @ref && @repository.branch_exists?(@ref) commit_params = @commit_params.merge( source_project: @project, - source_branch: source_branch, + source_branch: @ref, target_branch: @target_branch ) -- GitLab From ae5b935b2888f7721e424cf41e2963e1483d8bb5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 14:16:06 +0800 Subject: [PATCH 33/78] find the commit properly and replicate gitlab_git by checking filename as well --- app/models/repository.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 4d350f937a6..50f347b58c8 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -860,7 +860,8 @@ class Repository source_branch: source_branch, source_project: source_project) do index = rugged.index - branch_commit = find_branch(branch) + branch_commit = source_project.repository.find_branch( + source_branch || branch) parents = if branch_commit last_commit = branch_commit.dereferenced_target @@ -873,6 +874,9 @@ class Repository actions.each do |action| path = Gitlab::Git::PathHelper.normalize_path(action[:file_path]).to_s + raise Gitlab::Git::Repository::InvalidBlobName.new("Invalid path") if + path.split('/').include?('..') + case action[:action] when :create, :update, :move mode = -- GitLab From 4f94053c21196b3445c117130e3556463e4ca1d0 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 15:22:32 +0800 Subject: [PATCH 34/78] We still need it for empty repo for web UI! We shouldn't pass a non-existing branch to source_branch. Checkout test for: * spec/features/tags/master_views_tags_spec.rb:24 * spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb:13 --- app/controllers/concerns/creates_commit.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index dacb5679dd3..5d11f286e9a 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,9 +4,10 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables + source_branch = @ref if @ref && @repository.find_branch(@ref) commit_params = @commit_params.merge( source_project: @project, - source_branch: @ref, + source_branch: source_branch, target_branch: @target_branch ) -- GitLab From cf677378ee8104e7505cf0670ad45a51613af575 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 15:23:41 +0800 Subject: [PATCH 35/78] Prefer repository.branch_exists? --- app/services/files/base_service.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 6779bd2818a..80e1d1d60f2 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -5,7 +5,7 @@ module Files def execute @source_project = params[:source_project] || @project @source_branch = params[:source_branch] - @target_branch = params[:target_branch] + @target_branch = params[:target_branch] @commit_message = params[:commit_message] @file_path = params[:file_path] @@ -59,12 +59,12 @@ module Files end unless project.empty_repo? - unless @source_project.repository.branch_names.include?(@source_branch) + unless @source_project.repository.branch_exists?(@source_branch) raise_error('You can only create or edit files when you are on a branch') end if different_branch? - if repository.branch_names.include?(@target_branch) + if repository.branch_exists?(@target_branch) raise_error('Branch with such name already exists. You need to switch to this branch in order to make changes') end end -- GitLab From 691f1c496834078ba41209597558259d20790a0b Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 15:31:42 +0800 Subject: [PATCH 36/78] Simply give result if result[:status] == :error --- app/services/create_branch_service.rb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index 076f976ed06..1b5e504573a 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -1,8 +1,9 @@ class CreateBranchService < BaseService def execute(branch_name, ref) - failure = validate_new_branch(branch_name) + result = ValidateNewBranchService.new(project, current_user). + execute(branch_name) - return failure if failure + return result if result[:status] == :error new_branch = repository.add_branch(current_user, branch_name, ref) @@ -18,13 +19,4 @@ class CreateBranchService < BaseService def success(branch) super().merge(branch: branch) end - - private - - def validate_new_branch(branch_name) - result = ValidateNewBranchService.new(project, current_user). - execute(branch_name) - - error(result[:message]) if result[:status] == :error - end end -- GitLab From 3fa3fcd7876262bb63966debd04d16ea219fad73 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 17:08:25 +0800 Subject: [PATCH 37/78] Cleanup parameters, easier to understand and more consistent across different methodst --- app/models/repository.rb | 91 +++++++++++++----------- app/services/commits/change_service.rb | 2 +- app/services/files/create_dir_service.rb | 6 +- app/services/files/create_service.rb | 8 +-- app/services/files/delete_service.rb | 6 +- app/services/files/multi_service.rb | 4 +- app/services/files/update_service.rb | 6 +- app/services/git_operation_service.rb | 16 ++--- spec/models/repository_spec.rb | 86 ++++++++++++++-------- 9 files changed, 130 insertions(+), 95 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 50f347b58c8..73a9e269a65 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -746,12 +746,13 @@ class Repository # rubocop:disable Metrics/ParameterLists def commit_dir( - user, path, message, branch, + user, path, + message:, branch_name:, author_email: nil, author_name: nil, - source_branch: nil, source_project: project) - if branch_exists?(branch) + source_branch_name: nil, source_project: project) + if branch_exists?(branch_name) # tree_entry is private - entry = raw_repository.send(:tree_entry, commit(branch), path) + entry = raw_repository.send(:tree_entry, commit(branch_name), path) if entry if entry[:type] == :blob @@ -768,24 +769,25 @@ class Repository user, "#{path}/.gitkeep", '', - message, - branch, - false, + message: message, + branch_name: branch_name, + update: false, author_email: author_email, author_name: author_name, - source_branch: source_branch, + source_branch_name: source_branch_name, source_project: source_project) end # rubocop:enable Metrics/ParameterLists # rubocop:disable Metrics/ParameterLists def commit_file( - user, path, content, message, branch, update, + user, path, content, + message:, branch_name:, update: true, author_email: nil, author_name: nil, - source_branch: nil, source_project: project) - if branch_exists?(branch) && update == false + source_branch_name: nil, source_project: project) + if branch_exists?(branch_name) && update == false # tree_entry is private - if raw_repository.send(:tree_entry, commit(branch), path) + if raw_repository.send(:tree_entry, commit(branch_name), path) raise Gitlab::Git::Repository::InvalidBlobName.new( "Filename already exists; update not allowed") end @@ -793,11 +795,11 @@ class Repository multi_action( user: user, - branch: branch, message: message, + branch_name: branch_name, author_email: author_email, author_name: author_name, - source_branch: source_branch, + source_branch_name: source_branch_name, source_project: source_project, actions: [{ action: :create, file_path: path, @@ -808,9 +810,9 @@ class Repository # rubocop:disable Metrics/ParameterLists def update_file( user, path, content, - branch:, previous_path:, message:, + message:, branch_name:, previous_path:, author_email: nil, author_name: nil, - source_branch: nil, source_project: project) + source_branch_name: nil, source_project: project) action = if previous_path && previous_path != path :move else @@ -819,11 +821,11 @@ class Repository multi_action( user: user, - branch: branch, message: message, + branch_name: branch_name, author_email: author_email, author_name: author_name, - source_branch: source_branch, + source_branch_name: source_branch_name, source_project: source_project, actions: [{ action: action, file_path: path, @@ -834,16 +836,17 @@ class Repository # rubocop:disable Metrics/ParameterLists def remove_file( - user, path, message, branch, + user, path, + message:, branch_name:, author_email: nil, author_name: nil, - source_branch: nil, source_project: project) + source_branch_name: nil, source_project: project) multi_action( user: user, - branch: branch, message: message, + branch_name: branch_name, author_email: author_email, author_name: author_name, - source_branch: source_branch, + source_branch_name: source_branch_name, source_project: source_project, actions: [{ action: :delete, file_path: path }]) @@ -852,16 +855,16 @@ class Repository # rubocop:disable Metrics/ParameterLists def multi_action( - user:, branch:, message:, actions:, + user:, branch_name:, message:, actions:, author_email: nil, author_name: nil, - source_branch: nil, source_project: project) + source_branch_name: nil, source_project: project) GitOperationService.new(user, self).with_branch( - branch, - source_branch: source_branch, + branch_name, + source_branch_name: source_branch_name, source_project: source_project) do index = rugged.index branch_commit = source_project.repository.find_branch( - source_branch || branch) + source_branch_name || branch_name) parents = if branch_commit last_commit = branch_commit.dereferenced_target @@ -960,18 +963,19 @@ class Repository end def revert( - user, commit, base_branch, revert_tree_id = nil, - source_branch: nil, source_project: project) - revert_tree_id ||= check_revert_content(commit, base_branch) + user, commit, branch_name, revert_tree_id = nil, + source_branch_name: nil, source_project: project) + revert_tree_id ||= check_revert_content(commit, branch_name) return false unless revert_tree_id GitOperationService.new(user, self).with_branch( - base_branch, - source_branch: source_branch, source_project: source_project) do + branch_name, + source_branch_name: source_branch_name, + source_project: source_project) do source_sha = source_project.repository.find_source_sha( - source_branch || base_branch) + source_branch_name || branch_name) committer = user_to_committer(user) Rugged::Commit.create(rugged, @@ -984,18 +988,19 @@ class Repository end def cherry_pick( - user, commit, base_branch, cherry_pick_tree_id = nil, - source_branch: nil, source_project: project) - cherry_pick_tree_id ||= check_cherry_pick_content(commit, base_branch) + user, commit, branch_name, cherry_pick_tree_id = nil, + source_branch_name: nil, source_project: project) + cherry_pick_tree_id ||= check_cherry_pick_content(commit, branch_name) return false unless cherry_pick_tree_id GitOperationService.new(user, self).with_branch( - base_branch, - source_branch: source_branch, source_project: source_project) do + branch_name, + source_branch_name: source_branch_name, + source_project: source_project) do source_sha = source_project.repository.find_source_sha( - source_branch || base_branch) + source_branch_name || branch_name) committer = user_to_committer(user) Rugged::Commit.create(rugged, @@ -1019,8 +1024,8 @@ class Repository end end - def check_revert_content(commit, base_branch) - source_sha = find_branch(base_branch).dereferenced_target.sha + def check_revert_content(commit, branch_name) + source_sha = find_branch(branch_name).dereferenced_target.sha args = [commit.id, source_sha] args << { mainline: 1 } if commit.merge_commit? @@ -1033,8 +1038,8 @@ class Repository tree_id end - def check_cherry_pick_content(commit, base_branch) - source_sha = find_branch(base_branch).dereferenced_target.sha + def check_cherry_pick_content(commit, branch_name) + source_sha = find_branch(branch_name).dereferenced_target.sha args = [commit.id, source_sha] args << 1 if commit.merge_commit? diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 5458f7a6790..d49fcd42a08 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -37,7 +37,7 @@ module Commits @commit, into, tree_id, - source_branch: @target_branch) + source_branch_name: @target_branch) success else diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb index f0bb3333db8..4a2b2e8fcaf 100644 --- a/app/services/files/create_dir_service.rb +++ b/app/services/files/create_dir_service.rb @@ -4,11 +4,11 @@ module Files repository.commit_dir( current_user, @file_path, - @commit_message, - @target_branch, + message: @commit_message, + branch_name: @target_branch, author_email: @author_email, author_name: @author_name, - source_branch: @source_branch) + source_branch_name: @source_branch) end def validate diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index 65f7baf56fd..c95cb75f7cb 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -5,12 +5,12 @@ module Files current_user, @file_path, @file_content, - @commit_message, - @target_branch, - false, + message: @commit_message, + branch_name: @target_branch, + update: false, author_email: @author_email, author_name: @author_name, - source_branch: @source_branch) + source_branch_name: @source_branch) end def validate diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb index b3f323d0173..45a9a559469 100644 --- a/app/services/files/delete_service.rb +++ b/app/services/files/delete_service.rb @@ -4,11 +4,11 @@ module Files repository.remove_file( current_user, @file_path, - @commit_message, - @target_branch, + message: @commit_message, + branch_name: @target_branch, author_email: @author_email, author_name: @author_name, - source_branch: @source_branch) + source_branch_name: @source_branch) end end end diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb index 6f5f25f88fd..42ed97ca3c0 100644 --- a/app/services/files/multi_service.rb +++ b/app/services/files/multi_service.rb @@ -5,12 +5,12 @@ module Files def commit repository.multi_action( user: current_user, - branch: @target_branch, message: @commit_message, + branch_name: @target_branch, actions: params[:actions], author_email: @author_email, author_name: @author_name, - source_branch: @source_branch + source_branch_name: @source_branch ) end diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index 67d473d4978..5f671817cdb 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -4,13 +4,13 @@ module Files def commit repository.update_file(current_user, @file_path, @file_content, - branch: @target_branch, - previous_path: @previous_path, message: @commit_message, + branch_name: @target_branch, + previous_path: @previous_path, author_email: @author_email, author_name: @author_name, source_project: @source_project, - source_branch: @source_branch) + source_branch_name: @source_branch) end private diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 3a102a9276b..c8504ecf3cd 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -25,23 +25,23 @@ GitOperationService = Struct.new(:user, :repository) do end end - # Whenever `source_branch` is passed, if `branch` doesn't exist, - # it would be created from `source_branch`. + # Whenever `source_branch_name` is passed, if `branch_name` doesn't exist, + # it would be created from `source_branch_name`. # If `source_project` is passed, and the branch doesn't exist, # it would try to find the source from it instead of current repository. def with_branch( branch_name, - source_branch: nil, + source_branch_name: nil, source_project: repository.project) - check_with_branch_arguments!(branch_name, source_branch, source_project) + check_with_branch_arguments!( + branch_name, source_branch_name, source_project) - update_branch_with_hooks( - branch_name, source_branch, source_project) do |ref| + update_branch_with_hooks(branch_name) do |ref| if repository.project != source_project repository.fetch_ref( source_project.repository.path_to_repo, - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch}", + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch_name}", "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch_name}" ) end @@ -52,7 +52,7 @@ GitOperationService = Struct.new(:user, :repository) do private - def update_branch_with_hooks(branch_name, source_branch, source_project) + def update_branch_with_hooks(branch_name) update_autocrlf_option ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index ebd05c946cc..78596346b91 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -249,7 +249,8 @@ describe Repository, models: true do describe "#commit_dir" do it "commits a change that creates a new directory" do expect do - repository.commit_dir(user, 'newdir', 'Create newdir', 'master') + repository.commit_dir(user, 'newdir', + message: 'Create newdir', branch_name: 'master') end.to change { repository.commits('master').count }.by(1) newdir = repository.tree('master', 'newdir') @@ -259,7 +260,10 @@ describe Repository, models: true do context "when an author is specified" do it "uses the given email/name to set the commit's author" do expect do - repository.commit_dir(user, "newdir", "Add newdir", 'master', author_email: author_email, author_name: author_name) + repository.commit_dir(user, 'newdir', + message: 'Add newdir', + branch_name: 'master', + author_email: author_email, author_name: author_name) end.to change { repository.commits('master').count }.by(1) last_commit = repository.commit @@ -274,8 +278,9 @@ describe Repository, models: true do it 'commits change to a file successfully' do expect do repository.commit_file(user, 'CHANGELOG', 'Changelog!', - 'Updates file content', - 'master', true) + message: 'Updates file content', + branch_name: 'master', + update: true) end.to change { repository.commits('master').count }.by(1) blob = repository.blob_at('master', 'CHANGELOG') @@ -286,8 +291,12 @@ describe Repository, models: true do context "when an author is specified" do it "uses the given email/name to set the commit's author" do expect do - repository.commit_file(user, "README", 'README!', 'Add README', - 'master', true, author_email: author_email, author_name: author_name) + repository.commit_file(user, 'README', 'README!', + message: 'Add README', + branch_name: 'master', + update: true, + author_email: author_email, + author_name: author_name) end.to change { repository.commits('master').count }.by(1) last_commit = repository.commit @@ -302,7 +311,7 @@ describe Repository, models: true do it 'updates filename successfully' do expect do repository.update_file(user, 'NEWLICENSE', 'Copyright!', - branch: 'master', + branch_name: 'master', previous_path: 'LICENSE', message: 'Changes filename') end.to change { repository.commits('master').count }.by(1) @@ -315,15 +324,16 @@ describe Repository, models: true do context "when an author is specified" do it "uses the given email/name to set the commit's author" do - repository.commit_file(user, "README", 'README!', 'Add README', 'master', true) + repository.commit_file(user, 'README', 'README!', + message: 'Add README', branch_name: 'master', update: true) expect do - repository.update_file(user, 'README', "Updated README!", - branch: 'master', - previous_path: 'README', - message: 'Update README', - author_email: author_email, - author_name: author_name) + repository.update_file(user, 'README', 'Updated README!', + branch_name: 'master', + previous_path: 'README', + message: 'Update README', + author_email: author_email, + author_name: author_name) end.to change { repository.commits('master').count }.by(1) last_commit = repository.commit @@ -336,10 +346,12 @@ describe Repository, models: true do describe "#remove_file" do it 'removes file successfully' do - repository.commit_file(user, "README", 'README!', 'Add README', 'master', true) + repository.commit_file(user, 'README', 'README!', + message: 'Add README', branch_name: 'master', update: true) expect do - repository.remove_file(user, "README", "Remove README", 'master') + repository.remove_file(user, 'README', + message: 'Remove README', branch_name: 'master') end.to change { repository.commits('master').count }.by(1) expect(repository.blob_at('master', 'README')).to be_nil @@ -347,10 +359,13 @@ describe Repository, models: true do context "when an author is specified" do it "uses the given email/name to set the commit's author" do - repository.commit_file(user, "README", 'README!', 'Add README', 'master', true) + repository.commit_file(user, 'README', 'README!', + message: 'Add README', branch_name: 'master', update: true) expect do - repository.remove_file(user, "README", "Remove README", 'master', author_email: author_email, author_name: author_name) + repository.remove_file(user, 'README', + message: 'Remove README', branch_name: 'master', + author_email: author_email, author_name: author_name) end.to change { repository.commits('master').count }.by(1) last_commit = repository.commit @@ -498,11 +513,14 @@ describe Repository, models: true do describe "#license_blob", caching: true do before do - repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master') + repository.remove_file( + user, 'LICENSE', message: 'Remove LICENSE', branch_name: 'master') end it 'handles when HEAD points to non-existent ref' do - repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false) + repository.commit_file( + user, 'LICENSE', 'Copyright!', + message: 'Add LICENSE', branch_name: 'master', update: false) allow(repository).to receive(:file_on_head). and_raise(Rugged::ReferenceError) @@ -511,21 +529,27 @@ describe Repository, models: true do end it 'looks in the root_ref only' do - repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'markdown') - repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'markdown', false) + repository.remove_file(user, 'LICENSE', + message: 'Remove LICENSE', branch_name: 'markdown') + repository.commit_file(user, 'LICENSE', + Licensee::License.new('mit').content, + message: 'Add LICENSE', branch_name: 'markdown', update: false) expect(repository.license_blob).to be_nil end it 'detects license file with no recognizable open-source license content' do - repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false) + repository.commit_file(user, 'LICENSE', 'Copyright!', + message: 'Add LICENSE', branch_name: 'master', update: false) expect(repository.license_blob.name).to eq('LICENSE') end %w[LICENSE LICENCE LiCensE LICENSE.md LICENSE.foo COPYING COPYING.md].each do |filename| it "detects '#{filename}'" do - repository.commit_file(user, filename, Licensee::License.new('mit').content, "Add #{filename}", 'master', false) + repository.commit_file(user, filename, + Licensee::License.new('mit').content, + message: "Add #{filename}", branch_name: 'master', update: false) expect(repository.license_blob.name).to eq(filename) end @@ -534,7 +558,8 @@ describe Repository, models: true do describe '#license_key', caching: true do before do - repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master') + repository.remove_file(user, 'LICENSE', + message: 'Remove LICENSE', branch_name: 'master') end it 'returns nil when no license is detected' do @@ -548,13 +573,16 @@ describe Repository, models: true do end it 'detects license file with no recognizable open-source license content' do - repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false) + repository.commit_file(user, 'LICENSE', 'Copyright!', + message: 'Add LICENSE', branch_name: 'master', update: false) expect(repository.license_key).to be_nil end it 'returns the license key' do - repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false) + repository.commit_file(user, 'LICENSE', + Licensee::License.new('mit').content, + message: 'Add LICENSE', branch_name: 'master', update: false) expect(repository.license_key).to eq('mit') end @@ -815,7 +843,9 @@ describe Repository, models: true do expect(empty_repository).to receive(:expire_has_visible_content_cache) empty_repository.commit_file(user, 'CHANGELOG', 'Changelog!', - 'Updates file content', 'master', false) + message: 'Updates file content', + branch_name: 'master', + update: false) end end end -- GitLab From 23032467d4a1282f69e76bba921bd71c0083f7a8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 17:27:50 +0800 Subject: [PATCH 38/78] source_branch -> source_branch_name --- app/services/git_operation_service.rb | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index c8504ecf3cd..36c8b8ff575 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -134,27 +134,28 @@ GitOperationService = Struct.new(:user, :repository) do end end - def check_with_branch_arguments!(branch_name, source_branch, source_project) + def check_with_branch_arguments!( + branch_name, source_branch_name, source_project) return if repository.branch_exists?(branch_name) if repository.project != source_project - unless source_branch + unless source_branch_name raise ArgumentError, - 'Should also pass :source_branch if' + + 'Should also pass :source_branch_name if' + ' :source_project is different from current project' end - unless source_project.repository.commit(source_branch).try(:sha) + unless source_project.repository.commit(source_branch_name).try(:sha) raise Repository::CommitError.new( "Cannot find branch #{branch_name} nor" \ - " #{source_branch} from" \ + " #{source_branch_name} from" \ " #{source_project.path_with_namespace}") end - elsif source_branch - unless repository.commit(source_branch).try(:sha) + elsif source_branch_name + unless repository.commit(source_branch_name).try(:sha) raise Repository::CommitError.new( "Cannot find branch #{branch_name} nor" \ - " #{source_branch} from" \ + " #{source_branch_name} from" \ " #{repository.project.path_with_namespace}") end end -- GitLab From 8384d0d8d528ffdd60c9ba9e3c0c9f688cb560ef Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 17:57:52 +0800 Subject: [PATCH 39/78] Introduce Repository#with_tmp_ref which we need commits from the other repository. We'll cleanup the tmp ref after we're done with our business. --- .../projects/compare_controller.rb | 3 +- app/models/merge_request_diff.rb | 3 +- app/models/repository.rb | 15 ++++++++++ app/services/compare_service.rb | 30 +++++++++++-------- app/services/git_operation_service.rb | 15 +++++----- app/services/merge_requests/build_service.rb | 5 ++-- app/workers/emails_on_push_worker.rb | 6 ++-- spec/services/compare_service_spec.rb | 6 ++-- 8 files changed, 54 insertions(+), 29 deletions(-) diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index bee3d56076c..e2b178314c0 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -37,7 +37,8 @@ class Projects::CompareController < Projects::ApplicationController end def define_diff_vars - @compare = CompareService.new.execute(@project, @head_ref, @project, @start_ref) + @compare = CompareService.new(@project, @head_ref). + execute(@project, @start_ref) if @compare @commits = @compare.commits diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index b8f36a2c958..7946d8e123e 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -169,7 +169,8 @@ class MergeRequestDiff < ActiveRecord::Base # When compare merge request versions we want diff A..B instead of A...B # so we handle cases when user does squash and rebase of the commits between versions. # For this reason we set straight to true by default. - CompareService.new.execute(project, head_commit_sha, project, sha, straight: straight) + CompareService.new(project, head_commit_sha). + execute(project, sha, straight: straight) end def commits_count diff --git a/app/models/repository.rb b/app/models/repository.rb index 73a9e269a65..ced68b9d274 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1099,6 +1099,21 @@ class Repository Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:strip) end + def with_tmp_ref(source_repository, source_branch_name) + random_string = SecureRandom.hex + + fetch_ref( + source_repository.path_to_repo, + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch_name}", + "refs/tmp/#{random_string}/head" + ) + + yield + + ensure + FileUtils.rm_rf("#{path_to_repo}/refs/tmp/#{random_string}") + end + def fetch_ref(source_path, source_ref, target_ref) args = %W(#{Gitlab.config.git.bin_path} fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref}) Gitlab::Popen.popen(args, path_to_repo) diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 5e8fafca98c..4367cb5f615 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -3,23 +3,29 @@ require 'securerandom' # Compare 2 branches for one repo or between repositories # and return Gitlab::Git::Compare object that responds to commits and diffs class CompareService - def execute(source_project, source_branch, target_project, target_branch, straight: false) - source_commit = source_project.commit(source_branch) - return unless source_commit + attr_reader :source_project, :source_sha - source_sha = source_commit.sha + def initialize(new_source_project, source_branch) + @source_project = new_source_project + @source_sha = new_source_project.commit(source_branch).try(:sha) + end - # If compare with other project we need to fetch ref first - unless target_project == source_project - random_string = SecureRandom.hex + def execute(target_project, target_branch, straight: false) + return unless source_sha - target_project.repository.fetch_ref( - source_project.repository.path_to_repo, - "refs/heads/#{source_branch}", - "refs/tmp/#{random_string}/head" - ) + # If compare with other project we need to fetch ref first + if target_project == source_project + compare(target_project, target_branch, straight) + else + target_project.repository.with_tmp_ref(source_project, source_branch) do + compare(target_project, target_branch, straight) + end end + end + + private + def compare(target_project, target_branch, straight) raw_compare = Gitlab::Git::Compare.new( target_project.repository.raw_repository, target_branch, diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 36c8b8ff575..a7d267cd6b4 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -38,15 +38,14 @@ GitOperationService = Struct.new(:user, :repository) do branch_name, source_branch_name, source_project) update_branch_with_hooks(branch_name) do |ref| - if repository.project != source_project - repository.fetch_ref( - source_project.repository.path_to_repo, - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch_name}", - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch_name}" - ) + if repository.project == source_project + yield(ref) + else + repository.with_tmp_ref( + source_project.repository, source_branch_name) do + yield(ref) + end end - - yield(ref) end end diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb index bebfca7537b..a52a94c5ffa 100644 --- a/app/services/merge_requests/build_service.rb +++ b/app/services/merge_requests/build_service.rb @@ -16,9 +16,10 @@ module MergeRequests messages = validate_branches(merge_request) return build_failed(merge_request, messages) unless messages.empty? - compare = CompareService.new.execute( + compare = CompareService.new( merge_request.source_project, - merge_request.source_branch, + merge_request.source_branch + ).execute( merge_request.target_project, merge_request.target_branch, ) diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index b9cd49985dc..d4c3f14ec06 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -33,13 +33,15 @@ class EmailsOnPushWorker reverse_compare = false if action == :push - compare = CompareService.new.execute(project, after_sha, project, before_sha) + compare = CompareService.new(project, after_sha). + execute(project, before_sha) diff_refs = compare.diff_refs return false if compare.same if compare.commits.empty? - compare = CompareService.new.execute(project, before_sha, project, after_sha) + compare = CompareService.new(project, before_sha). + execute(project, after_sha) diff_refs = compare.diff_refs reverse_compare = true diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb index 3760f19aaa2..0a7fc58523f 100644 --- a/spec/services/compare_service_spec.rb +++ b/spec/services/compare_service_spec.rb @@ -3,17 +3,17 @@ require 'spec_helper' describe CompareService, services: true do let(:project) { create(:project) } let(:user) { create(:user) } - let(:service) { described_class.new } + let(:service) { described_class.new(project, 'feature') } describe '#execute' do context 'compare with base, like feature...fix' do - subject { service.execute(project, 'feature', project, 'fix', straight: false) } + subject { service.execute(project, 'fix', straight: false) } it { expect(subject.diffs.size).to eq(1) } end context 'straight compare, like feature..fix' do - subject { service.execute(project, 'feature', project, 'fix', straight: true) } + subject { service.execute(project, 'fix', straight: true) } it { expect(subject.diffs.size).to eq(3) } end -- GitLab From 07b9b80a8833cf44ba804c9b8dfdf1550785fe83 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 19:11:52 +0800 Subject: [PATCH 40/78] Fix tests to use the new API --- app/services/compare_service.rb | 14 ++++--- .../projects/templates_controller_spec.rb | 3 +- spec/factories/projects.rb | 34 +++++++++++++++- ...project_owner_creates_license_file_spec.rb | 3 +- .../projects/issuable_templates_spec.rb | 40 ++++++++++++++++--- spec/lib/gitlab/git_access_spec.rb | 8 +++- .../gitlab/template/issue_template_spec.rb | 19 +++++---- .../template/merge_request_template_spec.rb | 19 +++++---- .../models/cycle_analytics/production_spec.rb | 8 +++- spec/models/cycle_analytics/staging_spec.rb | 8 ++-- .../merge_requests/resolve_service_spec.rb | 8 +++- spec/support/cycle_analytics_helpers.rb | 8 +++- 12 files changed, 130 insertions(+), 42 deletions(-) diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 4367cb5f615..199a015622e 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -3,29 +3,31 @@ require 'securerandom' # Compare 2 branches for one repo or between repositories # and return Gitlab::Git::Compare object that responds to commits and diffs class CompareService - attr_reader :source_project, :source_sha + attr_reader :source_project, :source_branch - def initialize(new_source_project, source_branch) + def initialize(new_source_project, source_branch_name) @source_project = new_source_project - @source_sha = new_source_project.commit(source_branch).try(:sha) + @source_branch = new_source_project.commit(source_branch_name) end def execute(target_project, target_branch, straight: false) + source_sha = source_branch.try(:sha) + return unless source_sha # If compare with other project we need to fetch ref first if target_project == source_project - compare(target_project, target_branch, straight) + compare(source_sha, target_project, target_branch, straight) else target_project.repository.with_tmp_ref(source_project, source_branch) do - compare(target_project, target_branch, straight) + compare(source_sha, target_project, target_branch, straight) end end end private - def compare(target_project, target_branch, straight) + def compare(source_sha, target_project, target_branch, straight) raw_compare = Gitlab::Git::Compare.new( target_project.repository.raw_repository, target_branch, diff --git a/spec/controllers/projects/templates_controller_spec.rb b/spec/controllers/projects/templates_controller_spec.rb index 19a152bcb05..78e54e92a56 100644 --- a/spec/controllers/projects/templates_controller_spec.rb +++ b/spec/controllers/projects/templates_controller_spec.rb @@ -14,7 +14,8 @@ describe Projects::TemplatesController do before do project.add_user(user, Gitlab::Access::MASTER) - project.repository.commit_file(user, file_path_1, "something valid", "test 3", "master", false) + project.repository.commit_file(user, file_path_1, 'something valid', + message: 'test 3', branch_name: 'master', update: false) end describe '#show' do diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 1166498ddff..aa971e12a2e 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -91,8 +91,40 @@ FactoryGirl.define do factory :project, parent: :empty_project do path { 'gitlabhq' } - after :create do |project| + transient do + create_template nil + end + + after :create do |project, evaluator| TestEnv.copy_repo(project) + + if evaluator.create_template + args = evaluator.create_template + + project.add_user(args[:user], args[:access]) + + project.repository.commit_file( + args[:user], + ".gitlab/#{args[:path]}/bug.md", + 'something valid', + message: 'test 3', + branch_name: 'master', + update: false) + project.repository.commit_file( + args[:user], + ".gitlab/#{args[:path]}/template_test.md", + 'template_test', + message: 'test 1', + branch_name: 'master', + update: false) + project.repository.commit_file( + args[:user], + ".gitlab/#{args[:path]}/feature_proposal.md", + 'feature_proposal', + message: 'test 2', + branch_name: 'master', + update: false) + end end end diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index a521ce50f35..64094af29c0 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -6,7 +6,8 @@ feature 'project owner creates a license file', feature: true, js: true do let(:project_master) { create(:user) } let(:project) { create(:project) } background do - project.repository.remove_file(project_master, 'LICENSE', 'Remove LICENSE', 'master') + project.repository.remove_file(project_master, 'LICENSE', + message: 'Remove LICENSE', branch_name: 'master') project.team << [project_master, :master] login_as(project_master) visit namespace_project_path(project.namespace, project) diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index 2f377312ea5..daf08067ed1 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -18,8 +18,20 @@ feature 'issuable templates', feature: true, js: true do let(:description_addition) { ' appending to description' } background do - project.repository.commit_file(user, '.gitlab/issue_templates/bug.md', template_content, 'added issue template', 'master', false) - project.repository.commit_file(user, '.gitlab/issue_templates/test.md', longtemplate_content, 'added issue template', 'master', false) + project.repository.commit_file( + user, + '.gitlab/issue_templates/bug.md', + template_content, + message: 'added issue template', + branch_name: 'master', + update: false) + project.repository.commit_file( + user, + '.gitlab/issue_templates/test.md', + longtemplate_content, + message: 'added issue template', + branch_name: 'master', + update: false) visit edit_namespace_project_issue_path project.namespace, project, issue fill_in :'issue[title]', with: 'test issue title' end @@ -68,7 +80,13 @@ feature 'issuable templates', feature: true, js: true do let(:issue) { create(:issue, author: user, assignee: user, project: project) } background do - project.repository.commit_file(user, '.gitlab/issue_templates/bug.md', template_content, 'added issue template', 'master', false) + project.repository.commit_file( + user, + '.gitlab/issue_templates/bug.md', + template_content, + message: 'added issue template', + branch_name: 'master', + update: false) visit edit_namespace_project_issue_path project.namespace, project, issue fill_in :'issue[title]', with: 'test issue title' fill_in :'issue[description]', with: prior_description @@ -87,7 +105,13 @@ feature 'issuable templates', feature: true, js: true do let(:merge_request) { create(:merge_request, :with_diffs, source_project: project) } background do - project.repository.commit_file(user, '.gitlab/merge_request_templates/feature-proposal.md', template_content, 'added merge request template', 'master', false) + project.repository.commit_file( + user, + '.gitlab/merge_request_templates/feature-proposal.md', + template_content, + message: 'added merge request template', + branch_name: 'master', + update: false) visit edit_namespace_project_merge_request_path project.namespace, project, merge_request fill_in :'merge_request[title]', with: 'test merge request title' end @@ -112,7 +136,13 @@ feature 'issuable templates', feature: true, js: true do fork_project.team << [fork_user, :master] create(:forked_project_link, forked_to_project: fork_project, forked_from_project: project) login_as fork_user - project.repository.commit_file(fork_user, '.gitlab/merge_request_templates/feature-proposal.md', template_content, 'added merge request template', 'master', false) + project.repository.commit_file( + fork_user, + '.gitlab/merge_request_templates/feature-proposal.md', + template_content, + message: 'added merge request template', + branch_name: 'master', + update: false) visit edit_namespace_project_merge_request_path project.namespace, project, merge_request fill_in :'merge_request[title]', with: 'test merge request title' end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index f1d0a190002..a48287b7a75 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -209,7 +209,13 @@ describe Gitlab::GitAccess, lib: true do stub_git_hooks project.repository.add_branch(user, unprotected_branch, 'feature') target_branch = project.repository.lookup('feature') - source_branch = project.repository.commit_file(user, FFaker::InternetSE.login_user_name, FFaker::HipsterIpsum.paragraph, FFaker::HipsterIpsum.sentence, unprotected_branch, false) + source_branch = project.repository.commit_file( + user, + FFaker::InternetSE.login_user_name, + FFaker::HipsterIpsum.paragraph, + message: FFaker::HipsterIpsum.sentence, + branch_name: unprotected_branch, + update: false) rugged = project.repository.rugged author = { email: "email@example.com", time: Time.now, name: "Example Git User" } diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb index d2d334e6413..984236b74ce 100644 --- a/spec/lib/gitlab/template/issue_template_spec.rb +++ b/spec/lib/gitlab/template/issue_template_spec.rb @@ -4,16 +4,15 @@ describe Gitlab::Template::IssueTemplate do subject { described_class } let(:user) { create(:user) } - let(:project) { create(:project) } - let(:file_path_1) { '.gitlab/issue_templates/bug.md' } - let(:file_path_2) { '.gitlab/issue_templates/template_test.md' } - let(:file_path_3) { '.gitlab/issue_templates/feature_proposal.md' } - - before do - project.add_user(user, Gitlab::Access::MASTER) - project.repository.commit_file(user, file_path_1, "something valid", "test 3", "master", false) - project.repository.commit_file(user, file_path_2, "template_test", "test 1", "master", false) - project.repository.commit_file(user, file_path_3, "feature_proposal", "test 2", "master", false) + + let(:project) do + create(:project, + create_template: { + user: user, + access: Gitlab::Access::MASTER, + path: 'issue_templates' + } + ) end describe '.all' do diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb index ddf68c4cf78..e98a8beccdd 100644 --- a/spec/lib/gitlab/template/merge_request_template_spec.rb +++ b/spec/lib/gitlab/template/merge_request_template_spec.rb @@ -4,16 +4,15 @@ describe Gitlab::Template::MergeRequestTemplate do subject { described_class } let(:user) { create(:user) } - let(:project) { create(:project) } - let(:file_path_1) { '.gitlab/merge_request_templates/bug.md' } - let(:file_path_2) { '.gitlab/merge_request_templates/template_test.md' } - let(:file_path_3) { '.gitlab/merge_request_templates/feature_proposal.md' } - - before do - project.add_user(user, Gitlab::Access::MASTER) - project.repository.commit_file(user, file_path_1, "something valid", "test 3", "master", false) - project.repository.commit_file(user, file_path_2, "template_test", "test 1", "master", false) - project.repository.commit_file(user, file_path_3, "feature_proposal", "test 2", "master", false) + + let(:project) do + create(:project, + create_template: { + user: user, + access: Gitlab::Access::MASTER, + path: 'merge_request_templates' + } + ) end describe '.all' do diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb index 21b9c6e7150..97568c47903 100644 --- a/spec/models/cycle_analytics/production_spec.rb +++ b/spec/models/cycle_analytics/production_spec.rb @@ -21,7 +21,13 @@ describe 'CycleAnalytics#production', feature: true do ["production deploy happens after merge request is merged (along with other changes)", lambda do |context, data| # Make other changes on master - sha = context.project.repository.commit_file(context.user, context.random_git_name, "content", "commit message", 'master', false) + sha = context.project.repository.commit_file( + context.user, + context.random_git_name, + 'content', + message: 'commit message', + branch_name: 'master', + update: false) context.project.repository.commit(sha) context.deploy_master diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb index dad653964b7..27c826110fb 100644 --- a/spec/models/cycle_analytics/staging_spec.rb +++ b/spec/models/cycle_analytics/staging_spec.rb @@ -28,10 +28,10 @@ describe 'CycleAnalytics#staging', feature: true do sha = context.project.repository.commit_file( context.user, context.random_git_name, - "content", - "commit message", - 'master', - false) + 'content', + message: 'commit message', + branch_name: 'master', + update: false) context.project.repository.commit(sha) context.deploy_master diff --git a/spec/services/merge_requests/resolve_service_spec.rb b/spec/services/merge_requests/resolve_service_spec.rb index 388abb6a0df..a0e51681725 100644 --- a/spec/services/merge_requests/resolve_service_spec.rb +++ b/spec/services/merge_requests/resolve_service_spec.rb @@ -66,7 +66,13 @@ describe MergeRequests::ResolveService do context 'when the source project is a fork and does not contain the HEAD of the target branch' do let!(:target_head) do - project.repository.commit_file(user, 'new-file-in-target', '', 'Add new file in target', 'conflict-start', false) + project.repository.commit_file( + user, + 'new-file-in-target', + '', + message: 'Add new file in target', + branch_name: 'conflict-start', + update: false) end before do diff --git a/spec/support/cycle_analytics_helpers.rb b/spec/support/cycle_analytics_helpers.rb index 75c95d70951..6ed55289ed9 100644 --- a/spec/support/cycle_analytics_helpers.rb +++ b/spec/support/cycle_analytics_helpers.rb @@ -35,7 +35,13 @@ module CycleAnalyticsHelpers project.repository.add_branch(user, source_branch, 'master') end - sha = project.repository.commit_file(user, random_git_name, "content", "commit message", source_branch, false) + sha = project.repository.commit_file( + user, + random_git_name, + 'content', + message: 'commit message', + branch_name: source_branch, + update: false) project.repository.commit(sha) opts = { -- GitLab From 9c6563f64a3a770cccb9fcf3eb609416c2466080 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 19:46:51 +0800 Subject: [PATCH 41/78] rubocop prefers lisp style --- spec/lib/gitlab/template/issue_template_spec.rb | 4 +--- spec/lib/gitlab/template/merge_request_template_spec.rb | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb index 984236b74ce..4275fda5c74 100644 --- a/spec/lib/gitlab/template/issue_template_spec.rb +++ b/spec/lib/gitlab/template/issue_template_spec.rb @@ -10,9 +10,7 @@ describe Gitlab::Template::IssueTemplate do create_template: { user: user, access: Gitlab::Access::MASTER, - path: 'issue_templates' - } - ) + path: 'issue_templates' }) end describe '.all' do diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb index e98a8beccdd..708bb084eef 100644 --- a/spec/lib/gitlab/template/merge_request_template_spec.rb +++ b/spec/lib/gitlab/template/merge_request_template_spec.rb @@ -10,9 +10,7 @@ describe Gitlab::Template::MergeRequestTemplate do create_template: { user: user, access: Gitlab::Access::MASTER, - path: 'merge_request_templates' - } - ) + path: 'merge_request_templates' }) end describe '.all' do -- GitLab From e7599eb0b76f7ef199e8719377a212f53aaa17f8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 8 Dec 2016 19:49:20 +0800 Subject: [PATCH 42/78] Should pass repository rather than project --- app/services/compare_service.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 199a015622e..fcbfe68f1a3 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -19,7 +19,8 @@ class CompareService if target_project == source_project compare(source_sha, target_project, target_branch, straight) else - target_project.repository.with_tmp_ref(source_project, source_branch) do + target_project.repository.with_tmp_ref( + source_project.repository, source_branch) do compare(source_sha, target_project, target_branch, straight) end end -- GitLab From 56f697466d288c3bff16cc270e5cb2c50c9c14c8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 9 Dec 2016 20:05:35 +0800 Subject: [PATCH 43/78] Introduce git_action and normalize previous_path Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19747456 --- app/models/repository.rb | 72 +++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 1684aa97567..9d554991ab4 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -862,32 +862,8 @@ class Repository [] end - actions.each do |action| - path = Gitlab::Git::PathHelper.normalize_path(action[:file_path]).to_s - - raise Gitlab::Git::Repository::InvalidBlobName.new("Invalid path") if - path.split('/').include?('..') - - case action[:action] - when :create, :update, :move - mode = - case action[:action] - when :update - index.get(path)[:mode] - when :move - index.get(action[:previous_path])[:mode] - end - mode ||= 0o100644 - - index.remove(action[:previous_path]) if action[:action] == :move - - content = action[:encoding] == 'base64' ? Base64.decode64(action[:content]) : action[:content] - oid = rugged.write(content, :blob) - - index.add(path: path, oid: oid, mode: mode) - when :delete - index.remove(path) - end + actions.each do |act| + git_action(index, act) end options = { @@ -1181,6 +1157,50 @@ class Repository private + def git_action(index, action) + path = normalize_path(action[:file_path]) + + if action[:action] == :move + previous_path = normalize_path(action[:previous_path]) + end + + case action[:action] + when :create, :update, :move + mode = + case action[:action] + when :update + index.get(path)[:mode] + when :move + index.get(previous_path)[:mode] + end + mode ||= 0o100644 + + index.remove(previous_path) if action[:action] == :move + + content = if action[:encoding] == 'base64' + Base64.decode64(action[:content]) + else + action[:content] + end + + oid = rugged.write(content, :blob) + + index.add(path: path, oid: oid, mode: mode) + when :delete + index.remove(path) + end + end + + def normalize_path(path) + pathname = Gitlab::Git::PathHelper.normalize_path(path) + + if pathname.each_filename.include?('..') + raise Gitlab::Git::Repository::InvalidBlobName.new('Invalid path') + end + + pathname.to_s + end + def refs_directory_exists? return false unless path_with_namespace -- GitLab From 5a115671b9d7c22daf8160d7284786d0f8b216cb Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 9 Dec 2016 20:06:19 +0800 Subject: [PATCH 44/78] Use rugged.references.delete to delete reference Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19746468 --- app/models/repository.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 9d554991ab4..389d52f8c0f 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1064,18 +1064,18 @@ class Repository end def with_tmp_ref(source_repository, source_branch_name) - random_string = SecureRandom.hex + tmp_ref = "refs/tmp/#{SecureRandom.hex}/head" fetch_ref( source_repository.path_to_repo, "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch_name}", - "refs/tmp/#{random_string}/head" + tmp_ref ) yield ensure - FileUtils.rm_rf("#{path_to_repo}/refs/tmp/#{random_string}") + rugged.references.delete(tmp_ref) end def fetch_ref(source_path, source_ref, target_ref) -- GitLab From bb9d30590d4ca5b25d5020234916ce961acf15b6 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Sat, 10 Dec 2016 00:40:23 +0800 Subject: [PATCH 45/78] Pass source_commit so that we save a few lookups --- app/models/repository.rb | 51 ++++++++++----------------- app/services/git_operation_service.rb | 25 ++++++------- spec/models/repository_spec.rb | 28 ++++++++++++--- 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 389d52f8c0f..4034a49ae63 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -849,15 +849,12 @@ class Repository GitOperationService.new(user, self).with_branch( branch_name, source_branch_name: source_branch_name, - source_project: source_project) do + source_project: source_project) do |source_commit| index = rugged.index - branch_commit = source_project.repository.find_branch( - source_branch_name || branch_name) - parents = if branch_commit - last_commit = branch_commit.dereferenced_target - index.read_tree(last_commit.raw_commit.tree) - [last_commit.sha] + parents = if source_commit + index.read_tree(source_commit.raw_commit.tree) + [source_commit.sha] else [] end @@ -904,17 +901,17 @@ class Repository end def merge(user, merge_request, options = {}) - our_commit = rugged.branches[merge_request.target_branch].target - their_commit = rugged.lookup(merge_request.diff_head_sha) + GitOperationService.new(user, self).with_branch( + merge_request.target_branch) do |source_commit| + our_commit = source_commit.raw_commit + their_commit = rugged.lookup(merge_request.diff_head_sha) - raise "Invalid merge target" if our_commit.nil? - raise "Invalid merge source" if their_commit.nil? + raise 'Invalid merge target' unless our_commit + raise 'Invalid merge source' unless their_commit - merge_index = rugged.merge_commits(our_commit, their_commit) - return false if merge_index.conflicts? + merge_index = rugged.merge_commits(our_commit, their_commit) + break if merge_index.conflicts? - GitOperationService.new(user, self).with_branch( - merge_request.target_branch) do actual_options = options.merge( parents: [our_commit, their_commit], tree: merge_index.write_tree(rugged), @@ -924,6 +921,8 @@ class Repository merge_request.update(in_progress_merge_commit_sha: commit_id) commit_id end + rescue Repository::CommitError # when merge_index.conflicts? + false end def revert( @@ -936,10 +935,8 @@ class Repository GitOperationService.new(user, self).with_branch( branch_name, source_branch_name: source_branch_name, - source_project: source_project) do + source_project: source_project) do |source_commit| - source_sha = source_project.repository.find_source_sha( - source_branch_name || branch_name) committer = user_to_committer(user) Rugged::Commit.create(rugged, @@ -947,7 +944,7 @@ class Repository author: committer, committer: committer, tree: revert_tree_id, - parents: [rugged.lookup(source_sha)]) + parents: [source_commit.sha]) end end @@ -961,10 +958,8 @@ class Repository GitOperationService.new(user, self).with_branch( branch_name, source_branch_name: source_branch_name, - source_project: source_project) do + source_project: source_project) do |source_commit| - source_sha = source_project.repository.find_source_sha( - source_branch_name || branch_name) committer = user_to_committer(user) Rugged::Commit.create(rugged, @@ -976,7 +971,7 @@ class Repository }, committer: committer, tree: cherry_pick_tree_id, - parents: [rugged.lookup(source_sha)]) + parents: [source_commit.sha]) end end @@ -1145,16 +1140,6 @@ class Repository end end - protected - - def find_source_sha(branch_name) - if branch_exists?(branch_name) - find_branch(branch_name).dereferenced_target.sha - else - Gitlab::Git::BLANK_SHA - end - end - private def git_action(index, action) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index a7d267cd6b4..62a9eda3eba 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -37,13 +37,16 @@ GitOperationService = Struct.new(:user, :repository) do check_with_branch_arguments!( branch_name, source_branch_name, source_project) - update_branch_with_hooks(branch_name) do |ref| + source_commit = source_project.repository.find_branch( + source_branch_name || branch_name).try(:dereferenced_target) + + update_branch_with_hooks(branch_name) do if repository.project == source_project - yield(ref) + yield(source_commit) else repository.with_tmp_ref( source_project.repository, source_branch_name) do - yield(ref) + yield(source_commit) end end end @@ -54,31 +57,29 @@ GitOperationService = Struct.new(:user, :repository) do def update_branch_with_hooks(branch_name) update_autocrlf_option - ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name - oldrev = Gitlab::Git::BLANK_SHA was_empty = repository.empty? # Make commit - newrev = yield(ref) + newrev = yield unless newrev raise Repository::CommitError.new('Failed to create commit') end branch = repository.find_branch(branch_name) - oldrev = if repository.rugged.lookup(newrev).parent_ids.empty? || - branch.nil? - Gitlab::Git::BLANK_SHA + oldrev = if branch + # This could verify we're not losing commits + repository.rugged.merge_base(newrev, branch.target) else - repository.rugged.merge_base( - newrev, branch.dereferenced_target.sha) + Gitlab::Git::BLANK_SHA end + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name with_hooks_and_update_ref(ref, oldrev, newrev) do # If repo was empty expire cache repository.after_create if was_empty repository.after_create_branch if was_empty || - oldrev == Gitlab::Git::BLANK_SHA + Gitlab::Git.blank_ref?(oldrev) end newrev diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 9cc13a9a25b..a61d7f0c76d 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -257,6 +257,24 @@ describe Repository, models: true do expect(newdir.path).to eq('newdir') end + context "when committing to another project" do + let(:forked_project) { create(:project) } + + it "creates a fork and commit to the forked project" do + expect do + repository.commit_dir(user, 'newdir', + message: 'Create newdir', branch_name: 'patch', + source_branch_name: 'master', source_project: forked_project) + end.to change { repository.commits('master').count }.by(0) + + expect(repository.branch_exists?('patch')).to be_truthy + expect(forked_project.repository.branch_exists?('patch')).to be_falsy + + newdir = repository.tree('patch', 'newdir') + expect(newdir.path).to eq('newdir') + end + end + context "when an author is specified" do it "uses the given email/name to set the commit's author" do expect do @@ -758,9 +776,9 @@ describe Repository, models: true do end context 'when the update adds more than one commit' do - it 'runs without errors' do - old_rev = '33f3729a45c02fc67d00adb1b8bca394b0e761d9' + let(:old_rev) { '33f3729a45c02fc67d00adb1b8bca394b0e761d9' } + it 'runs without errors' do # old_rev is an ancestor of new_rev expect(repository.rugged.merge_base(old_rev, new_rev)).to eq(old_rev) @@ -779,10 +797,10 @@ describe Repository, models: true do end context 'when the update would remove commits from the target branch' do - it 'raises an exception' do - branch = 'master' - old_rev = repository.find_branch(branch).dereferenced_target.sha + let(:branch) { 'master' } + let(:old_rev) { repository.find_branch(branch).dereferenced_target.sha } + it 'raises an exception' do # The 'master' branch is NOT an ancestor of new_rev. expect(repository.rugged.merge_base(old_rev, new_rev)).not_to eq(old_rev) -- GitLab From 3e01385bca92dc8c0df3aa4032cc58d708dc0ff5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Sat, 10 Dec 2016 01:23:49 +0800 Subject: [PATCH 46/78] Should pass branch name, not commit object! --- app/services/compare_service.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index fcbfe68f1a3..31c371c4b34 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -3,15 +3,16 @@ require 'securerandom' # Compare 2 branches for one repo or between repositories # and return Gitlab::Git::Compare object that responds to commits and diffs class CompareService - attr_reader :source_project, :source_branch + attr_reader :source_project, :source_branch_name - def initialize(new_source_project, source_branch_name) + def initialize(new_source_project, new_source_branch_name) @source_project = new_source_project - @source_branch = new_source_project.commit(source_branch_name) + @source_branch_name = new_source_branch_name end def execute(target_project, target_branch, straight: false) - source_sha = source_branch.try(:sha) + source_sha = source_project.repository. + commit(source_branch_name).try(:sha) return unless source_sha @@ -20,7 +21,7 @@ class CompareService compare(source_sha, target_project, target_branch, straight) else target_project.repository.with_tmp_ref( - source_project.repository, source_branch) do + source_project.repository, source_branch_name) do compare(source_sha, target_project, target_branch, straight) end end -- GitLab From c0dfa0c609805558b30f11046eedadfb8a14886d Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Mon, 12 Dec 2016 23:07:52 +0800 Subject: [PATCH 47/78] Not sure why, but apparently SHA works better It's very weird that source_commit.raw_commit and rugged.branches[merge_request.target_branch].target should be completely the same. I checked with == and other values which proved that both should be the same, but still tests cannot pass for: spec/services/merge_requests/refresh_service_spec.rb I decided to give it up. We could just use SHA and that works fine anyway. --- app/models/repository.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 44f66b89600..7a7236993a8 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -903,8 +903,8 @@ class Repository def merge(user, merge_request, options = {}) GitOperationService.new(user, self).with_branch( merge_request.target_branch) do |source_commit| - our_commit = source_commit.raw_commit - their_commit = rugged.lookup(merge_request.diff_head_sha) + our_commit = source_commit.sha + their_commit = merge_request.diff_head_sha raise 'Invalid merge target' unless our_commit raise 'Invalid merge source' unless their_commit -- GitLab From 26af4b5a61d5cdaffa7769336f40cd0861f6b1d4 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 14 Dec 2016 01:21:48 +0800 Subject: [PATCH 48/78] Also check blob path from source branch Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19747244 --- app/models/repository.rb | 57 +++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 7a7236993a8..2e706b770b2 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -738,19 +738,11 @@ class Repository message:, branch_name:, author_email: nil, author_name: nil, source_branch_name: nil, source_project: project) - if branch_exists?(branch_name) - # tree_entry is private - entry = raw_repository.send(:tree_entry, commit(branch_name), path) - - if entry - if entry[:type] == :blob - raise Gitlab::Git::Repository::InvalidBlobName.new( - "Directory already exists as a file") - else - raise Gitlab::Git::Repository::InvalidBlobName.new( - "Directory already exists") - end - end + check_tree_entry_for_dir(branch_name, path) + + if source_branch_name + source_project.repository. + check_tree_entry_for_dir(source_branch_name, path) end commit_file( @@ -773,11 +765,16 @@ class Repository message:, branch_name:, update: true, author_email: nil, author_name: nil, source_branch_name: nil, source_project: project) - if branch_exists?(branch_name) && update == false - # tree_entry is private - if raw_repository.send(:tree_entry, commit(branch_name), path) - raise Gitlab::Git::Repository::InvalidBlobName.new( - "Filename already exists; update not allowed") + unless update + error_message = "Filename already exists; update not allowed" + + if tree_entry_at(branch_name, path) + raise Gitlab::Git::Repository::InvalidBlobName.new(error_message) + end + + if source_branch_name && + source_project.repository.tree_entry_at(source_branch_name, path) + raise Gitlab::Git::Repository::InvalidBlobName.new(error_message) end end @@ -1140,6 +1137,30 @@ class Repository end end + protected + + def tree_entry_at(branch_name, path) + branch_exists?(branch_name) && + # tree_entry is private + raw_repository.send(:tree_entry, commit(branch_name), path) + end + + def check_tree_entry_for_dir(branch_name, path) + return unless branch_exists?(branch_name) + + entry = tree_entry_at(branch_name, path) + + return unless entry + + if entry[:type] == :blob + raise Gitlab::Git::Repository::InvalidBlobName.new( + "Directory already exists as a file") + else + raise Gitlab::Git::Repository::InvalidBlobName.new( + "Directory already exists") + end + end + private def git_action(index, action) -- GitLab From dc4b3dd0ae5d6e0b55ba6723e5deff6eee127409 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 14 Dec 2016 01:47:17 +0800 Subject: [PATCH 49/78] Fix source_project and also pass source_project Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19747556 --- app/controllers/concerns/creates_commit.rb | 4 ++-- app/services/commits/change_service.rb | 1 + app/services/files/create_dir_service.rb | 1 + app/services/files/create_service.rb | 1 + app/services/files/delete_service.rb | 1 + app/services/files/multi_service.rb | 1 + 6 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index d2fcb2efd6a..a94077c2bd4 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -6,12 +6,12 @@ module CreatesCommit source_branch = @ref if @ref && @repository.find_branch(@ref) commit_params = @commit_params.merge( - source_project: @project, + source_project: @tree_edit_project, source_branch: source_branch, target_branch: @target_branch ) - result = service.new(@tree_edit_project, current_user, commit_params).execute + result = service.new(@project, current_user, commit_params).execute if result[:status] == :success update_flash_notice(success_notice) diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 99d459908e7..9c630f5bbf1 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -37,6 +37,7 @@ module Commits @commit, into, tree_id, + source_project: @source_project, source_branch_name: @target_branch) success diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb index 4a2b2e8fcaf..ee4e130a38f 100644 --- a/app/services/files/create_dir_service.rb +++ b/app/services/files/create_dir_service.rb @@ -8,6 +8,7 @@ module Files branch_name: @target_branch, author_email: @author_email, author_name: @author_name, + source_project: @source_project, source_branch_name: @source_branch) end diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index c95cb75f7cb..853c471666d 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -10,6 +10,7 @@ module Files update: false, author_email: @author_email, author_name: @author_name, + source_project: @source_project, source_branch_name: @source_branch) end diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb index 45a9a559469..cfe532d49b3 100644 --- a/app/services/files/delete_service.rb +++ b/app/services/files/delete_service.rb @@ -8,6 +8,7 @@ module Files branch_name: @target_branch, author_email: @author_email, author_name: @author_name, + source_project: @source_project, source_branch_name: @source_branch) end end diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb index 42ed97ca3c0..f77e5d91103 100644 --- a/app/services/files/multi_service.rb +++ b/app/services/files/multi_service.rb @@ -10,6 +10,7 @@ module Files actions: params[:actions], author_email: @author_email, author_name: @author_name, + source_project: @source_project, source_branch_name: @source_branch ) end -- GitLab From 46d752ce218d833ff947bd4503de56300471a8cb Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 14 Dec 2016 02:03:04 +0800 Subject: [PATCH 50/78] Use a regular class for GitOperationService Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19747793 --- app/services/git_operation_service.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 62a9eda3eba..9a052f952cf 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -1,5 +1,12 @@ -GitOperationService = Struct.new(:user, :repository) do +class GitOperationService + attr_reader :user, :repository + + def initialize(new_user, new_repository) + @user = new_user + @repository = new_repository + end + def add_branch(branch_name, newrev) ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name oldrev = Gitlab::Git::BLANK_SHA -- GitLab From d03c605bd4a128d45179dd05f117a78aab7af6be Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 14 Dec 2016 02:29:35 +0800 Subject: [PATCH 51/78] Unify parameters and callback after hooks Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19747856 --- app/services/git_operation_service.rb | 34 +++++++++---------- lib/gitlab/git.rb | 2 +- spec/models/repository_spec.rb | 7 ++-- .../git_garbage_collect_worker_spec.rb | 2 +- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 9a052f952cf..68b28231595 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -11,7 +11,7 @@ class GitOperationService ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name oldrev = Gitlab::Git::BLANK_SHA - with_hooks_and_update_ref(ref, oldrev, newrev) + update_ref_in_hooks(ref, newrev, oldrev) end def rm_branch(branch) @@ -19,14 +19,14 @@ class GitOperationService oldrev = branch.dereferenced_target.id newrev = Gitlab::Git::BLANK_SHA - with_hooks_and_update_ref(ref, oldrev, newrev) + update_ref_in_hooks(ref, newrev, oldrev) end def add_tag(tag_name, newrev, options = {}) ref = Gitlab::Git::TAG_REF_PREFIX + tag_name oldrev = Gitlab::Git::BLANK_SHA - with_hooks(ref, oldrev, newrev) do |service| + with_hooks(ref, newrev, oldrev) do |service| raw_tag = repository.rugged.tags.create(tag_name, newrev, options) service.newrev = raw_tag.target_id end @@ -82,25 +82,23 @@ class GitOperationService end ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name - with_hooks_and_update_ref(ref, oldrev, newrev) do - # If repo was empty expire cache - repository.after_create if was_empty - repository.after_create_branch if was_empty || - Gitlab::Git.blank_ref?(oldrev) - end + update_ref_in_hooks(ref, newrev, oldrev) + + # If repo was empty expire cache + repository.after_create if was_empty + repository.after_create_branch if was_empty || + Gitlab::Git.blank_ref?(oldrev) newrev end - def with_hooks_and_update_ref(ref, oldrev, newrev) - with_hooks(ref, oldrev, newrev) do |service| - update_ref!(ref, newrev, oldrev) - - yield(service) if block_given? + def update_ref_in_hooks(ref, newrev, oldrev) + with_hooks(ref, newrev, oldrev) do + update_ref(ref, newrev, oldrev) end end - def with_hooks(ref, oldrev, newrev) + def with_hooks(ref, newrev, oldrev) result = nil GitHooksService.new.execute( @@ -116,7 +114,7 @@ class GitOperationService result end - def update_ref!(name, newrev, oldrev) + def update_ref(ref, newrev, oldrev) # We use 'git update-ref' because libgit2/rugged currently does not # offer 'compare and swap' ref updates. Without compare-and-swap we can # (and have!) accidentally reset the ref to an earlier state, clobbering @@ -125,12 +123,12 @@ class GitOperationService _, status = Gitlab::Popen.popen( command, repository.path_to_repo) do |stdin| - stdin.write("update #{name}\x00#{newrev}\x00#{oldrev}\x00") + stdin.write("update #{ref}\x00#{newrev}\x00#{oldrev}\x00") end unless status.zero? raise Repository::CommitError.new( - "Could not update branch #{name.sub('refs/heads/', '')}." \ + "Could not update branch #{Gitlab::Git.branch_name(ref)}." \ " Please refresh and try again.") end end diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb index 3cd515e4a3a..d3df3f1bca1 100644 --- a/lib/gitlab/git.rb +++ b/lib/gitlab/git.rb @@ -6,7 +6,7 @@ module Gitlab class << self def ref_name(ref) - ref.gsub(/\Arefs\/(tags|heads)\//, '') + ref.sub(/\Arefs\/(tags|heads)\//, '') end def branch_name(ref) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index a61d7f0c76d..65e96351033 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -829,7 +829,6 @@ describe Repository, models: true do context 'when target branch is different from source branch' do before do allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, '']) - allow(repository).to receive(:update_ref!) end it 'expires branch cache' do @@ -1474,16 +1473,16 @@ describe Repository, models: true do end end - describe '#update_ref!' do + describe '#update_ref' do it 'can create a ref' do - GitOperationService.new(nil, repository).send(:update_ref!, 'refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA) + GitOperationService.new(nil, repository).send(:update_ref, 'refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA) expect(repository.find_branch('foobar')).not_to be_nil end it 'raises CommitError when the ref update fails' do expect do - GitOperationService.new(nil, repository).send(:update_ref!, 'refs/heads/master', 'refs/heads/master', Gitlab::Git::BLANK_SHA) + GitOperationService.new(nil, repository).send(:update_ref, 'refs/heads/master', 'refs/heads/master', Gitlab::Git::BLANK_SHA) end.to raise_error(Repository::CommitError) end end diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index 2b31efbf631..5ef8cf1105b 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -108,7 +108,7 @@ describe GitGarbageCollectWorker do parents: [old_commit], ) GitOperationService.new(nil, project.repository).send( - :update_ref!, + :update_ref, "refs/heads/#{SecureRandom.hex(6)}", new_commit_sha, Gitlab::Git::BLANK_SHA -- GitLab From 944a8fa4d204ce7e9967f372a61657e75b4e88a0 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 14 Dec 2016 03:00:16 +0800 Subject: [PATCH 52/78] Use branch_exists? to check branches Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19747922 --- app/services/git_operation_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 68b28231595..b00fbcf9a79 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -150,14 +150,14 @@ class GitOperationService ' :source_project is different from current project' end - unless source_project.repository.commit(source_branch_name).try(:sha) + unless source_project.repository.branch_exists?(source_branch_name) raise Repository::CommitError.new( "Cannot find branch #{branch_name} nor" \ " #{source_branch_name} from" \ " #{source_project.path_with_namespace}") end elsif source_branch_name - unless repository.commit(source_branch_name).try(:sha) + unless repository.branch_exists?(source_branch_name) raise Repository::CommitError.new( "Cannot find branch #{branch_name} nor" \ " #{source_branch_name} from" \ -- GitLab From 56d131dcd52cba98e0eee253cab8bbf0b3b706df Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 14 Dec 2016 03:03:20 +0800 Subject: [PATCH 53/78] Use ArgumentError error instead because it's a bug if it happens. Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_19747933 --- app/services/git_operation_service.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index b00fbcf9a79..0d1bd05e552 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -151,17 +151,17 @@ class GitOperationService end unless source_project.repository.branch_exists?(source_branch_name) - raise Repository::CommitError.new( + raise ArgumentError, "Cannot find branch #{branch_name} nor" \ " #{source_branch_name} from" \ - " #{source_project.path_with_namespace}") + " #{source_project.path_with_namespace}" end elsif source_branch_name unless repository.branch_exists?(source_branch_name) - raise Repository::CommitError.new( + raise ArgumentError, "Cannot find branch #{branch_name} nor" \ " #{source_branch_name} from" \ - " #{repository.project.path_with_namespace}") + " #{repository.project.path_with_namespace}" end end end -- GitLab From 99b556976370bfe0c052d15b6a8f0642256173fd Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 14 Dec 2016 03:33:43 +0800 Subject: [PATCH 54/78] Try to use those @mr variables for full correctness --- app/controllers/concerns/creates_commit.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index a94077c2bd4..f0e6fc4b3e8 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,14 +4,16 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - source_branch = @ref if @ref && @repository.find_branch(@ref) + source_branch = @ref if @ref && + @mr_source_project.repository.branch_exists?(@ref) commit_params = @commit_params.merge( - source_project: @tree_edit_project, + source_project: @mr_source_project, source_branch: source_branch, - target_branch: @target_branch + target_branch: @mr_target_branch ) - result = service.new(@project, current_user, commit_params).execute + result = service.new( + @mr_target_project, current_user, commit_params).execute if result[:status] == :success update_flash_notice(success_notice) -- GitLab From 14c4db2ae4efa1187476f11569df1b77c9c055fa Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 4 Jan 2017 22:31:06 +0800 Subject: [PATCH 55/78] Add a comment to explain why newrev should be updated Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_20301332 --- app/services/git_operation_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 0d1bd05e552..5acfdb0f9e2 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -1,4 +1,3 @@ - class GitOperationService attr_reader :user, :repository @@ -28,6 +27,9 @@ class GitOperationService with_hooks(ref, newrev, oldrev) do |service| raw_tag = repository.rugged.tags.create(tag_name, newrev, options) + + # If raw_tag is an annotated tag, we'll need to update newrev to point + # to the new revision. service.newrev = raw_tag.target_id end end -- GitLab From c1a75c3c0b59af7a9e6af3ff834adf56256aa2ce Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 4 Jan 2017 22:32:36 +0800 Subject: [PATCH 56/78] Prefer leading dots over trailing dots Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_20601323 --- app/controllers/projects/compare_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 325987199fa..d359920c91e 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -37,8 +37,8 @@ class Projects::CompareController < Projects::ApplicationController end def define_diff_vars - @compare = CompareService.new(@project, @head_ref). - execute(@project, @start_ref) + @compare = CompareService.new(@project, @head_ref) + .execute(@project, @start_ref) if @compare @commits = @compare.commits -- GitLab From ecac2f1122f093455e7b9e5d054157241dcd5cff Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Wed, 4 Jan 2017 22:50:01 +0800 Subject: [PATCH 57/78] Update the comment: Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_20876648 --- app/services/git_operation_service.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 5acfdb0f9e2..f36c0b082e4 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -26,10 +26,12 @@ class GitOperationService oldrev = Gitlab::Git::BLANK_SHA with_hooks(ref, newrev, oldrev) do |service| + # We want to pass the OID of the tag object to the hooks. For an + # annotated tag we don't know that OID until after the tag object + # (raw_tag) is created in the repository. That is why we have to + # update the value after creating the tag object. Only the + # "post-receive" hook will receive the correct value in this case. raw_tag = repository.rugged.tags.create(tag_name, newrev, options) - - # If raw_tag is an annotated tag, we'll need to update newrev to point - # to the new revision. service.newrev = raw_tag.target_id end end -- GitLab From 05d742a047cca3ded10e6e3a545e211a3592c89c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 5 Jan 2017 01:10:35 +0800 Subject: [PATCH 58/78] Indent the way rubocop likes --- app/controllers/concerns/creates_commit.rb | 4 ++-- app/models/repository.rb | 2 +- app/services/git_operation_service.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 58de0917049..9d41c559b0b 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,8 +4,8 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - source_branch = @ref if @ref && - @mr_source_project.repository.branch_exists?(@ref) + source_branch = @ref if + @ref && @mr_source_project.repository.branch_exists?(@ref) commit_params = @commit_params.merge( source_project: @mr_source_project, source_branch: source_branch, diff --git a/app/models/repository.rb b/app/models/repository.rb index b01437acd8e..46995bdcb33 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -781,7 +781,7 @@ class Repository end if source_branch_name && - source_project.repository.tree_entry_at(source_branch_name, path) + source_project.repository.tree_entry_at(source_branch_name, path) raise Gitlab::Git::Repository::InvalidBlobName.new(error_message) end end diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index f36c0b082e4..00c85112873 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -90,8 +90,8 @@ class GitOperationService # If repo was empty expire cache repository.after_create if was_empty - repository.after_create_branch if was_empty || - Gitlab::Git.blank_ref?(oldrev) + repository.after_create_branch if + was_empty || Gitlab::Git.blank_ref?(oldrev) newrev end -- GitLab From 99ac0935271b1e99f4512e496104219045f1018e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 5 Jan 2017 01:52:21 +0800 Subject: [PATCH 59/78] Introduce Repository#with_repo_branch_commit We merge repository checks inside it so we don't have to check it on the call site, and we could also load the commit for the caller. This greatly reduce code duplication. Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_20572919 --- app/models/repository.rb | 25 ++++++++++++++++--------- app/services/compare_service.rb | 18 ++++++------------ app/services/git_operation_service.rb | 18 ++++++------------ 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 46995bdcb33..b1a789492d3 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1063,19 +1063,26 @@ class Repository Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:strip) end - def with_tmp_ref(source_repository, source_branch_name) - tmp_ref = "refs/tmp/#{SecureRandom.hex}/head" + def with_repo_branch_commit(source_repository, source_branch_name) + branch_name_or_sha = + if source_repository == self + source_branch_name + else + tmp_ref = "refs/tmp/#{SecureRandom.hex}/head" - fetch_ref( - source_repository.path_to_repo, - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch_name}", - tmp_ref - ) + fetch_ref( + source_repository.path_to_repo, + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch_name}", + tmp_ref + ) + + source_repository.commit(source_branch_name).sha + end - yield + yield(commit(branch_name_or_sha)) ensure - rugged.references.delete(tmp_ref) + rugged.references.delete(tmp_ref) if tmp_ref end def fetch_ref(source_path, source_ref, target_ref) diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 31c371c4b34..d3d613661a6 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -11,19 +11,13 @@ class CompareService end def execute(target_project, target_branch, straight: false) - source_sha = source_project.repository. - commit(source_branch_name).try(:sha) - - return unless source_sha - # If compare with other project we need to fetch ref first - if target_project == source_project - compare(source_sha, target_project, target_branch, straight) - else - target_project.repository.with_tmp_ref( - source_project.repository, source_branch_name) do - compare(source_sha, target_project, target_branch, straight) - end + target_project.repository.with_repo_branch_commit( + source_project.repository, + source_branch_name) do |commit| + break unless commit + + compare(commit.sha, target_project, target_branch, straight) end end diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 00c85112873..ed9822cfee6 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -43,23 +43,17 @@ class GitOperationService def with_branch( branch_name, source_branch_name: nil, - source_project: repository.project) + source_project: repository.project, + &block) check_with_branch_arguments!( branch_name, source_branch_name, source_project) - source_commit = source_project.repository.find_branch( - source_branch_name || branch_name).try(:dereferenced_target) - update_branch_with_hooks(branch_name) do - if repository.project == source_project - yield(source_commit) - else - repository.with_tmp_ref( - source_project.repository, source_branch_name) do - yield(source_commit) - end - end + repository.with_repo_branch_commit( + source_project.repository, + source_branch_name || branch_name, + &block) end end -- GitLab From e01c692a35d817c09416356b549f473f63d78dc8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 5 Jan 2017 02:53:45 +0800 Subject: [PATCH 60/78] Remove tag with git hooks --- app/models/repository.rb | 19 +++++++++++-------- app/services/delete_tag_service.rb | 2 +- app/services/git_operation_service.rb | 12 +++++++++++- spec/models/repository_spec.rb | 5 +++-- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index b1a789492d3..e834936aa93 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -196,16 +196,14 @@ class Repository true end - # TODO: why we don't pass user here? - def rm_tag(tag_name) + def rm_tag(user, tag_name) before_remove_tag + tag = find_tag(tag_name) - begin - rugged.tags.delete(tag_name) - true - rescue Rugged::ReferenceError - false - end + GitOperationService.new(user, self).rm_tag(tag) + + after_remove_tag + true end def ref_names @@ -401,6 +399,11 @@ class Repository repository_event(:remove_tag) end + # Runs code after removing a tag. + def after_remove_tag + expire_tags_cache + end + def before_import expire_content_cache end diff --git a/app/services/delete_tag_service.rb b/app/services/delete_tag_service.rb index a44dee14a0f..9d4bffb93e9 100644 --- a/app/services/delete_tag_service.rb +++ b/app/services/delete_tag_service.rb @@ -7,7 +7,7 @@ class DeleteTagService < BaseService return error('No such tag', 404) end - if repository.rm_tag(tag_name) + if repository.rm_tag(current_user, tag_name) release = project.releases.find_by(tag: tag_name) release.destroy if release diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index ed9822cfee6..3b7f702e3ab 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -15,7 +15,7 @@ class GitOperationService def rm_branch(branch) ref = Gitlab::Git::BRANCH_REF_PREFIX + branch.name - oldrev = branch.dereferenced_target.id + oldrev = branch.target newrev = Gitlab::Git::BLANK_SHA update_ref_in_hooks(ref, newrev, oldrev) @@ -36,6 +36,16 @@ class GitOperationService end end + def rm_tag(tag) + ref = Gitlab::Git::TAG_REF_PREFIX + tag.name + oldrev = tag.target + newrev = Gitlab::Git::BLANK_SHA + + update_ref_in_hooks(ref, newrev, oldrev) do + repository.rugged.tags.delete(tag_name) + end + end + # Whenever `source_branch_name` is passed, if `branch_name` doesn't exist, # it would be created from `source_branch_name`. # If `source_project` is passed, and the branch doesn't exist, diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index b1fee342b57..0f43c5c019a 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1419,9 +1419,10 @@ describe Repository, models: true do describe '#rm_tag' do it 'removes a tag' do expect(repository).to receive(:before_remove_tag) - expect(repository.rugged.tags).to receive(:delete).with('v1.1.0') - repository.rm_tag('v1.1.0') + repository.rm_tag(create(:user), 'v1.1.0') + + expect(repository.find_tag('v1.1.0')).to be_nil end end -- GitLab From 9244c81bc5f1c74966cb3ecb7b099fe7fd33689f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 5 Jan 2017 03:01:16 +0800 Subject: [PATCH 61/78] I think I am really confused, should be @tree_edit_project Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_20571990 --- app/controllers/concerns/creates_commit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 9d41c559b0b..a2e1d7c4653 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -13,7 +13,7 @@ module CreatesCommit ) result = service.new( - @mr_target_project, current_user, commit_params).execute + @tree_edit_project, current_user, commit_params).execute if result[:status] == :success update_flash_notice(success_notice) -- GitLab From 0b3b56b34d959322cced8a317138945c685015b8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 5 Jan 2017 22:58:04 +0800 Subject: [PATCH 62/78] Merge request terms are reversed for GitOperationService This is seriously confusing but a target branch in merge request, is actually the source branch for GitOperationService, which is the base branch. The source branch in a merge request, is the target branch for GitOperationService, which is where we want to make commits. Perhaps we should rename source branch in GitOperationService to base branch, and target branch to committing branch. --- app/controllers/concerns/creates_commit.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index a2e1d7c4653..025fca088bf 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -5,15 +5,15 @@ module CreatesCommit set_commit_variables source_branch = @ref if - @ref && @mr_source_project.repository.branch_exists?(@ref) + @ref && @mr_target_project.repository.branch_exists?(@ref) commit_params = @commit_params.merge( - source_project: @mr_source_project, + source_project: @mr_target_project, source_branch: source_branch, - target_branch: @mr_target_branch + target_branch: @mr_source_branch ) result = service.new( - @tree_edit_project, current_user, commit_params).execute + @mr_source_project, current_user, commit_params).execute if result[:status] == :success update_flash_notice(success_notice) -- GitLab From 5e12b3d841b0da1a2c6047de53a033107bbb5c32 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 5 Jan 2017 23:49:11 +0800 Subject: [PATCH 63/78] Prefer leading dots over trailing dots --- app/services/create_branch_service.rb | 4 ++-- app/workers/emails_on_push_worker.rb | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index 1b5e504573a..77459d8779d 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -1,7 +1,7 @@ class CreateBranchService < BaseService def execute(branch_name, ref) - result = ValidateNewBranchService.new(project, current_user). - execute(branch_name) + result = ValidateNewBranchService.new(project, current_user) + .execute(branch_name) return result if result[:status] == :error diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index d4c3f14ec06..f5ccc84c160 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -33,15 +33,15 @@ class EmailsOnPushWorker reverse_compare = false if action == :push - compare = CompareService.new(project, after_sha). - execute(project, before_sha) + compare = CompareService.new(project, after_sha) + .execute(project, before_sha) diff_refs = compare.diff_refs return false if compare.same if compare.commits.empty? - compare = CompareService.new(project, before_sha). - execute(project, after_sha) + compare = CompareService.new(project, before_sha) + .execute(project, after_sha) diff_refs = compare.diff_refs reverse_compare = true -- GitLab From ae86a1b9d3c9ca4ce592fa89085acd059ffc09a0 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 02:11:27 +0800 Subject: [PATCH 64/78] Just trust set_commit_variables to set everything! Removing those weird setup in assign_change_commit_vars fixed all the failures in the tests. I still cannot say why but clearly we need to have better names. It's so confusing right now. We should seriously stop fiddling those instance variables. --- app/controllers/concerns/creates_commit.rb | 4 +--- app/controllers/projects/commit_controller.rb | 8 +++----- app/services/commits/change_service.rb | 3 ++- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 025fca088bf..eafaed8a3d0 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,11 +4,9 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - source_branch = @ref if - @ref && @mr_target_project.repository.branch_exists?(@ref) commit_params = @commit_params.merge( source_project: @mr_target_project, - source_branch: source_branch, + source_branch: @mr_target_branch, target_branch: @mr_source_branch ) diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 791ed88db30..44f34006049 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -40,7 +40,7 @@ class Projects::CommitController < Projects::ApplicationController end def revert - assign_change_commit_vars(@commit.revert_branch_name) + assign_change_commit_vars return render_404 if @target_branch.blank? @@ -49,7 +49,7 @@ class Projects::CommitController < Projects::ApplicationController end def cherry_pick - assign_change_commit_vars(@commit.cherry_pick_branch_name) + assign_change_commit_vars return render_404 if @target_branch.blank? @@ -110,11 +110,9 @@ class Projects::CommitController < Projects::ApplicationController @ci_pipelines = project.pipelines.where(sha: commit.sha) end - def assign_change_commit_vars(mr_source_branch) + def assign_change_commit_vars @commit = project.commit(params[:id]) @target_branch = params[:target_branch] - @mr_source_branch = mr_source_branch - @mr_target_branch = @target_branch @commit_params = { commit: @commit, create_merge_request: params[:create_merge_request].present? || different_project? diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 9b241aa8b04..60bd59a5d9f 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -5,6 +5,7 @@ module Commits def execute @source_project = params[:source_project] || @project + @source_branch = params[:source_branch] @target_branch = params[:target_branch] @commit = params[:commit] @create_merge_request = params[:create_merge_request].present? @@ -38,7 +39,7 @@ module Commits into, tree_id, source_project: @source_project, - source_branch_name: @target_branch) + source_branch_name: @source_branch) success else -- GitLab From a30f278bdee399346f199ada0e33f5c2d233d861 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 04:18:51 +0800 Subject: [PATCH 65/78] Fix for initial commit and remove unneeded args --- app/controllers/concerns/creates_commit.rb | 12 +++++++++--- app/services/commits/change_service.rb | 11 +++++++++-- lib/api/commits.rb | 2 -- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index eafaed8a3d0..f5f9cdeaec5 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,9 +4,10 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables + source_branch = @mr_target_branch unless initial_commit? commit_params = @commit_params.merge( source_project: @mr_target_project, - source_branch: @mr_target_branch, + source_branch: source_branch, target_branch: @mr_source_branch ) @@ -113,7 +114,7 @@ module CreatesCommit else # Merge request to this project @mr_target_project = @project - @mr_target_branch ||= @ref + @mr_target_branch = @ref || @target_branch end else # Edit file in fork @@ -121,7 +122,12 @@ module CreatesCommit # Merge request from fork to this project @mr_source_project = @tree_edit_project @mr_target_project = @project - @mr_target_branch ||= @ref + @mr_target_branch = @ref || @target_branch end end + + def initial_commit? + @mr_target_branch.nil? || + !@mr_target_project.repository.branch_exists?(@mr_target_branch) + end end diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 60bd59a5d9f..4a5d8029413 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -26,8 +26,15 @@ module Commits def commit_change(action) raise NotImplementedError unless repository.respond_to?(action) - into = @create_merge_request ? @commit.public_send("#{action}_branch_name") : @target_branch - tree_id = repository.public_send("check_#{action}_content", @commit, @target_branch) + if @create_merge_request + into = @commit.public_send("#{action}_branch_name") + tree_branch = @source_branch + else + into = tree_branch = @target_branch + end + + tree_id = repository.public_send( + "check_#{action}_content", @commit, tree_branch) if tree_id validate_target_branch(into) if @create_merge_request diff --git a/lib/api/commits.rb b/lib/api/commits.rb index cf2489dbb67..2c1da0902c9 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -140,8 +140,6 @@ module API commit_params = { commit: commit, create_merge_request: false, - source_project: user_project, - source_branch: commit.cherry_pick_branch_name, target_branch: params[:branch] } -- GitLab From dea589d635d4c41fbf0db721b132ea466c34cb4a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 04:41:17 +0800 Subject: [PATCH 66/78] Prefer leading dots over trailing dots --- app/models/merge_request_diff.rb | 4 ++-- app/services/commits/change_service.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 7946d8e123e..00c2a3695af 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -169,8 +169,8 @@ class MergeRequestDiff < ActiveRecord::Base # When compare merge request versions we want diff A..B instead of A...B # so we handle cases when user does squash and rebase of the commits between versions. # For this reason we set straight to true by default. - CompareService.new(project, head_commit_sha). - execute(project, sha, straight: straight) + CompareService.new(project, head_commit_sha) + .execute(project, sha, straight: straight) end def commits_count diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 4a5d8029413..8d1dfbcea7d 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -70,8 +70,8 @@ module Commits # Temporary branch exists and contains the change commit return if repository.find_branch(new_branch) - result = ValidateNewBranchService.new(@project, current_user). - execute(new_branch) + result = ValidateNewBranchService.new(@project, current_user) + .execute(new_branch) if result[:status] == :error raise ChangeError, "There was an error creating the source branch: #{result[:message]}" -- GitLab From 593228ffe3b2e4ff82c4d63e5d5c59b835f70085 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 20:59:38 +0800 Subject: [PATCH 67/78] Don't set invalid @mr_source_branch when create_merge_request? --- app/controllers/concerns/creates_commit.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index f5f9cdeaec5..258791bb5cd 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -91,16 +91,13 @@ module CreatesCommit @mr_source_project != @mr_target_project end - def different_branch? - @mr_source_branch != @mr_target_branch || different_project? - end - def create_merge_request? - params[:create_merge_request].present? && different_branch? + params[:create_merge_request].present? end + # TODO: We should really clean this up def set_commit_variables - @mr_source_branch ||= @target_branch + @mr_source_branch = @target_branch unless create_merge_request? if can?(current_user, :push_code, @project) # Edit file in this project -- GitLab From a4b97b2cb61c03d08e25cf2cd7fcbb3f21611350 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 22:05:30 +0800 Subject: [PATCH 68/78] Rename source to base to avoid confusion from MR --- app/controllers/concerns/creates_commit.rb | 6 +- app/models/repository.rb | 78 +++++++++++----------- app/services/commits/change_service.rb | 10 +-- app/services/compare_service.rb | 12 ++-- app/services/files/base_service.rb | 10 +-- app/services/files/create_dir_service.rb | 4 +- app/services/files/create_service.rb | 6 +- app/services/files/delete_service.rb | 4 +- app/services/files/multi_service.rb | 6 +- app/services/files/update_service.rb | 6 +- app/services/git_operation_service.rb | 40 +++++------ 11 files changed, 91 insertions(+), 91 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 258791bb5cd..c503f8bf696 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,10 +4,10 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - source_branch = @mr_target_branch unless initial_commit? + base_branch = @mr_target_branch unless initial_commit? commit_params = @commit_params.merge( - source_project: @mr_target_project, - source_branch: source_branch, + base_project: @mr_target_project, + base_branch: base_branch, target_branch: @mr_source_branch ) diff --git a/app/models/repository.rb b/app/models/repository.rb index e834936aa93..a335c629a78 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -748,12 +748,12 @@ class Repository user, path, message:, branch_name:, author_email: nil, author_name: nil, - source_branch_name: nil, source_project: project) + base_branch_name: nil, base_project: project) check_tree_entry_for_dir(branch_name, path) - if source_branch_name - source_project.repository. - check_tree_entry_for_dir(source_branch_name, path) + if base_branch_name + base_project.repository. + check_tree_entry_for_dir(base_branch_name, path) end commit_file( @@ -765,8 +765,8 @@ class Repository update: false, author_email: author_email, author_name: author_name, - source_branch_name: source_branch_name, - source_project: source_project) + base_branch_name: base_branch_name, + base_project: base_project) end # rubocop:enable Metrics/ParameterLists @@ -775,7 +775,7 @@ class Repository user, path, content, message:, branch_name:, update: true, author_email: nil, author_name: nil, - source_branch_name: nil, source_project: project) + base_branch_name: nil, base_project: project) unless update error_message = "Filename already exists; update not allowed" @@ -783,8 +783,8 @@ class Repository raise Gitlab::Git::Repository::InvalidBlobName.new(error_message) end - if source_branch_name && - source_project.repository.tree_entry_at(source_branch_name, path) + if base_branch_name && + base_project.repository.tree_entry_at(base_branch_name, path) raise Gitlab::Git::Repository::InvalidBlobName.new(error_message) end end @@ -795,8 +795,8 @@ class Repository branch_name: branch_name, author_email: author_email, author_name: author_name, - source_branch_name: source_branch_name, - source_project: source_project, + base_branch_name: base_branch_name, + base_project: base_project, actions: [{ action: :create, file_path: path, content: content }]) @@ -808,7 +808,7 @@ class Repository user, path, content, message:, branch_name:, previous_path:, author_email: nil, author_name: nil, - source_branch_name: nil, source_project: project) + base_branch_name: nil, base_project: project) action = if previous_path && previous_path != path :move else @@ -821,8 +821,8 @@ class Repository branch_name: branch_name, author_email: author_email, author_name: author_name, - source_branch_name: source_branch_name, - source_project: source_project, + base_branch_name: base_branch_name, + base_project: base_project, actions: [{ action: action, file_path: path, content: content, @@ -835,15 +835,15 @@ class Repository user, path, message:, branch_name:, author_email: nil, author_name: nil, - source_branch_name: nil, source_project: project) + base_branch_name: nil, base_project: project) multi_action( user: user, message: message, branch_name: branch_name, author_email: author_email, author_name: author_name, - source_branch_name: source_branch_name, - source_project: source_project, + base_branch_name: base_branch_name, + base_project: base_project, actions: [{ action: :delete, file_path: path }]) end @@ -853,16 +853,16 @@ class Repository def multi_action( user:, branch_name:, message:, actions:, author_email: nil, author_name: nil, - source_branch_name: nil, source_project: project) + base_branch_name: nil, base_project: project) GitOperationService.new(user, self).with_branch( branch_name, - source_branch_name: source_branch_name, - source_project: source_project) do |source_commit| + base_branch_name: base_branch_name, + base_project: base_project) do |base_commit| index = rugged.index - parents = if source_commit - index.read_tree(source_commit.raw_commit.tree) - [source_commit.sha] + parents = if base_commit + index.read_tree(base_commit.raw_commit.tree) + [base_commit.sha] else [] end @@ -910,8 +910,8 @@ class Repository def merge(user, merge_request, options = {}) GitOperationService.new(user, self).with_branch( - merge_request.target_branch) do |source_commit| - our_commit = source_commit.sha + merge_request.target_branch) do |base_commit| + our_commit = base_commit.sha their_commit = merge_request.diff_head_sha raise 'Invalid merge target' unless our_commit @@ -935,15 +935,15 @@ class Repository def revert( user, commit, branch_name, revert_tree_id = nil, - source_branch_name: nil, source_project: project) + base_branch_name: nil, base_project: project) revert_tree_id ||= check_revert_content(commit, branch_name) return false unless revert_tree_id GitOperationService.new(user, self).with_branch( branch_name, - source_branch_name: source_branch_name, - source_project: source_project) do |source_commit| + base_branch_name: base_branch_name, + base_project: base_project) do |base_commit| committer = user_to_committer(user) @@ -952,21 +952,21 @@ class Repository author: committer, committer: committer, tree: revert_tree_id, - parents: [source_commit.sha]) + parents: [base_commit.sha]) end end def cherry_pick( user, commit, branch_name, cherry_pick_tree_id = nil, - source_branch_name: nil, source_project: project) + base_branch_name: nil, base_project: project) cherry_pick_tree_id ||= check_cherry_pick_content(commit, branch_name) return false unless cherry_pick_tree_id GitOperationService.new(user, self).with_branch( branch_name, - source_branch_name: source_branch_name, - source_project: source_project) do |source_commit| + base_branch_name: base_branch_name, + base_project: base_project) do |base_commit| committer = user_to_committer(user) @@ -979,7 +979,7 @@ class Repository }, committer: committer, tree: cherry_pick_tree_id, - parents: [source_commit.sha]) + parents: [base_commit.sha]) end end @@ -1066,20 +1066,20 @@ class Repository Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:strip) end - def with_repo_branch_commit(source_repository, source_branch_name) + def with_repo_branch_commit(base_repository, base_branch_name) branch_name_or_sha = - if source_repository == self - source_branch_name + if base_repository == self + base_branch_name else tmp_ref = "refs/tmp/#{SecureRandom.hex}/head" fetch_ref( - source_repository.path_to_repo, - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{source_branch_name}", + base_repository.path_to_repo, + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{base_branch_name}", tmp_ref ) - source_repository.commit(source_branch_name).sha + base_repository.commit(base_branch_name).sha end yield(commit(branch_name_or_sha)) diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 8d1dfbcea7d..1faa052e0ca 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -4,8 +4,8 @@ module Commits class ChangeError < StandardError; end def execute - @source_project = params[:source_project] || @project - @source_branch = params[:source_branch] + @base_project = params[:base_project] || @project + @base_branch = params[:base_branch] @target_branch = params[:target_branch] @commit = params[:commit] @create_merge_request = params[:create_merge_request].present? @@ -28,7 +28,7 @@ module Commits if @create_merge_request into = @commit.public_send("#{action}_branch_name") - tree_branch = @source_branch + tree_branch = @base_branch else into = tree_branch = @target_branch end @@ -45,8 +45,8 @@ module Commits @commit, into, tree_id, - source_project: @source_project, - source_branch_name: @source_branch) + base_project: @base_project, + base_branch_name: @base_branch) success else diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index d3d613661a6..2e4f8ee9dc8 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -3,18 +3,18 @@ require 'securerandom' # Compare 2 branches for one repo or between repositories # and return Gitlab::Git::Compare object that responds to commits and diffs class CompareService - attr_reader :source_project, :source_branch_name + attr_reader :base_project, :base_branch_name - def initialize(new_source_project, new_source_branch_name) - @source_project = new_source_project - @source_branch_name = new_source_branch_name + def initialize(new_base_project, new_base_branch_name) + @base_project = new_base_project + @base_branch_name = new_base_branch_name end def execute(target_project, target_branch, straight: false) # If compare with other project we need to fetch ref first target_project.repository.with_repo_branch_commit( - source_project.repository, - source_branch_name) do |commit| + base_project.repository, + base_branch_name) do |commit| break unless commit compare(commit.sha, target_project, target_branch, straight) diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 80e1d1d60f2..89f7dcbaa87 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -3,8 +3,8 @@ module Files class ValidationError < StandardError; end def execute - @source_project = params[:source_project] || @project - @source_branch = params[:source_branch] + @base_project = params[:base_project] || @project + @base_branch = params[:base_branch] @target_branch = params[:target_branch] @commit_message = params[:commit_message] @@ -22,7 +22,7 @@ module Files # Validate parameters validate - # Create new branch if it different from source_branch + # Create new branch if it different from base_branch validate_target_branch if different_branch? result = commit @@ -38,7 +38,7 @@ module Files private def different_branch? - @source_branch != @target_branch || @source_project != @project + @base_branch != @target_branch || @base_project != @project end def file_has_changed? @@ -59,7 +59,7 @@ module Files end unless project.empty_repo? - unless @source_project.repository.branch_exists?(@source_branch) + unless @base_project.repository.branch_exists?(@base_branch) raise_error('You can only create or edit files when you are on a branch') end diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb index ee4e130a38f..53b6d456e0d 100644 --- a/app/services/files/create_dir_service.rb +++ b/app/services/files/create_dir_service.rb @@ -8,8 +8,8 @@ module Files branch_name: @target_branch, author_email: @author_email, author_name: @author_name, - source_project: @source_project, - source_branch_name: @source_branch) + base_project: @base_project, + base_branch_name: @base_branch) end def validate diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index 853c471666d..270dc6471aa 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -10,8 +10,8 @@ module Files update: false, author_email: @author_email, author_name: @author_name, - source_project: @source_project, - source_branch_name: @source_branch) + base_project: @base_project, + base_branch_name: @base_branch) end def validate @@ -34,7 +34,7 @@ module Files unless project.empty_repo? @file_path.slice!(0) if @file_path.start_with?('/') - blob = repository.blob_at_branch(@source_branch, @file_path) + blob = repository.blob_at_branch(@base_branch, @file_path) if blob raise_error('Your changes could not be committed because a file with the same name already exists') diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb index cfe532d49b3..d5341b9e197 100644 --- a/app/services/files/delete_service.rb +++ b/app/services/files/delete_service.rb @@ -8,8 +8,8 @@ module Files branch_name: @target_branch, author_email: @author_email, author_name: @author_name, - source_project: @source_project, - source_branch_name: @source_branch) + base_project: @base_project, + base_branch_name: @base_branch) end end end diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb index f77e5d91103..ca13b887e06 100644 --- a/app/services/files/multi_service.rb +++ b/app/services/files/multi_service.rb @@ -10,8 +10,8 @@ module Files actions: params[:actions], author_email: @author_email, author_name: @author_name, - source_project: @source_project, - source_branch_name: @source_branch + base_project: @base_project, + base_branch_name: @base_branch ) end @@ -63,7 +63,7 @@ module Files end def last_commit - Gitlab::Git::Commit.last_for_path(repository, @source_branch, @file_path) + Gitlab::Git::Commit.last_for_path(repository, @base_branch, @file_path) end def regex_check(file) diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index 5f671817cdb..f546b169550 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -9,8 +9,8 @@ module Files previous_path: @previous_path, author_email: @author_email, author_name: @author_name, - source_project: @source_project, - source_branch_name: @source_branch) + base_project: @base_project, + base_branch_name: @base_branch) end private @@ -25,7 +25,7 @@ module Files def last_commit @last_commit ||= Gitlab::Git::Commit. - last_for_path(@source_project.repository, @source_branch, @file_path) + last_for_path(@base_project.repository, @base_branch, @file_path) end end end diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 3b7f702e3ab..ec23407544c 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -46,23 +46,23 @@ class GitOperationService end end - # Whenever `source_branch_name` is passed, if `branch_name` doesn't exist, - # it would be created from `source_branch_name`. - # If `source_project` is passed, and the branch doesn't exist, - # it would try to find the source from it instead of current repository. + # Whenever `base_branch_name` is passed, if `branch_name` doesn't exist, + # it would be created from `base_branch_name`. + # If `base_project` is passed, and the branch doesn't exist, + # it would try to find the base from it instead of current repository. def with_branch( branch_name, - source_branch_name: nil, - source_project: repository.project, + base_branch_name: nil, + base_project: repository.project, &block) check_with_branch_arguments!( - branch_name, source_branch_name, source_project) + branch_name, base_branch_name, base_project) update_branch_with_hooks(branch_name) do repository.with_repo_branch_commit( - source_project.repository, - source_branch_name || branch_name, + base_project.repository, + base_branch_name || branch_name, &block) end end @@ -148,27 +148,27 @@ class GitOperationService end def check_with_branch_arguments!( - branch_name, source_branch_name, source_project) + branch_name, base_branch_name, base_project) return if repository.branch_exists?(branch_name) - if repository.project != source_project - unless source_branch_name + if repository.project != base_project + unless base_branch_name raise ArgumentError, - 'Should also pass :source_branch_name if' + - ' :source_project is different from current project' + 'Should also pass :base_branch_name if' + + ' :base_project is different from current project' end - unless source_project.repository.branch_exists?(source_branch_name) + unless base_project.repository.branch_exists?(base_branch_name) raise ArgumentError, "Cannot find branch #{branch_name} nor" \ - " #{source_branch_name} from" \ - " #{source_project.path_with_namespace}" + " #{base_branch_name} from" \ + " #{base_project.path_with_namespace}" end - elsif source_branch_name - unless repository.branch_exists?(source_branch_name) + elsif base_branch_name + unless repository.branch_exists?(base_branch_name) raise ArgumentError, "Cannot find branch #{branch_name} nor" \ - " #{source_branch_name} from" \ + " #{base_branch_name} from" \ " #{repository.project.path_with_namespace}" end end -- GitLab From 358501df2d3229f68be700d2fc57cd3c3e7e5042 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 22:20:02 +0800 Subject: [PATCH 69/78] Properly fix the edge case! --- app/controllers/concerns/creates_commit.rb | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index c503f8bf696..516b1cac6ef 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -97,8 +97,6 @@ module CreatesCommit # TODO: We should really clean this up def set_commit_variables - @mr_source_branch = @target_branch unless create_merge_request? - if can?(current_user, :push_code, @project) # Edit file in this project @tree_edit_project = @project @@ -121,10 +119,25 @@ module CreatesCommit @mr_target_project = @project @mr_target_branch = @ref || @target_branch end + + @mr_source_branch = guess_mr_source_branch end def initial_commit? @mr_target_branch.nil? || !@mr_target_project.repository.branch_exists?(@mr_target_branch) end + + def guess_mr_source_branch + # XXX: Happens when viewing a commit without a branch. In this case, + # @target_branch would be the default branch for @mr_source_project, + # however we want a generated new branch here. Thus we can't use + # @target_branch, but should pass nil to indicate that we want a new + # branch instead of @target_branch. + return if + create_merge_request? && + @mr_source_project.repository.branch_exists?(@target_branch) + + @target_branch + end end -- GitLab From e3c36850a618ee2f7f9087b681e62d8a50e7b1b1 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 22:49:23 +0800 Subject: [PATCH 70/78] Detect if we really want a new merge request properly --- app/controllers/concerns/creates_commit.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 516b1cac6ef..646d922cb24 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -92,7 +92,9 @@ module CreatesCommit end def create_merge_request? - params[:create_merge_request].present? + # XXX: Even if the field is set, if we're checking the same branch + # as the target branch, we don't want to create a merge request. + params[:create_merge_request].present? && @ref != @target_branch end # TODO: We should really clean this up @@ -136,7 +138,8 @@ module CreatesCommit # branch instead of @target_branch. return if create_merge_request? && - @mr_source_project.repository.branch_exists?(@target_branch) + # XXX: Don't understand why rubocop prefers this indention + @mr_source_project.repository.branch_exists?(@target_branch) @target_branch end -- GitLab From ccc73c455ba0b95b531c69414a6a1f47667f16b5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 23:29:13 +0800 Subject: [PATCH 71/78] Rename from base to start because base could mean merge base --- app/controllers/concerns/creates_commit.rb | 6 +- app/models/repository.rb | 78 +++++++++++----------- app/services/commits/change_service.rb | 10 +-- app/services/compare_service.rb | 12 ++-- app/services/files/base_service.rb | 10 +-- app/services/files/create_dir_service.rb | 4 +- app/services/files/create_service.rb | 6 +- app/services/files/delete_service.rb | 4 +- app/services/files/multi_service.rb | 6 +- app/services/files/update_service.rb | 6 +- app/services/git_operation_service.rb | 40 +++++------ 11 files changed, 91 insertions(+), 91 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 646d922cb24..2ece99aebc0 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -4,10 +4,10 @@ module CreatesCommit def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) set_commit_variables - base_branch = @mr_target_branch unless initial_commit? + start_branch = @mr_target_branch unless initial_commit? commit_params = @commit_params.merge( - base_project: @mr_target_project, - base_branch: base_branch, + start_project: @mr_target_project, + start_branch: start_branch, target_branch: @mr_source_branch ) diff --git a/app/models/repository.rb b/app/models/repository.rb index a335c629a78..f8bdfb602a9 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -748,12 +748,12 @@ class Repository user, path, message:, branch_name:, author_email: nil, author_name: nil, - base_branch_name: nil, base_project: project) + start_branch_name: nil, start_project: project) check_tree_entry_for_dir(branch_name, path) - if base_branch_name - base_project.repository. - check_tree_entry_for_dir(base_branch_name, path) + if start_branch_name + start_project.repository. + check_tree_entry_for_dir(start_branch_name, path) end commit_file( @@ -765,8 +765,8 @@ class Repository update: false, author_email: author_email, author_name: author_name, - base_branch_name: base_branch_name, - base_project: base_project) + start_branch_name: start_branch_name, + start_project: start_project) end # rubocop:enable Metrics/ParameterLists @@ -775,7 +775,7 @@ class Repository user, path, content, message:, branch_name:, update: true, author_email: nil, author_name: nil, - base_branch_name: nil, base_project: project) + start_branch_name: nil, start_project: project) unless update error_message = "Filename already exists; update not allowed" @@ -783,8 +783,8 @@ class Repository raise Gitlab::Git::Repository::InvalidBlobName.new(error_message) end - if base_branch_name && - base_project.repository.tree_entry_at(base_branch_name, path) + if start_branch_name && + start_project.repository.tree_entry_at(start_branch_name, path) raise Gitlab::Git::Repository::InvalidBlobName.new(error_message) end end @@ -795,8 +795,8 @@ class Repository branch_name: branch_name, author_email: author_email, author_name: author_name, - base_branch_name: base_branch_name, - base_project: base_project, + start_branch_name: start_branch_name, + start_project: start_project, actions: [{ action: :create, file_path: path, content: content }]) @@ -808,7 +808,7 @@ class Repository user, path, content, message:, branch_name:, previous_path:, author_email: nil, author_name: nil, - base_branch_name: nil, base_project: project) + start_branch_name: nil, start_project: project) action = if previous_path && previous_path != path :move else @@ -821,8 +821,8 @@ class Repository branch_name: branch_name, author_email: author_email, author_name: author_name, - base_branch_name: base_branch_name, - base_project: base_project, + start_branch_name: start_branch_name, + start_project: start_project, actions: [{ action: action, file_path: path, content: content, @@ -835,15 +835,15 @@ class Repository user, path, message:, branch_name:, author_email: nil, author_name: nil, - base_branch_name: nil, base_project: project) + start_branch_name: nil, start_project: project) multi_action( user: user, message: message, branch_name: branch_name, author_email: author_email, author_name: author_name, - base_branch_name: base_branch_name, - base_project: base_project, + start_branch_name: start_branch_name, + start_project: start_project, actions: [{ action: :delete, file_path: path }]) end @@ -853,16 +853,16 @@ class Repository def multi_action( user:, branch_name:, message:, actions:, author_email: nil, author_name: nil, - base_branch_name: nil, base_project: project) + start_branch_name: nil, start_project: project) GitOperationService.new(user, self).with_branch( branch_name, - base_branch_name: base_branch_name, - base_project: base_project) do |base_commit| + start_branch_name: start_branch_name, + start_project: start_project) do |start_commit| index = rugged.index - parents = if base_commit - index.read_tree(base_commit.raw_commit.tree) - [base_commit.sha] + parents = if start_commit + index.read_tree(start_commit.raw_commit.tree) + [start_commit.sha] else [] end @@ -910,8 +910,8 @@ class Repository def merge(user, merge_request, options = {}) GitOperationService.new(user, self).with_branch( - merge_request.target_branch) do |base_commit| - our_commit = base_commit.sha + merge_request.target_branch) do |start_commit| + our_commit = start_commit.sha their_commit = merge_request.diff_head_sha raise 'Invalid merge target' unless our_commit @@ -935,15 +935,15 @@ class Repository def revert( user, commit, branch_name, revert_tree_id = nil, - base_branch_name: nil, base_project: project) + start_branch_name: nil, start_project: project) revert_tree_id ||= check_revert_content(commit, branch_name) return false unless revert_tree_id GitOperationService.new(user, self).with_branch( branch_name, - base_branch_name: base_branch_name, - base_project: base_project) do |base_commit| + start_branch_name: start_branch_name, + start_project: start_project) do |start_commit| committer = user_to_committer(user) @@ -952,21 +952,21 @@ class Repository author: committer, committer: committer, tree: revert_tree_id, - parents: [base_commit.sha]) + parents: [start_commit.sha]) end end def cherry_pick( user, commit, branch_name, cherry_pick_tree_id = nil, - base_branch_name: nil, base_project: project) + start_branch_name: nil, start_project: project) cherry_pick_tree_id ||= check_cherry_pick_content(commit, branch_name) return false unless cherry_pick_tree_id GitOperationService.new(user, self).with_branch( branch_name, - base_branch_name: base_branch_name, - base_project: base_project) do |base_commit| + start_branch_name: start_branch_name, + start_project: start_project) do |start_commit| committer = user_to_committer(user) @@ -979,7 +979,7 @@ class Repository }, committer: committer, tree: cherry_pick_tree_id, - parents: [base_commit.sha]) + parents: [start_commit.sha]) end end @@ -1066,20 +1066,20 @@ class Repository Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:strip) end - def with_repo_branch_commit(base_repository, base_branch_name) + def with_repo_branch_commit(start_repository, start_branch_name) branch_name_or_sha = - if base_repository == self - base_branch_name + if start_repository == self + start_branch_name else tmp_ref = "refs/tmp/#{SecureRandom.hex}/head" fetch_ref( - base_repository.path_to_repo, - "#{Gitlab::Git::BRANCH_REF_PREFIX}#{base_branch_name}", + start_repository.path_to_repo, + "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}", tmp_ref ) - base_repository.commit(base_branch_name).sha + start_repository.commit(start_branch_name).sha end yield(commit(branch_name_or_sha)) diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index 1faa052e0ca..25e22f14e60 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -4,8 +4,8 @@ module Commits class ChangeError < StandardError; end def execute - @base_project = params[:base_project] || @project - @base_branch = params[:base_branch] + @start_project = params[:start_project] || @project + @start_branch = params[:start_branch] @target_branch = params[:target_branch] @commit = params[:commit] @create_merge_request = params[:create_merge_request].present? @@ -28,7 +28,7 @@ module Commits if @create_merge_request into = @commit.public_send("#{action}_branch_name") - tree_branch = @base_branch + tree_branch = @start_branch else into = tree_branch = @target_branch end @@ -45,8 +45,8 @@ module Commits @commit, into, tree_id, - base_project: @base_project, - base_branch_name: @base_branch) + start_project: @start_project, + start_branch_name: @start_branch) success else diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 2e4f8ee9dc8..ab4c02a97a0 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -3,18 +3,18 @@ require 'securerandom' # Compare 2 branches for one repo or between repositories # and return Gitlab::Git::Compare object that responds to commits and diffs class CompareService - attr_reader :base_project, :base_branch_name + attr_reader :start_project, :start_branch_name - def initialize(new_base_project, new_base_branch_name) - @base_project = new_base_project - @base_branch_name = new_base_branch_name + def initialize(new_start_project, new_start_branch_name) + @start_project = new_start_project + @start_branch_name = new_start_branch_name end def execute(target_project, target_branch, straight: false) # If compare with other project we need to fetch ref first target_project.repository.with_repo_branch_commit( - base_project.repository, - base_branch_name) do |commit| + start_project.repository, + start_branch_name) do |commit| break unless commit compare(commit.sha, target_project, target_branch, straight) diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 89f7dcbaa87..0a25f56d24c 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -3,8 +3,8 @@ module Files class ValidationError < StandardError; end def execute - @base_project = params[:base_project] || @project - @base_branch = params[:base_branch] + @start_project = params[:start_project] || @project + @start_branch = params[:start_branch] @target_branch = params[:target_branch] @commit_message = params[:commit_message] @@ -22,7 +22,7 @@ module Files # Validate parameters validate - # Create new branch if it different from base_branch + # Create new branch if it different from start_branch validate_target_branch if different_branch? result = commit @@ -38,7 +38,7 @@ module Files private def different_branch? - @base_branch != @target_branch || @base_project != @project + @start_branch != @target_branch || @start_project != @project end def file_has_changed? @@ -59,7 +59,7 @@ module Files end unless project.empty_repo? - unless @base_project.repository.branch_exists?(@base_branch) + unless @start_project.repository.branch_exists?(@start_branch) raise_error('You can only create or edit files when you are on a branch') end diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb index 53b6d456e0d..858de5f0538 100644 --- a/app/services/files/create_dir_service.rb +++ b/app/services/files/create_dir_service.rb @@ -8,8 +8,8 @@ module Files branch_name: @target_branch, author_email: @author_email, author_name: @author_name, - base_project: @base_project, - base_branch_name: @base_branch) + start_project: @start_project, + start_branch_name: @start_branch) end def validate diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index 270dc6471aa..88dd7bbaedb 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -10,8 +10,8 @@ module Files update: false, author_email: @author_email, author_name: @author_name, - base_project: @base_project, - base_branch_name: @base_branch) + start_project: @start_project, + start_branch_name: @start_branch) end def validate @@ -34,7 +34,7 @@ module Files unless project.empty_repo? @file_path.slice!(0) if @file_path.start_with?('/') - blob = repository.blob_at_branch(@base_branch, @file_path) + blob = repository.blob_at_branch(@start_branch, @file_path) if blob raise_error('Your changes could not be committed because a file with the same name already exists') diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb index d5341b9e197..50f0ffcac9f 100644 --- a/app/services/files/delete_service.rb +++ b/app/services/files/delete_service.rb @@ -8,8 +8,8 @@ module Files branch_name: @target_branch, author_email: @author_email, author_name: @author_name, - base_project: @base_project, - base_branch_name: @base_branch) + start_project: @start_project, + start_branch_name: @start_branch) end end end diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb index ca13b887e06..6ba868df04d 100644 --- a/app/services/files/multi_service.rb +++ b/app/services/files/multi_service.rb @@ -10,8 +10,8 @@ module Files actions: params[:actions], author_email: @author_email, author_name: @author_name, - base_project: @base_project, - base_branch_name: @base_branch + start_project: @start_project, + start_branch_name: @start_branch ) end @@ -63,7 +63,7 @@ module Files end def last_commit - Gitlab::Git::Commit.last_for_path(repository, @base_branch, @file_path) + Gitlab::Git::Commit.last_for_path(repository, @start_branch, @file_path) end def regex_check(file) diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index f546b169550..a71fe61a4b6 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -9,8 +9,8 @@ module Files previous_path: @previous_path, author_email: @author_email, author_name: @author_name, - base_project: @base_project, - base_branch_name: @base_branch) + start_project: @start_project, + start_branch_name: @start_branch) end private @@ -25,7 +25,7 @@ module Files def last_commit @last_commit ||= Gitlab::Git::Commit. - last_for_path(@base_project.repository, @base_branch, @file_path) + last_for_path(@start_project.repository, @start_branch, @file_path) end end end diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index ec23407544c..2b2ba0870a4 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -46,23 +46,23 @@ class GitOperationService end end - # Whenever `base_branch_name` is passed, if `branch_name` doesn't exist, - # it would be created from `base_branch_name`. - # If `base_project` is passed, and the branch doesn't exist, - # it would try to find the base from it instead of current repository. + # Whenever `start_branch_name` is passed, if `branch_name` doesn't exist, + # it would be created from `start_branch_name`. + # If `start_project` is passed, and the branch doesn't exist, + # it would try to find the commits from it instead of current repository. def with_branch( branch_name, - base_branch_name: nil, - base_project: repository.project, + start_branch_name: nil, + start_project: repository.project, &block) check_with_branch_arguments!( - branch_name, base_branch_name, base_project) + branch_name, start_branch_name, start_project) update_branch_with_hooks(branch_name) do repository.with_repo_branch_commit( - base_project.repository, - base_branch_name || branch_name, + start_project.repository, + start_branch_name || branch_name, &block) end end @@ -148,27 +148,27 @@ class GitOperationService end def check_with_branch_arguments!( - branch_name, base_branch_name, base_project) + branch_name, start_branch_name, start_project) return if repository.branch_exists?(branch_name) - if repository.project != base_project - unless base_branch_name + if repository.project != start_project + unless start_branch_name raise ArgumentError, - 'Should also pass :base_branch_name if' + - ' :base_project is different from current project' + 'Should also pass :start_branch_name if' + + ' :start_project is different from current project' end - unless base_project.repository.branch_exists?(base_branch_name) + unless start_project.repository.branch_exists?(start_branch_name) raise ArgumentError, "Cannot find branch #{branch_name} nor" \ - " #{base_branch_name} from" \ - " #{base_project.path_with_namespace}" + " #{start_branch_name} from" \ + " #{start_project.path_with_namespace}" end - elsif base_branch_name - unless repository.branch_exists?(base_branch_name) + elsif start_branch_name + unless repository.branch_exists?(start_branch_name) raise ArgumentError, "Cannot find branch #{branch_name} nor" \ - " #{base_branch_name} from" \ + " #{start_branch_name} from" \ " #{repository.project.path_with_namespace}" end end -- GitLab From a6394540327cd3919e5189a35a21b57800a104fc Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Fri, 6 Jan 2017 23:50:08 +0800 Subject: [PATCH 72/78] Fix renaming --- lib/api/commits.rb | 2 +- lib/api/files.rb | 2 +- spec/features/projects/files/editing_a_file_spec.rb | 2 +- spec/lib/gitlab/diff/position_tracer_spec.rb | 6 +++--- spec/models/repository_spec.rb | 2 +- spec/services/files/update_service_spec.rb | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 2c1da0902c9..031759cdcdf 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -55,7 +55,7 @@ module API authorize! :push_code, user_project attrs = declared_params - attrs[:source_branch] = attrs[:branch_name] + attrs[:start_branch] = attrs[:branch_name] attrs[:target_branch] = attrs[:branch_name] attrs[:actions].map! do |action| action[:action] = action[:action].to_sym diff --git a/lib/api/files.rb b/lib/api/files.rb index 2e79e22e649..c58472de578 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -5,7 +5,7 @@ module API def commit_params(attrs) { file_path: attrs[:file_path], - source_branch: attrs[:branch_name], + start_branch: attrs[:branch_name], target_branch: attrs[:branch_name], commit_message: attrs[:commit_message], file_content: attrs[:content], diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb index fe047e00409..36a80d7575d 100644 --- a/spec/features/projects/files/editing_a_file_spec.rb +++ b/spec/features/projects/files/editing_a_file_spec.rb @@ -7,7 +7,7 @@ feature 'User wants to edit a file', feature: true do let(:user) { create(:user) } let(:commit_params) do { - source_branch: project.default_branch, + start_branch: project.default_branch, target_branch: project.default_branch, commit_message: "Committing First Update", file_path: ".gitignore", diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb index c268f84c759..f77ab016e9b 100644 --- a/spec/lib/gitlab/diff/position_tracer_spec.rb +++ b/spec/lib/gitlab/diff/position_tracer_spec.rb @@ -99,7 +99,7 @@ describe Gitlab::Diff::PositionTracer, lib: true do Files::CreateService.new( project, current_user, - source_branch: branch_name, + start_branch: branch_name, target_branch: branch_name, commit_message: "Create file", file_path: file_name, @@ -112,7 +112,7 @@ describe Gitlab::Diff::PositionTracer, lib: true do Files::UpdateService.new( project, current_user, - source_branch: branch_name, + start_branch: branch_name, target_branch: branch_name, commit_message: "Update file", file_path: file_name, @@ -125,7 +125,7 @@ describe Gitlab::Diff::PositionTracer, lib: true do Files::DeleteService.new( project, current_user, - source_branch: branch_name, + start_branch: branch_name, target_branch: branch_name, commit_message: "Delete file", file_path: file_name diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 0f43c5c019a..36564a3f9e0 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -280,7 +280,7 @@ describe Repository, models: true do expect do repository.commit_dir(user, 'newdir', message: 'Create newdir', branch_name: 'patch', - source_branch_name: 'master', source_project: forked_project) + start_branch_name: 'master', start_project: forked_project) end.to change { repository.commits('master').count }.by(0) expect(repository.branch_exists?('patch')).to be_truthy diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb index 6fadee9304b..35e6e139238 100644 --- a/spec/services/files/update_service_spec.rb +++ b/spec/services/files/update_service_spec.rb @@ -17,8 +17,8 @@ describe Files::UpdateService do file_content: new_contents, file_content_encoding: "text", last_commit_sha: last_commit_sha, - source_project: project, - source_branch: project.default_branch, + start_project: project, + start_branch: project.default_branch, target_branch: target_branch } end -- GitLab From acda0cd48d69dbd98ec9df8339f15139cd098726 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 26 Jan 2017 19:13:02 +0800 Subject: [PATCH 73/78] @tree_edit_project is no longer used Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_21626434 --- app/controllers/concerns/creates_commit.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 2ece99aebc0..fa7c22b5388 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -101,7 +101,6 @@ module CreatesCommit def set_commit_variables if can?(current_user, :push_code, @project) # Edit file in this project - @tree_edit_project = @project @mr_source_project = @project if @project.forked? @@ -114,10 +113,8 @@ module CreatesCommit @mr_target_branch = @ref || @target_branch end else - # Edit file in fork - @tree_edit_project = current_user.fork_of(@project) # Merge request from fork to this project - @mr_source_project = @tree_edit_project + @mr_source_project = current_user.fork_of(@project) @mr_target_project = @project @mr_target_branch = @ref || @target_branch end -- GitLab From 9bb4cd75ad51f61a53a2bef205be2b4b24acc513 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 26 Jan 2017 19:22:44 +0800 Subject: [PATCH 74/78] Use commit rather than branch, and rename to avoid confusion Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_21626953 https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_21626952 --- app/models/repository.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index f3a0148c423..6c847e07c00 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -996,10 +996,10 @@ class Repository end end - def check_revert_content(commit, branch_name) - source_sha = find_branch(branch_name).dereferenced_target.sha - args = [commit.id, source_sha] - args << { mainline: 1 } if commit.merge_commit? + def check_revert_content(target_commit, branch_name) + source_sha = commit(branch_name).sha + args = [target_commit.sha, source_sha] + args << { mainline: 1 } if target_commit.merge_commit? revert_index = rugged.revert_commit(*args) return false if revert_index.conflicts? @@ -1010,10 +1010,10 @@ class Repository tree_id end - def check_cherry_pick_content(commit, branch_name) - source_sha = find_branch(branch_name).dereferenced_target.sha - args = [commit.id, source_sha] - args << 1 if commit.merge_commit? + def check_cherry_pick_content(target_commit, branch_name) + source_sha = commit(branch_name).sha + args = [target_commit.sha, source_sha] + args << 1 if target_commit.merge_commit? cherry_pick_index = rugged.cherrypick_commit(*args) return false if cherry_pick_index.conflicts? -- GitLab From 05f4e48a4c761e13faf080e2d33fb8cc9886f723 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 26 Jan 2017 19:35:19 +0800 Subject: [PATCH 75/78] Make GitHooksService#execute return block value Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_21627207 --- app/services/git_hooks_service.rb | 6 +++--- app/services/git_operation_service.rb | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/services/git_hooks_service.rb b/app/services/git_hooks_service.rb index 6cd3908d43a..d222d1e63aa 100644 --- a/app/services/git_hooks_service.rb +++ b/app/services/git_hooks_service.rb @@ -18,9 +18,9 @@ class GitHooksService end end - yield self - - run_hook('post-receive') + yield(self).tap do + run_hook('post-receive') + end end private diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 2b2ba0870a4..df9c393844d 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -107,8 +107,6 @@ class GitOperationService end def with_hooks(ref, newrev, oldrev) - result = nil - GitHooksService.new.execute( user, repository.path_to_repo, @@ -116,10 +114,8 @@ class GitOperationService newrev, ref) do |service| - result = yield(service) if block_given? + yield(service) end - - result end def update_ref(ref, newrev, oldrev) -- GitLab From d475fa094689a6319fa60f2532898234979e30d3 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 26 Jan 2017 21:18:04 +0800 Subject: [PATCH 76/78] We don't care about the return value now --- spec/services/git_hooks_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/git_hooks_service_spec.rb b/spec/services/git_hooks_service_spec.rb index 41b0968b8b4..3318dfb22b6 100644 --- a/spec/services/git_hooks_service_spec.rb +++ b/spec/services/git_hooks_service_spec.rb @@ -21,7 +21,7 @@ describe GitHooksService, services: true do hook = double(trigger: [true, nil]) expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook) - expect(service.execute(user, @repo_path, @blankrev, @newrev, @ref) { }).to eq([true, nil]) + service.execute(user, @repo_path, @blankrev, @newrev, @ref) { } end end -- GitLab From 8f3aa6ac338ee3595909fea9938611fb03187e6a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 26 Jan 2017 21:59:12 +0800 Subject: [PATCH 77/78] Try to check if branch diverged explicitly Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_21627134 --- app/services/git_operation_service.rb | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index df9c393844d..27bcc047601 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -82,12 +82,7 @@ class GitOperationService end branch = repository.find_branch(branch_name) - oldrev = if branch - # This could verify we're not losing commits - repository.rugged.merge_base(newrev, branch.target) - else - Gitlab::Git::BLANK_SHA - end + oldrev = find_oldrev_from_branch(newrev, branch) ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name update_ref_in_hooks(ref, newrev, oldrev) @@ -100,6 +95,18 @@ class GitOperationService newrev end + def find_oldrev_from_branch(newrev, branch) + return Gitlab::Git::BLANK_SHA unless branch + + oldrev = branch.target + + if oldrev == repository.rugged.merge_base(newrev, branch.target) + oldrev + else + raise Repository::CommitError.new('Branch diverged') + end + end + def update_ref_in_hooks(ref, newrev, oldrev) with_hooks(ref, newrev, oldrev) do update_ref(ref, newrev, oldrev) -- GitLab From eb242fc865c032f6408f3b68700da9b840b416dd Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin <godfat@godfat.org> Date: Thu, 26 Jan 2017 22:37:22 +0800 Subject: [PATCH 78/78] Make sure different project gets a merge request Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7237#note_21626479 --- app/controllers/concerns/creates_commit.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index fa7c22b5388..6286d67d30c 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -93,8 +93,10 @@ module CreatesCommit def create_merge_request? # XXX: Even if the field is set, if we're checking the same branch - # as the target branch, we don't want to create a merge request. - params[:create_merge_request].present? && @ref != @target_branch + # as the target branch in the same project, + # we don't want to create a merge request. + params[:create_merge_request].present? && + (different_project? || @ref != @target_branch) end # TODO: We should really clean this up -- GitLab