Refactor how repository makes commit with pre/post receive hooks
This commit is contained in:
parent
4e4866f255
commit
f4149bcddc
6 changed files with 94 additions and 95 deletions
|
@ -1,4 +1,9 @@
|
|||
require 'securerandom'
|
||||
|
||||
class Repository
|
||||
class PreReceiveError < StandardError; end
|
||||
class CommitError < StandardError; end
|
||||
|
||||
include Gitlab::ShellAdapter
|
||||
|
||||
attr_accessor :raw_repository, :path_with_namespace, :project
|
||||
|
@ -364,43 +369,47 @@ class Repository
|
|||
@root_ref ||= raw_repository.root_ref
|
||||
end
|
||||
|
||||
def commit_file(user, path, content, message, ref)
|
||||
path[0] = '' if path[0] == '/'
|
||||
def commit_file(user, path, content, message, branch)
|
||||
commit_with_hooks(user, branch) do |ref|
|
||||
path[0] = '' if path[0] == '/'
|
||||
|
||||
committer = user_to_comitter(user)
|
||||
options = {}
|
||||
options[:committer] = committer
|
||||
options[:author] = committer
|
||||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref,
|
||||
}
|
||||
committer = user_to_comitter(user)
|
||||
options = {}
|
||||
options[:committer] = committer
|
||||
options[:author] = committer
|
||||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref,
|
||||
}
|
||||
|
||||
options[:file] = {
|
||||
content: content,
|
||||
path: path
|
||||
}
|
||||
options[:file] = {
|
||||
content: content,
|
||||
path: path
|
||||
}
|
||||
|
||||
Gitlab::Git::Blob.commit(raw_repository, options)
|
||||
Gitlab::Git::Blob.commit(raw_repository, options)
|
||||
end
|
||||
end
|
||||
|
||||
def remove_file(user, path, message, ref)
|
||||
path[0] = '' if path[0] == '/'
|
||||
def remove_file(user, path, message, branch)
|
||||
commit_with_hooks(user, branch) do |branch|
|
||||
path[0] = '' if path[0] == '/'
|
||||
|
||||
committer = user_to_comitter(user)
|
||||
options = {}
|
||||
options[:committer] = committer
|
||||
options[:author] = committer
|
||||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref
|
||||
}
|
||||
committer = user_to_comitter(user)
|
||||
options = {}
|
||||
options[:committer] = committer
|
||||
options[:author] = committer
|
||||
options[:commit] = {
|
||||
message: message,
|
||||
branch: ref
|
||||
}
|
||||
|
||||
options[:file] = {
|
||||
path: path
|
||||
}
|
||||
options[:file] = {
|
||||
path: path
|
||||
}
|
||||
|
||||
Gitlab::Git::Blob.remove(raw_repository, options)
|
||||
Gitlab::Git::Blob.remove(raw_repository, options)
|
||||
end
|
||||
end
|
||||
|
||||
def user_to_comitter(user)
|
||||
|
@ -479,6 +488,58 @@ class Repository
|
|||
Gitlab::Popen.popen(args, path_to_repo)
|
||||
end
|
||||
|
||||
def commit_with_hooks(current_user, branch)
|
||||
oldrev = Gitlab::Git::BLANK_SHA
|
||||
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch
|
||||
gl_id = Gitlab::ShellEnv.gl_id(current_user)
|
||||
|
||||
# Create temporary ref
|
||||
random_string = SecureRandom.hex
|
||||
tmp_ref = "refs/tmp/#{random_string}/head"
|
||||
|
||||
unless empty?
|
||||
oldrev = find_branch(branch).target
|
||||
rugged.references.create(tmp_ref, oldrev)
|
||||
end
|
||||
|
||||
# Make commit in tmp ref
|
||||
newrev = yield(tmp_ref)
|
||||
|
||||
unless newrev
|
||||
raise CommitError.new('Failed to create commit')
|
||||
end
|
||||
|
||||
# Run GitLab pre-receive hook
|
||||
pre_receive_hook = Gitlab::Git::Hook.new('pre-receive', path_to_repo)
|
||||
status = pre_receive_hook.trigger(gl_id, oldrev, newrev, ref)
|
||||
|
||||
if status
|
||||
if empty?
|
||||
# Create branch
|
||||
rugged.references.create(ref, newrev)
|
||||
else
|
||||
# Update head
|
||||
current_head = find_branch(branch).target
|
||||
|
||||
# Make sure target branch was not changed during pre-receive hook
|
||||
if current_head == oldrev
|
||||
rugged.references.update(ref, newrev)
|
||||
else
|
||||
raise CommitError.new('Commit was rejected because branch received new push')
|
||||
end
|
||||
end
|
||||
|
||||
# Run GitLab post receive hook
|
||||
post_receive_hook = Gitlab::Git::Hook.new('post-receive', path_to_repo)
|
||||
status = post_receive_hook.trigger(gl_id, oldrev, newrev, ref)
|
||||
else
|
||||
# Remove tmp ref and return error to user
|
||||
rugged.references.delete(tmp_ref)
|
||||
|
||||
raise PreReceiveError.new('Commit was rejected by pre-reveive hook')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cache
|
||||
|
|
|
@ -1,61 +1,5 @@
|
|||
require 'securerandom'
|
||||
|
||||
class CommitService
|
||||
class PreReceiveError < StandardError; end
|
||||
class CommitError < StandardError; end
|
||||
|
||||
def self.transaction(project, current_user, branch)
|
||||
repository = project.repository
|
||||
path_to_repo = repository.path_to_repo
|
||||
empty_repo = repository.empty?
|
||||
oldrev = Gitlab::Git::BLANK_SHA
|
||||
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch
|
||||
gl_id = Gitlab::ShellEnv.gl_id(current_user)
|
||||
|
||||
# Create temporary ref
|
||||
random_string = SecureRandom.hex
|
||||
tmp_ref = "refs/tmp/#{random_string}/head"
|
||||
|
||||
unless empty_repo
|
||||
oldrev = repository.find_branch(branch).target
|
||||
repository.rugged.references.create(tmp_ref, oldrev)
|
||||
end
|
||||
|
||||
# Make commit in tmp ref
|
||||
newrev = yield(tmp_ref)
|
||||
|
||||
unless newrev
|
||||
raise CommitError.new('Failed to create commit')
|
||||
end
|
||||
|
||||
# Run GitLab pre-receive hook
|
||||
pre_receive_hook = Gitlab::Git::Hook.new('pre-receive', path_to_repo)
|
||||
status = pre_receive_hook.trigger(gl_id, oldrev, newrev, ref)
|
||||
|
||||
if status
|
||||
if empty_repo
|
||||
# Create branch
|
||||
repository.rugged.references.create(ref, newrev)
|
||||
else
|
||||
# Update head
|
||||
current_head = repository.find_branch(branch).target
|
||||
|
||||
# Make sure target branch was not changed during pre-receive hook
|
||||
if current_head == oldrev
|
||||
repository.rugged.references.update(ref, newrev)
|
||||
else
|
||||
raise CommitError.new('Commit was rejected because branch received new push')
|
||||
end
|
||||
end
|
||||
|
||||
# Run GitLab post receive hook
|
||||
post_receive_hook = Gitlab::Git::Hook.new('post-receive', path_to_repo)
|
||||
status = post_receive_hook.trigger(gl_id, oldrev, newrev, ref)
|
||||
else
|
||||
# Remove tmp ref and return error to user
|
||||
repository.rugged.references.delete(tmp_ref)
|
||||
|
||||
raise PreReceiveError.new('Commit was rejected by pre-reveive hook')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,7 +26,7 @@ module Files
|
|||
else
|
||||
error("Something went wrong. Your changes were not committed")
|
||||
end
|
||||
rescue CommitService::CommitError, CommitService::PreReceiveError, ValidationError => ex
|
||||
rescue Repository::CommitError, Repository::PreReceiveError, ValidationError => ex
|
||||
error(ex.message)
|
||||
end
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ require_relative "base_service"
|
|||
module Files
|
||||
class CreateService < Files::BaseService
|
||||
def commit
|
||||
CommitService.transaction(project, current_user, @target_branch) do |tmp_ref|
|
||||
repository.commit_file(current_user, @file_path, @file_content, @commit_message, tmp_ref)
|
||||
end
|
||||
repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch)
|
||||
end
|
||||
|
||||
def validate
|
||||
|
|
|
@ -3,9 +3,7 @@ require_relative "base_service"
|
|||
module Files
|
||||
class DeleteService < Files::BaseService
|
||||
def commit
|
||||
CommitService.transaction(project, current_user, @target_branch) do |tmp_ref|
|
||||
repository.remove_file(current_user, @file_path, @commit_message, tmp_ref)
|
||||
end
|
||||
repository.remove_file(current_user, @file_path, @commit_message, @target_branch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,9 +3,7 @@ require_relative "base_service"
|
|||
module Files
|
||||
class UpdateService < Files::BaseService
|
||||
def commit
|
||||
CommitService.transaction(project, current_user, @target_branch) do |tmp_ref|
|
||||
repository.commit_file(current_user, @file_path, @file_content, @commit_message, tmp_ref)
|
||||
end
|
||||
repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue