summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2014-11-07 15:19:03 +0200
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2014-11-07 15:19:03 +0200
commitff9808c0f24ed562d6bacd1061f0f8e30a3452f3 (patch)
treeed5f44fa244d95ded39d70ab2691c3709868f272
parent00b3d2cb7095af3859734c88a7797182e598f047 (diff)
parentb6d84f628489ebb6b8915dfa4808c552fe8e267b (diff)
downloadgitlab-shell-ff9808c0f24ed562d6bacd1061f0f8e30a3452f3.tar.gz
Merge pull request #190 from dblessing/feature/custom_hooks
Custom hooks
-rwxr-xr-xhooks/post-receive7
-rwxr-xr-xhooks/pre-receive5
-rwxr-xr-xhooks/update17
-rw-r--r--lib/gitlab_access.rb2
-rw-r--r--lib/gitlab_custom_hook.rb69
-rw-r--r--lib/gitlab_post_receive.rb7
6 files changed, 99 insertions, 8 deletions
diff --git a/hooks/post-receive b/hooks/post-receive
index d85ad42..301f639 100755
--- a/hooks/post-receive
+++ b/hooks/post-receive
@@ -2,15 +2,16 @@
# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
-# You can add your own hooks to this file, but be careful when updating gitlab-shell!
-changes = ARGF.read
+refs = ARGF.read
key_id = ENV['GL_ID']
repo_path = Dir.pwd
+require_relative '../lib/gitlab_custom_hook'
require_relative '../lib/gitlab_post_receive'
-if GitlabPostReceive.new(repo_path, key_id, changes).exec
+if GitlabPostReceive.new(repo_path, key_id, refs).exec &&
+ GitlabCustomHook.new.post_receive(refs, repo_path)
exit 0
else
exit 1
diff --git a/hooks/pre-receive b/hooks/pre-receive
index 2b979fa..7f9c0c0 100755
--- a/hooks/pre-receive
+++ b/hooks/pre-receive
@@ -2,15 +2,16 @@
# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
-# You can add your own hooks to this file, but be careful when updating gitlab-shell!
refs = ARGF.read
key_id = ENV['GL_ID']
repo_path = Dir.pwd
+require_relative '../lib/gitlab_custom_hook'
require_relative '../lib/gitlab_access'
-if GitlabAccess.new(repo_path, key_id, refs).exec
+if GitlabAccess.new(repo_path, key_id, refs).exec &&
+ GitlabCustomHook.new.pre_receive(refs, repo_path)
exit 0
else
exit 1
diff --git a/hooks/update b/hooks/update
new file mode 100755
index 0000000..f1ac8e7
--- /dev/null
+++ b/hooks/update
@@ -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
diff --git a/lib/gitlab_access.rb b/lib/gitlab_access.rb
index 804d06d..78d353c 100644
--- a/lib/gitlab_access.rb
+++ b/lib/gitlab_access.rb
@@ -23,7 +23,7 @@ class GitlabAccess
# reset GL_ID env since we stop git push here
ENV['GL_ID'] = nil
puts "GitLab: You are not allowed to access some of the refs!"
- exit 1
+ return false
end
end
diff --git a/lib/gitlab_custom_hook.rb b/lib/gitlab_custom_hook.rb
new file mode 100644
index 0000000..ba11e29
--- /dev/null
+++ b/lib/gitlab_custom_hook.rb
@@ -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|
+ 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
diff --git a/lib/gitlab_post_receive.rb b/lib/gitlab_post_receive.rb
index bd80408..b4770d9 100644
--- a/lib/gitlab_post_receive.rb
+++ b/lib/gitlab_post_receive.rb
@@ -23,9 +23,12 @@ class GitlabPostReceive
def update_redis
queue = "#{config.redis_namespace}:queue:post_receive"
msg = JSON.dump({'class' => 'PostReceive', 'args' => [@repo_path, @actor, @changes]})
- unless system(*config.redis_command, 'rpush', queue, msg, err: '/dev/null', out: '/dev/null')
+ if system(*config.redis_command, 'rpush', queue, msg,
+ err: '/dev/null', out: '/dev/null')
+ return true
+ else
puts "GitLab: An unexpected error occurred (redis-cli returned #{$?.exitstatus})."
- exit 1
+ return false
end
end
end