From 99585a738cdf119ca59ce932b4ac0f278f6fda88 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Date: Mon, 10 Aug 2015 10:54:42 +0200
Subject: [PATCH] Trigger post-receive hoooks when commits are made by GitLab

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
---
 app/services/post_commit_service.rb | 65 ++++++++++++++++++++++++++++-
 app/workers/post_receive.rb         |  2 +-
 2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/app/services/post_commit_service.rb b/app/services/post_commit_service.rb
index 7d7e5fbc32e..aa9a807b7d2 100644
--- a/app/services/post_commit_service.rb
+++ b/app/services/post_commit_service.rb
@@ -1,8 +1,71 @@
 class PostCommitService < BaseService
+  include Gitlab::Popen
+
+  attr_reader :changes
+
   def execute(sha, branch)
     commit = repository.commit(sha)
     full_ref = 'refs/heads/' + branch
     old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
-    GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
+
+    @changes = "#{old_sha} #{sha} #{full_ref}"
+    post_receive(@changes, repository.path_to_repo)
+  end
+
+  private
+
+  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 call_receive_hook(hook, changes)
+    # function  will return true if succesful
+    exit_status = false
+
+    vars = {
+      'GL_ID' => Gitlab::ShellEnv.gl_id(current_user),
+      'PWD' => repository.path_to_repo
+    }
+
+    options = {
+      chdir: repository.path_to_repo
+    }
+
+    # we combine both stdout and stderr as we don't know what stream
+    # will be used by the custom hook
+    Open3.popen2e(vars, hook, options) 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, 'hooks')
+    hook_file = "#{hook_path}/#{hook_type}"
+    hook_file if File.exist?(hook_file)
   end
 end
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 33d8cc8861b..994b8e8ed38 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -45,7 +45,7 @@ class PostReceive
 
   def utf8_encode_changes(changes)
     changes = changes.dup
-    
+
     changes.force_encoding("UTF-8")
     return changes if changes.valid_encoding?
 
-- 
2.30.9