Commit aa9b97f0 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'git_hooks_better_message' into 'master'

More descriptive message for git hooks and file locks

## What does this MR do?
Most of the benefits will be in GitLab EE because we have git hooks there (push rules) and file lock features.
Instead of showing "Git operation was rejected by #{hook_name} hook" the actual problem description will be shown.
Also you will see a clear message when you edit locked file.

## Why was this MR needed?

Because we don't want to confuse our users

## What are the relevant issue numbers?

https://gitlab.com/gitlab-org/gitlab-ee/issues/713


See merge request !5067
parents 021b6aef bf218337
...@@ -32,6 +32,7 @@ v 8.10.0 (unreleased) ...@@ -32,6 +32,7 @@ v 8.10.0 (unreleased)
- Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w)
- Add basic system information like memory and disk usage to the admin panel - Add basic system information like memory and disk usage to the admin panel
- Don't garbage collect commits that have related DB records like comments - Don't garbage collect commits that have related DB records like comments
- More descriptive message for git hooks and file locks
v 8.9.5 (unreleased) v 8.9.5 (unreleased)
- Improve the request / withdraw access button. !4860 - Improve the request / withdraw access button. !4860
......
...@@ -34,8 +34,8 @@ class CreateBranchService < BaseService ...@@ -34,8 +34,8 @@ class CreateBranchService < BaseService
else else
error('Invalid reference name') error('Invalid reference name')
end end
rescue GitHooksService::PreReceiveError rescue GitHooksService::PreReceiveError => ex
error('Branch creation was rejected by Git hook') error(ex.message)
end end
def success(branch) def success(branch)
......
...@@ -13,8 +13,8 @@ class CreateTagService < BaseService ...@@ -13,8 +13,8 @@ class CreateTagService < BaseService
new_tag = repository.add_tag(current_user, tag_name, target, message) new_tag = repository.add_tag(current_user, tag_name, target, message)
rescue Rugged::TagError rescue Rugged::TagError
return error("Tag #{tag_name} already exists") return error("Tag #{tag_name} already exists")
rescue GitHooksService::PreReceiveError rescue GitHooksService::PreReceiveError => ex
return error('Tag creation was rejected by Git hook') return error(ex.message)
end end
if new_tag if new_tag
......
...@@ -30,8 +30,8 @@ class DeleteBranchService < BaseService ...@@ -30,8 +30,8 @@ class DeleteBranchService < BaseService
else else
error('Failed to remove branch') error('Failed to remove branch')
end end
rescue GitHooksService::PreReceiveError rescue GitHooksService::PreReceiveError => ex
error('Branch deletion was rejected by Git hook') error(ex.message)
end end
def error(message, return_code = 400) def error(message, return_code = 400)
......
...@@ -9,8 +9,10 @@ class GitHooksService ...@@ -9,8 +9,10 @@ class GitHooksService
@ref = ref @ref = ref
%w(pre-receive update).each do |hook_name| %w(pre-receive update).each do |hook_name|
unless run_hook(hook_name) status, message = run_hook(hook_name)
raise PreReceiveError.new("Git operation was rejected by #{hook_name} hook")
unless status
raise PreReceiveError, message
end end
end end
......
...@@ -29,8 +29,8 @@ module Gitlab ...@@ -29,8 +29,8 @@ module Gitlab
def call_receive_hook(gl_id, oldrev, newrev, ref) def call_receive_hook(gl_id, oldrev, newrev, ref)
changes = [oldrev, newrev, ref].join(" ") changes = [oldrev, newrev, ref].join(" ")
# function will return true if succesful
exit_status = false exit_status = false
exit_message = nil
vars = { vars = {
'GL_ID' => gl_id, 'GL_ID' => gl_id,
...@@ -41,7 +41,7 @@ module Gitlab ...@@ -41,7 +41,7 @@ module Gitlab
chdir: repo_path chdir: repo_path
} }
Open3.popen2(vars, path, options) do |stdin, _, wait_thr| Open3.popen3(vars, path, options) do |stdin, _, stderr, wait_thr|
exit_status = true exit_status = true
stdin.sync = true stdin.sync = true
...@@ -60,16 +60,21 @@ module Gitlab ...@@ -60,16 +60,21 @@ module Gitlab
unless wait_thr.value == 0 unless wait_thr.value == 0
exit_status = false exit_status = false
exit_message = stderr.gets
end end
end end
exit_status [exit_status, exit_message]
end end
def call_update_hook(gl_id, oldrev, newrev, ref) def call_update_hook(gl_id, oldrev, newrev, ref)
status = nil
Dir.chdir(repo_path) do Dir.chdir(repo_path) do
system({ 'GL_ID' => gl_id }, path, ref, oldrev, newrev) status = system({ 'GL_ID' => gl_id }, path, ref, oldrev, newrev)
end end
[status, nil]
end end
end end
end end
......
...@@ -308,14 +308,14 @@ describe Repository, models: true do ...@@ -308,14 +308,14 @@ describe Repository, models: true do
describe :add_branch do describe :add_branch do
context 'when pre hooks were successful' do context 'when pre hooks were successful' do
it 'should run without errors' do it 'should run without errors' do
hook = double(trigger: true) hook = double(trigger: [true, nil])
expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook) expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
expect { repository.add_branch(user, 'new_feature', 'master') }.not_to raise_error expect { repository.add_branch(user, 'new_feature', 'master') }.not_to raise_error
end end
it 'should create the branch' do it 'should create the branch' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
branch = repository.add_branch(user, 'new_feature', 'master') branch = repository.add_branch(user, 'new_feature', 'master')
...@@ -331,7 +331,7 @@ describe Repository, models: true do ...@@ -331,7 +331,7 @@ describe Repository, models: true do
context 'when pre hooks failed' do context 'when pre hooks failed' do
it 'should get an error' do it 'should get an error' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
expect do expect do
repository.add_branch(user, 'new_feature', 'master') repository.add_branch(user, 'new_feature', 'master')
...@@ -339,7 +339,7 @@ describe Repository, models: true do ...@@ -339,7 +339,7 @@ describe Repository, models: true do
end end
it 'should not create the branch' do it 'should not create the branch' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
expect do expect do
repository.add_branch(user, 'new_feature', 'master') repository.add_branch(user, 'new_feature', 'master')
...@@ -352,13 +352,13 @@ describe Repository, models: true do ...@@ -352,13 +352,13 @@ describe Repository, models: true do
describe :rm_branch do describe :rm_branch do
context 'when pre hooks were successful' do context 'when pre hooks were successful' do
it 'should run without errors' do it 'should run without errors' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
expect { repository.rm_branch(user, 'feature') }.not_to raise_error expect { repository.rm_branch(user, 'feature') }.not_to raise_error
end end
it 'should delete the branch' do it 'should delete the branch' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
expect { repository.rm_branch(user, 'feature') }.not_to raise_error expect { repository.rm_branch(user, 'feature') }.not_to raise_error
...@@ -368,7 +368,7 @@ describe Repository, models: true do ...@@ -368,7 +368,7 @@ describe Repository, models: true do
context 'when pre hooks failed' do context 'when pre hooks failed' do
it 'should get an error' do it 'should get an error' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
expect do expect do
repository.rm_branch(user, 'new_feature') repository.rm_branch(user, 'new_feature')
...@@ -376,7 +376,7 @@ describe Repository, models: true do ...@@ -376,7 +376,7 @@ describe Repository, models: true do
end end
it 'should not delete the branch' do it 'should not delete the branch' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
expect do expect do
repository.rm_branch(user, 'feature') repository.rm_branch(user, 'feature')
...@@ -408,7 +408,7 @@ describe Repository, models: true do ...@@ -408,7 +408,7 @@ describe Repository, models: true do
context 'when pre hooks failed' do context 'when pre hooks failed' do
it 'should get an error' do it 'should get an error' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
expect do expect do
repository.commit_with_hooks(user, 'feature') { sample_commit.id } repository.commit_with_hooks(user, 'feature') { sample_commit.id }
......
...@@ -41,12 +41,12 @@ describe CreateTagService, services: true do ...@@ -41,12 +41,12 @@ describe CreateTagService, services: true do
it 'returns an error' do it 'returns an error' do
expect(repository).to receive(:add_tag). expect(repository).to receive(:add_tag).
with(user, 'v1.1.0', 'master', 'Foo'). with(user, 'v1.1.0', 'master', 'Foo').
and_raise(GitHooksService::PreReceiveError) and_raise(GitHooksService::PreReceiveError, 'something went wrong')
response = service.execute('v1.1.0', 'master', 'Foo') response = service.execute('v1.1.0', 'master', 'Foo')
expect(response).to eq(status: :error, expect(response).to eq(status: :error,
message: 'Tag creation was rejected by Git hook') message: 'something went wrong')
end end
end end
end end
......
...@@ -18,16 +18,16 @@ describe GitHooksService, services: true do ...@@ -18,16 +18,16 @@ describe GitHooksService, services: true do
describe '#execute' do describe '#execute' do
context 'when receive hooks were successful' do context 'when receive hooks were successful' do
it 'should call post-receive hook' do it 'should call post-receive hook' do
hook = double(trigger: true) hook = double(trigger: [true, nil])
expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook) 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) expect(service.execute(user, @repo_path, @blankrev, @newrev, @ref) { }).to eq([true, nil])
end end
end end
context 'when pre-receive hook failed' do context 'when pre-receive hook failed' do
it 'should not call post-receive hook' do it 'should not call post-receive hook' do
expect(service).to receive(:run_hook).with('pre-receive').and_return(false) expect(service).to receive(:run_hook).with('pre-receive').and_return([false, ''])
expect(service).not_to receive(:run_hook).with('post-receive') expect(service).not_to receive(:run_hook).with('post-receive')
expect do expect do
...@@ -38,8 +38,8 @@ describe GitHooksService, services: true do ...@@ -38,8 +38,8 @@ describe GitHooksService, services: true do
context 'when update hook failed' do context 'when update hook failed' do
it 'should not call post-receive hook' do it 'should not call post-receive hook' do
expect(service).to receive(:run_hook).with('pre-receive').and_return(true) expect(service).to receive(:run_hook).with('pre-receive').and_return([true, nil])
expect(service).to receive(:run_hook).with('update').and_return(false) expect(service).to receive(:run_hook).with('update').and_return([false, ''])
expect(service).not_to receive(:run_hook).with('post-receive') expect(service).not_to receive(:run_hook).with('post-receive')
expect do expect do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment