-
Notifications
You must be signed in to change notification settings - Fork 312
Custom hooks #190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Custom hooks #190
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#!/usr/bin/env ruby | ||
|
||
# This file was placed here by GitLab. It makes sure that your pushed commits | ||
# will be processed properly. | ||
|
||
ref_name = ARGV[0] | ||
old_value = ARGV[1] | ||
new_value = ARGV[2] | ||
repo_path = Dir.pwd | ||
|
||
require_relative '../lib/gitlab_custom_hook' | ||
|
||
if GitlabCustomHook.new.update(ref_name, old_value, new_value, repo_path) | ||
exit 0 | ||
else | ||
exit 1 | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
require 'open3' | ||
|
||
class GitlabCustomHook | ||
def pre_receive(changes, repo_path) | ||
hook = hook_file('pre-receive', repo_path) | ||
return true if hook.nil? | ||
if call_receive_hook(hook, changes) | ||
return true | ||
else | ||
# reset GL_ID env since we stop git push here | ||
ENV['GL_ID'] = nil | ||
return false | ||
end | ||
end | ||
|
||
def post_receive(changes, repo_path) | ||
hook = hook_file('post-receive', repo_path) | ||
return true if hook.nil? | ||
call_receive_hook(hook, changes) ? true : false | ||
end | ||
|
||
def update(ref_name, old_value, new_value, repo_path) | ||
hook = hook_file('update', repo_path) | ||
return true if hook.nil? | ||
system(hook, ref_name, old_value, new_value) ? true : false | ||
end | ||
|
||
private | ||
|
||
def call_receive_hook(hook, changes) | ||
# function will return true if succesful | ||
exit_status = false | ||
|
||
# we combine both stdout and stderr as we don't know what stream | ||
# will be used by the custom hook | ||
Open3.popen2e (hook) do |stdin, stdout_stderr, wait_thr| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dblessing can you describe me what happens in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a nutshell, this function emulates the pre- andpost-receive hook API that a standalone git provides. To be more precise, the git interface for the pre-receive and post-receive comments sends the information of what branch and references have changed directly thru stdin, not thru the command line arguments. This is what this function does. Like @dblessing said, you can push multiple branches. That's the other part that this function does, feeding each line thru stdin. This has the benefit that you can use standard git hook code as we respect the API. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. aha so when executed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. call_receive_hook() does that does that for both pre-receive and post-receive custom hooks. There may just one difference, though, but the git API is not clear about this. When you do a multiple branch push and the custom pre- and post- receive hooks fail for one or more of the pushed branches, it is not clear how to tell git that some branches failed. I took the choice of not returning success unless the hook returns success for all the branches. The git docs don't talk about this at all. The custom update hook calls works exactly as git's. The tests I did was that I wrote very simple pre-receive, post-receive, and update hooks that just output what's being fed by the API and tested them all in permutations when returning with exit 0 or exit 1. First did the tests on a standalone vanilla git environment and then verified that we had the the same behavior inside gitlab by means of gitlab_custom_hook.rb My own more complex custom hooks now work the same in either the vanilla git or gitlab. The git doc: http://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jkbzh thanks |
||
exit_status = true | ||
stdin.sync = true | ||
|
||
# in git, pre- and post- receive hooks may just exit without | ||
# reading stdin. We catch the exception to avoid a broken pipe | ||
# warning | ||
begin | ||
# inject all the changes as stdin to the hook | ||
changes.lines do |line| | ||
stdin.puts (line) | ||
end | ||
rescue Errno::EPIPE | ||
end | ||
|
||
# need to close stdin before reading stdout | ||
stdin.close | ||
|
||
# only output stdut_stderr if scripts doesn't return 0 | ||
unless wait_thr.value == 0 | ||
exit_status = false | ||
stdout_stderr.each_line { |line| puts line } | ||
end | ||
end | ||
|
||
exit_status | ||
end | ||
|
||
def hook_file(hook_type, repo_path) | ||
hook_path = File.join(repo_path.strip, 'custom_hooks') | ||
hook_file = "#{hook_path}/#{hook_type}" | ||
hook_file if File.exist?(hook_file) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this would not be multiple files. Only one hook per type per repo.