Add RevertService class with basic logic to revert commit
This commit is contained in:
parent
34e26b8212
commit
8061399368
4 changed files with 100 additions and 12 deletions
|
@ -11,6 +11,7 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
before_action :authorize_read_commit_status!, only: [:builds]
|
||||
before_action :commit
|
||||
before_action :define_show_vars, only: [:show, :builds]
|
||||
before_action :assign_revert_commit_vars, only: [:revert]
|
||||
before_action :authorize_edit_tree!, only: [:revert]
|
||||
|
||||
def show
|
||||
|
@ -59,7 +60,11 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def revert
|
||||
# return render_404 unless @commit_params.values.all?
|
||||
|
||||
create_commit(Commits::RevertService, success_notice: "The commit has been successfully reverted.",
|
||||
success_path: namespace_project_commits_path(@project.namespace, @project, @target_branch),
|
||||
failure_path: namespace_project_commit_path(@project.namespace, @project, params[:id]))
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -86,4 +91,12 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
|
||||
@statuses = ci_commit.statuses if ci_commit
|
||||
end
|
||||
|
||||
def assign_revert_commit_vars
|
||||
@target_branch = params[:target_branch]
|
||||
|
||||
@commit_params = {
|
||||
revert_commit_id: params[:id],
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -215,6 +215,14 @@ class Commit
|
|||
ci_commit.try(:status) || :not_found
|
||||
end
|
||||
|
||||
def revert_branch_name
|
||||
"revert-#{project.id}-#{short_id}"
|
||||
end
|
||||
|
||||
def revert_message
|
||||
"Revert \"#{safe_message.lines.first}\"".truncate(80) + "\n\nReverts #{to_reference}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def repo_changes
|
||||
|
|
|
@ -622,29 +622,48 @@ class Repository
|
|||
merge_commit_sha
|
||||
end
|
||||
|
||||
def revert_merge(user, merge_commit_id, new_branch_name, target_branch, commit_message)
|
||||
# branch exists and it's highly probable that it has the revert commit
|
||||
return if find_branch(new_branch_name)
|
||||
def revert(user, commit_id, target_branch, base_branch, commit_message)
|
||||
source_sha = find_branch(base_branch).target
|
||||
target_sha = find_branch(target_branch).try(:target)
|
||||
|
||||
target_sha = find_branch(target_branch).target
|
||||
# First make revert in temp branch
|
||||
unless target_sha
|
||||
revert_commit(user, commit_id, target_branch, base_branch, commit_message)
|
||||
end
|
||||
|
||||
# Make the revert happen in the target branch
|
||||
source_sha = find_branch(target_branch).target
|
||||
target_sha = find_branch(base_branch).target
|
||||
|
||||
if is_there_something_to_merge?(source_sha, target_sha)
|
||||
revert_commit(user, commit_id, base_branch, base_branch, commit_message)
|
||||
end
|
||||
end
|
||||
|
||||
def revert_commit(user, commit_id, target_branch, base_branch, commit_message)
|
||||
base_sha = find_branch(base_branch).target
|
||||
|
||||
commit_with_hooks(user, target_branch) do |ref|
|
||||
new_index = rugged.revert_commit(commit_id, base_sha)#, mainline: 1)
|
||||
|
||||
return false if new_index.conflicts?
|
||||
|
||||
commit_with_hooks(user, new_branch_name) do |ref|
|
||||
new_index = rugged.revert_commit(merge_commit_id, target_sha, mainline: 1)
|
||||
committer = user_to_committer(user)
|
||||
|
||||
options = {
|
||||
source_sha = Rugged::Commit.create(rugged, {
|
||||
message: commit_message,
|
||||
author: committer,
|
||||
committer: committer,
|
||||
tree: new_index.write_tree(rugged),
|
||||
parents: [rugged.lookup(target_sha)],
|
||||
parents: [rugged.lookup(base_sha)],
|
||||
update_ref: ref
|
||||
}
|
||||
|
||||
Rugged::Commit.create(rugged, options)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def is_there_something_to_merge?(source_branch_sha, target_branch_sha)
|
||||
CompareService.new.execute(project, source_branch_sha, project, target_branch_sha).diffs.present?
|
||||
end
|
||||
|
||||
def merged_to_root_ref?(branch_name)
|
||||
branch_commit = commit(branch_name)
|
||||
root_ref_commit = commit(root_ref)
|
||||
|
|
48
app/services/commits/revert_service.rb
Normal file
48
app/services/commits/revert_service.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
module Commits
|
||||
class RevertService < ::BaseService
|
||||
class ValidationError < StandardError; end
|
||||
|
||||
def execute
|
||||
@source_project = params[:source_project] || @project
|
||||
@target_branch = params[:target_branch]
|
||||
@commit_to_revert = @source_project.commit(params[:revert_commit_id])
|
||||
|
||||
# Check push permissions to branch
|
||||
validate
|
||||
|
||||
if commit
|
||||
success
|
||||
else
|
||||
error("Something went wrong. Your changes were not committed")
|
||||
end
|
||||
rescue Repository::CommitError, Gitlab::Git::Repository::InvalidBlobName, GitHooksService::PreReceiveError, ValidationError => ex
|
||||
error(ex.message)
|
||||
end
|
||||
|
||||
def commit
|
||||
raw_repo = repository.rugged
|
||||
|
||||
# Create branch with revert commit
|
||||
reverted = repository.revert(current_user, @commit_to_revert.id,
|
||||
@commit_to_revert.revert_branch_name, @target_branch,
|
||||
@commit_to_revert.revert_message)
|
||||
repository.rm_branch(current_user, @commit_to_revert.revert_branch_name)
|
||||
|
||||
reverted
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def raise_error(message)
|
||||
raise ValidationError.new(message)
|
||||
end
|
||||
|
||||
def validate
|
||||
allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(@target_branch)
|
||||
|
||||
unless allowed
|
||||
raise_error("You are not allowed to push into this branch")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue