From 2d774eeae8ccfb211cc6ab6aeab5db600f3fdc7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20H=C3=B6rner?= <dirker@gmail.com> Date: Mon, 5 Sep 2016 10:44:18 +0200 Subject: [PATCH 01/21] custom_hook: only execute hook if file is executable This commit fixes an issue where an existing but unexecutable hook would cause an uncaught execption. --- lib/gitlab_custom_hook.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab_custom_hook.rb b/lib/gitlab_custom_hook.rb index 25385cf..e84d702 100644 --- a/lib/gitlab_custom_hook.rb +++ b/lib/gitlab_custom_hook.rb @@ -56,6 +56,6 @@ class GitlabCustomHook 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) + hook_file if File.executable?(hook_file) end end -- GitLab From d05522de85dcdfa91349c0d9fc78bf72931d6a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20H=C3=B6rner?= <dirker@gmail.com> Date: Mon, 5 Sep 2016 11:59:25 +0200 Subject: [PATCH 02/21] custom_hook: refactor to pull repo_path into class This commit takes the GitlabCustomHook a bit clother to the other hook handling classes by receiving the repo_path as argument to initialize() instead of passing it to each method. --- hooks/post-receive | 2 +- hooks/pre-receive | 2 +- hooks/update | 2 +- lib/gitlab_custom_hook.rb | 15 ++++++++------- spec/gitlab_custom_hook_spec.rb | 8 ++++---- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/hooks/post-receive b/hooks/post-receive index b84d0d1..7877306 100755 --- a/hooks/post-receive +++ b/hooks/post-receive @@ -11,7 +11,7 @@ require_relative '../lib/gitlab_custom_hook' require_relative '../lib/gitlab_post_receive' if GitlabPostReceive.new(repo_path, key_id, refs).exec && - GitlabCustomHook.new(key_id).post_receive(refs, repo_path) + GitlabCustomHook.new(repo_path, key_id).post_receive(refs) exit 0 else exit 1 diff --git a/hooks/pre-receive b/hooks/pre-receive index 4d9a4e9..1b16fd0 100755 --- a/hooks/pre-receive +++ b/hooks/pre-receive @@ -17,7 +17,7 @@ require_relative '../lib/gitlab_access' # other hand, we run GitlabPostReceive first because the push is already done # and we don't want to skip it if the custom hook fails. if GitlabAccess.new(repo_path, key_id, refs, protocol).exec && - GitlabCustomHook.new(key_id).pre_receive(refs, repo_path) && + GitlabCustomHook.new(repo_path, key_id).pre_receive(refs) && GitlabReferenceCounter.new(repo_path).increase exit 0 else diff --git a/hooks/update b/hooks/update index 223575d..4c2fc08 100755 --- a/hooks/update +++ b/hooks/update @@ -11,7 +11,7 @@ key_id = ENV.delete('GL_ID') require_relative '../lib/gitlab_custom_hook' -if GitlabCustomHook.new(key_id).update(ref_name, old_value, new_value, repo_path) +if GitlabCustomHook.new(repo_path, key_id).update(ref_name, old_value, new_value) exit 0 else exit 1 diff --git a/lib/gitlab_custom_hook.rb b/lib/gitlab_custom_hook.rb index e84d702..0187e1e 100644 --- a/lib/gitlab_custom_hook.rb +++ b/lib/gitlab_custom_hook.rb @@ -5,26 +5,27 @@ require_relative 'gitlab_metrics' class GitlabCustomHook attr_reader :vars - def initialize(key_id) + def initialize(repo_path, key_id) + @repo_path = repo_path @vars = { 'GL_ID' => key_id } end - def pre_receive(changes, repo_path) - hook = hook_file('pre-receive', repo_path) + def pre_receive(changes) + hook = hook_file('pre-receive', @repo_path) return true if hook.nil? GitlabMetrics.measure("pre-receive-hook") { call_receive_hook(hook, changes) } end - def post_receive(changes, repo_path) - hook = hook_file('post-receive', repo_path) + def post_receive(changes) + hook = hook_file('post-receive', @repo_path) return true if hook.nil? GitlabMetrics.measure("post-receive-hook") { call_receive_hook(hook, changes) } end - def update(ref_name, old_value, new_value, repo_path) - hook = hook_file('update', repo_path) + def update(ref_name, old_value, new_value) + hook = hook_file('update', @repo_path) return true if hook.nil? GitlabMetrics.measure("update-hook") { system(vars, hook, ref_name, old_value, new_value) } diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index f93c8b4..328b925 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -4,14 +4,14 @@ require 'pry' require 'gitlab_custom_hook' describe GitlabCustomHook do - let(:gitlab_custom_hook) { GitlabCustomHook.new('key_1') } + let(:gitlab_custom_hook) { GitlabCustomHook.new('repo_path', 'key_1') } let(:hook_path) { File.join(ROOT_PATH, 'spec/support/gl_id_test_hook') } context 'pre_receive hook' do it 'passes GL_ID variable to hook' do allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) - expect(gitlab_custom_hook.pre_receive('changes', 'repo_path')).to be_true + expect(gitlab_custom_hook.pre_receive('changes')).to be_true end end @@ -19,7 +19,7 @@ describe GitlabCustomHook do it 'passes GL_ID variable to hook' do allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) - expect(gitlab_custom_hook.post_receive('changes', 'repo_path')).to be_true + expect(gitlab_custom_hook.post_receive('changes')).to be_true end end @@ -27,7 +27,7 @@ describe GitlabCustomHook do it 'passes GL_ID variable to hook' do allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) - expect(gitlab_custom_hook.update('master', '', '', 'repo_path')).to be_true + expect(gitlab_custom_hook.update('master', '', '')).to be_true end end end -- GitLab From 0e409ee49b1d68ea949da2d0504f325439ad53b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20H=C3=B6rner?= <dirker@gmail.com> Date: Mon, 5 Sep 2016 12:06:32 +0200 Subject: [PATCH 03/21] custom_hook: add support for global custom hooks This commit adds the option of having another set of global custom hooks along with the already supported repository local custom hooks. The repository local custom hook is executed first (if available). If successful, execution continues with the global custom hook (if available). This way, local custom hooks get priority over global custom hooks. Global custom hooks can be enabled by placing an executable file into the "custom_hooks" directory within gitlab-shell (create if it does not exist, yet). --- .gitignore | 1 + hooks/post-receive | 1 + hooks/pre-receive | 1 + hooks/update | 1 + lib/gitlab_custom_hook.rb | 34 ++++++++++++++++++++++------------ 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 62e2cd1..995e19d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ coverage/ .bundle tags .bundle/ +custom_hooks diff --git a/hooks/post-receive b/hooks/post-receive index 7877306..16a6fa9 100755 --- a/hooks/post-receive +++ b/hooks/post-receive @@ -7,6 +7,7 @@ refs = $stdin.read key_id = ENV.delete('GL_ID') repo_path = Dir.pwd +require_relative '../lib/gitlab_init' require_relative '../lib/gitlab_custom_hook' require_relative '../lib/gitlab_post_receive' diff --git a/hooks/pre-receive b/hooks/pre-receive index 1b16fd0..97b9669 100755 --- a/hooks/pre-receive +++ b/hooks/pre-receive @@ -8,6 +8,7 @@ key_id = ENV.delete('GL_ID') protocol = ENV.delete('GL_PROTOCOL') repo_path = Dir.pwd +require_relative '../lib/gitlab_init' require_relative '../lib/gitlab_custom_hook' require_relative '../lib/gitlab_reference_counter' require_relative '../lib/gitlab_access' diff --git a/hooks/update b/hooks/update index 4c2fc08..e569446 100755 --- a/hooks/update +++ b/hooks/update @@ -9,6 +9,7 @@ new_value = ARGV[2] repo_path = Dir.pwd key_id = ENV.delete('GL_ID') +require_relative '../lib/gitlab_init' require_relative '../lib/gitlab_custom_hook' if GitlabCustomHook.new(repo_path, key_id).update(ref_name, old_value, new_value) diff --git a/lib/gitlab_custom_hook.rb b/lib/gitlab_custom_hook.rb index 0187e1e..f7ae6de 100644 --- a/lib/gitlab_custom_hook.rb +++ b/lib/gitlab_custom_hook.rb @@ -11,28 +11,38 @@ class GitlabCustomHook end def pre_receive(changes) - hook = hook_file('pre-receive', @repo_path) - return true if hook.nil? - - GitlabMetrics.measure("pre-receive-hook") { call_receive_hook(hook, changes) } + GitlabMetrics.measure("pre-receive-hook") do + find_hooks('pre-receive').all? do |hook| + call_receive_hook(hook, changes) + end + end end def post_receive(changes) - hook = hook_file('post-receive', @repo_path) - return true if hook.nil? - - GitlabMetrics.measure("post-receive-hook") { call_receive_hook(hook, changes) } + GitlabMetrics.measure("post-receive-hook") do + find_hooks('post-receive').all? do |hook| + call_receive_hook(hook, changes) + end + end end def update(ref_name, old_value, new_value) - hook = hook_file('update', @repo_path) - return true if hook.nil? - - GitlabMetrics.measure("update-hook") { system(vars, hook, ref_name, old_value, new_value) } + GitlabMetrics.measure("update-hook") do + find_hooks('update').all? do |hook| + system(vars, hook, ref_name, old_value, new_value) + end + end end private + def find_hooks(hook_name) + [ + hook_file(hook_name, @repo_path), + hook_file(hook_name, ROOT_PATH) + ].compact + end + def call_receive_hook(hook, changes) # Prepare the hook subprocess. Attach a pipe to its stdin, and merge # both its stdout and stderr into our own stdout. -- GitLab From c5cf54392a8853c07352a54f94a754a61259124f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20H=C3=B6rner?= <dirker@gmail.com> Date: Fri, 9 Sep 2016 13:57:21 +0200 Subject: [PATCH 04/21] spec: add tests for global custom hooks --- spec/gitlab_custom_hook_spec.rb | 174 +++++++++++++++++++++++++++++--- spec/support/hook_fail | 3 + spec/support/hook_ok | 3 + 3 files changed, 165 insertions(+), 15 deletions(-) create mode 100755 spec/support/hook_fail create mode 100755 spec/support/hook_ok diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index 328b925..a456709 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -1,33 +1,177 @@ # coding: utf-8 require 'spec_helper' -require 'pry' require 'gitlab_custom_hook' describe GitlabCustomHook do - let(:gitlab_custom_hook) { GitlabCustomHook.new('repo_path', 'key_1') } - let(:hook_path) { File.join(ROOT_PATH, 'spec/support/gl_id_test_hook') } + let(:tmp_repo_path) { File.join(ROOT_PATH, 'tmp', 'repo.git') } + let(:tmp_root_path) { File.join(ROOT_PATH, 'tmp') } + let(:hook_ok) { File.join(ROOT_PATH, 'spec', 'support', 'hook_ok') } + let(:hook_fail) { File.join(ROOT_PATH, 'spec', 'support', 'hook_fail') } - context 'pre_receive hook' do - it 'passes GL_ID variable to hook' do - allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) + let(:vars) { {"GL_ID" => "key_1"} } + let(:old_value) { "old-value" } + let(:new_value) { "new-value" } + let(:ref_name) { "name/of/ref" } + let(:changes) { "#{old_value} #{new_value} #{ref_name}\n" } - expect(gitlab_custom_hook.pre_receive('changes')).to be_true + let(:gitlab_custom_hook) { GitlabCustomHook.new(tmp_repo_path, 'key_1') } + + before do + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks')) + FileUtils.mkdir_p(File.join(tmp_root_path, 'custom_hooks')) + end + + after do + FileUtils.rm_rf(File.join(tmp_repo_path, 'custom_hooks')) + FileUtils.rm_rf(File.join(tmp_root_path, 'custom_hooks')) + end + + context 'with gl_id_test_hook' do + let(:hook_path) { File.join(ROOT_PATH, 'spec/support/gl_id_test_hook') } + + context 'pre_receive hook' do + it 'passes GL_ID variable to hook' do + allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) + + expect(gitlab_custom_hook.pre_receive(changes)).to be_true + end + end + + context 'post_receive hook' do + it 'passes GL_ID variable to hook' do + allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) + + expect(gitlab_custom_hook.post_receive(changes)).to be_true + end + end + + context 'update hook' do + it 'passes GL_ID variable to hook' do + allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) + + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to be_true + end + end + end + + context "having no hooks" do + it "returns true" do + stub_const("ROOT_PATH", tmp_root_path) + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) + end + end + + context "having only ok repo hooks" do + before do + create_hooks(tmp_repo_path, hook_ok) + end + + it "returns true" do + stub_const("ROOT_PATH", tmp_root_path) + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) + end + end + + context "having both ok repo and global hooks" do + before do + create_hooks(tmp_repo_path, hook_ok) + create_hooks(tmp_root_path, hook_ok) + end + + it "returns true" do + stub_const("ROOT_PATH", tmp_root_path) + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) end end - context 'post_receive hook' do - it 'passes GL_ID variable to hook' do - allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) + context "having failing repo and ok global hooks" do + before do + create_hooks(tmp_repo_path, hook_fail) + create_hooks(tmp_root_path, hook_ok) + end + + it "returns false" do + stub_const("ROOT_PATH", tmp_root_path) + expect(gitlab_custom_hook.pre_receive(changes)).to eq(false) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(false) + expect(gitlab_custom_hook.post_receive(changes)).to eq(false) + end + + it "only executes the repo hook" do + expect(gitlab_custom_hook).to receive(:call_receive_hook) + .with(hook_path(tmp_repo_path, "pre-receive"), changes) + .and_call_original + expect(gitlab_custom_hook).to receive(:system) + .with(vars, hook_path(tmp_repo_path, "update"), ref_name, old_value, new_value) + .and_call_original + expect(gitlab_custom_hook).to receive(:call_receive_hook) + .with(hook_path(tmp_repo_path, "post-receive"), changes) + .and_call_original - expect(gitlab_custom_hook.post_receive('changes')).to be_true + stub_const("ROOT_PATH", tmp_root_path) + gitlab_custom_hook.pre_receive(changes) + gitlab_custom_hook.update(ref_name, old_value, new_value) + gitlab_custom_hook.post_receive(changes) end end - context 'update hook' do - it 'passes GL_ID variable to hook' do - allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) + context "having ok repo but failing global hooks" do + before do + create_hooks(tmp_repo_path, hook_ok) + create_hooks(tmp_root_path, hook_fail) + end - expect(gitlab_custom_hook.update('master', '', '')).to be_true + it "returns false" do + stub_const("ROOT_PATH", tmp_root_path) + expect(gitlab_custom_hook.pre_receive(changes)).to eq(false) + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(false) + expect(gitlab_custom_hook.post_receive(changes)).to eq(false) end + + it "executes the relevant hooks" do + expect(gitlab_custom_hook).to receive(:call_receive_hook) + .with(hook_path(tmp_repo_path, "pre-receive"), changes) + .and_call_original + expect(gitlab_custom_hook).to receive(:call_receive_hook) + .with(hook_path(tmp_root_path, "pre-receive"), changes) + .and_call_original + expect(gitlab_custom_hook).to receive(:system) + .with(vars, hook_path(tmp_repo_path, "update"), ref_name, old_value, new_value) + .and_call_original + expect(gitlab_custom_hook).to receive(:system) + .with(vars, hook_path(tmp_root_path, "update"), ref_name, old_value, new_value) + .and_call_original + expect(gitlab_custom_hook).to receive(:call_receive_hook) + .with(hook_path(tmp_repo_path, "post-receive"), changes) + .and_call_original + expect(gitlab_custom_hook).to receive(:call_receive_hook) + .with(hook_path(tmp_root_path, "post-receive"), changes) + .and_call_original + + stub_const("ROOT_PATH", tmp_root_path) + gitlab_custom_hook.pre_receive(changes) + gitlab_custom_hook.update(ref_name, old_value, new_value) + gitlab_custom_hook.post_receive(changes) + end + end + + def hook_path(path, name) + File.join(path, 'custom_hooks', name) + end + + def create_hook(path, name, which) + FileUtils.ln_sf(which, hook_path(path, name)) + end + + def create_hooks(path, which) + create_hook(path, 'pre-receive', which) + create_hook(path, 'update', which) + create_hook(path, 'post-receive', which) end end diff --git a/spec/support/hook_fail b/spec/support/hook_fail new file mode 100755 index 0000000..4420796 --- /dev/null +++ b/spec/support/hook_fail @@ -0,0 +1,3 @@ +#!/bin/bash +#echo "fail: $0" +exit 1 diff --git a/spec/support/hook_ok b/spec/support/hook_ok new file mode 100755 index 0000000..eb1e3bc --- /dev/null +++ b/spec/support/hook_ok @@ -0,0 +1,3 @@ +#!/bin/bash +#echo "ok: $0" +exit 0 -- GitLab From dbd4bc264baf611b91c03d799f77376963633551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 26 Oct 2016 21:13:01 +0300 Subject: [PATCH 05/21] custom_hook: chain custom hooks update hooks lookup to use <hook>.d/* from repository hooks dir the order would be: 1. <repository>.git/custom_hooks/<hook_name> - per project hook 2. <repository>.git/custom_hooks/<hook_name>.d/* - per project hooks 3. <repository>.git/hooks/<hook_name>.d/* - global hooks only executable files are matched and backup files excluded (*~) and the resulting list is sorted per each lookup --- lib/gitlab_custom_hook.rb | 48 ++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/lib/gitlab_custom_hook.rb b/lib/gitlab_custom_hook.rb index f7ae6de..451d5b4 100644 --- a/lib/gitlab_custom_hook.rb +++ b/lib/gitlab_custom_hook.rb @@ -36,13 +36,6 @@ class GitlabCustomHook private - def find_hooks(hook_name) - [ - hook_file(hook_name, @repo_path), - hook_file(hook_name, ROOT_PATH) - ].compact - end - def call_receive_hook(hook, changes) # Prepare the hook subprocess. Attach a pipe to its stdin, and merge # both its stdout and stderr into our own stdout. @@ -64,9 +57,42 @@ class GitlabCustomHook $?.success? 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.executable?(hook_file) + # lookup hook files in this order: + # + # 1. <repository>.git/custom_hooks/<hook_name> - per project hook + # 2. <repository>.git/custom_hooks/<hook_name>.d/* - per project hooks + # 3. <repository>.git/hooks/<hook_name>.d/* - global hooks + # + def find_hooks(hook_name) + hook_files = [] + + # <repository>.git/custom_hooks/<hook_name> + hook_file = File.join(@repo_path, 'custom_hooks', hook_name) + hook_files.push(hook_file) if File.executable?(hook_file) + + # <repository>.git/custom_hooks/<hook_name>.d/* + hook_path = File.join(@repo_path, 'custom_hooks', "#{hook_name}.d") + if Dir.exist?(hook_path) + hook_files += match_hook_files(hook_path) + end + + # <repository>.git/hooks/<hook_name>.d/* + hook_path = File.join(@repo_path, 'hooks', "#{hook_name}.d") + if Dir.exist?(hook_path) + hook_files += match_hook_files(hook_path) + end + + hook_files + end + + # match files from path: + # 1. file must be executable + # 2. file must not match backup file + # + # the resulting list is sorted + def match_hook_files(path) + Dir["#{path}/*"].select do |f| + !f[/~$/] && File.executable?(f) + end.sort end end -- GitLab From e60a0ee7bb00962a5e1ee3b49c6686f86dd3ea60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 9 Nov 2016 22:22:16 +0200 Subject: [PATCH 06/21] spec: updated tests to match current code --- Gemfile.lock | 3 - spec/gitlab_custom_hook_spec.rb | 101 +++++++++++++++++++++----------- 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 0fbade8..9bf7d9f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -81,6 +81,3 @@ DEPENDENCIES rubocop (= 0.28.0) vcr webmock - -BUNDLED WITH - 1.11.2 diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index a456709..701218c 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -16,14 +16,34 @@ describe GitlabCustomHook do let(:gitlab_custom_hook) { GitlabCustomHook.new(tmp_repo_path, 'key_1') } + # setup paths + # <repository>.git/hooks/ - symlink to gitlab-shell/hooks global dir + # <repository>.git/hooks/<hook_name> - executed by git itself, this is gitlab-shell/hooks/<hook_name> + # <repository>.git/hooks/<hook_name>.d/* - global hooks: all executable files (minus editor backup files) + # <repository>.git/custom_hooks/<hook_name> - per project hook (this is already existing behavior) + # <repository>.git/custom_hooks/<hook_name>.d/* - per project hooks + # + # custom hooks are invoked in such way that first failure prevents other scripts being ran + # as global scripts are ran first, failing global skips repo hooks + before do + FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks')) + FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'update.d')) + FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'pre-receive.d')) + FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'post-receive.d')) + + FileUtils.symlink(File.join(tmp_root_path, 'hooks'), File.join(tmp_repo_path, 'hooks')) FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks')) - FileUtils.mkdir_p(File.join(tmp_root_path, 'custom_hooks')) + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'update.d')) + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'pre-receive.d')) + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'post-receive.d')) end after do FileUtils.rm_rf(File.join(tmp_repo_path, 'custom_hooks')) - FileUtils.rm_rf(File.join(tmp_root_path, 'custom_hooks')) + FileUtils.rm_rf(File.join(tmp_repo_path, 'hooks')) + FileUtils.rm_rf(File.join(tmp_repo_path, 'hooks.d')) + FileUtils.rm_rf(File.join(tmp_root_path, 'hooks')) end context 'with gl_id_test_hook' do @@ -56,7 +76,6 @@ describe GitlabCustomHook do context "having no hooks" do it "returns true" do - stub_const("ROOT_PATH", tmp_root_path) expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) expect(gitlab_custom_hook.post_receive(changes)).to eq(true) @@ -65,11 +84,10 @@ describe GitlabCustomHook do context "having only ok repo hooks" do before do - create_hooks(tmp_repo_path, hook_ok) + create_repo_hooks(tmp_repo_path, hook_ok) end it "returns true" do - stub_const("ROOT_PATH", tmp_root_path) expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) expect(gitlab_custom_hook.post_receive(changes)).to eq(true) @@ -78,12 +96,11 @@ describe GitlabCustomHook do context "having both ok repo and global hooks" do before do - create_hooks(tmp_repo_path, hook_ok) - create_hooks(tmp_root_path, hook_ok) + create_repo_hooks(tmp_repo_path, hook_ok) + create_global_hooks_d(tmp_root_path, hook_ok) end it "returns true" do - stub_const("ROOT_PATH", tmp_root_path) expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) expect(gitlab_custom_hook.post_receive(changes)).to eq(true) @@ -92,29 +109,27 @@ describe GitlabCustomHook do context "having failing repo and ok global hooks" do before do - create_hooks(tmp_repo_path, hook_fail) - create_hooks(tmp_root_path, hook_ok) + create_repo_hooks_d(tmp_repo_path, hook_fail) + create_global_hooks_d(tmp_repo_path, hook_ok) end it "returns false" do - stub_const("ROOT_PATH", tmp_root_path) expect(gitlab_custom_hook.pre_receive(changes)).to eq(false) expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(false) expect(gitlab_custom_hook.post_receive(changes)).to eq(false) end - it "only executes the repo hook" do + it "only executes the global hook" do expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "pre-receive"), changes) + .with(hook_path(tmp_repo_path, "custom_hooks/pre-receive.d/hook"), changes) .and_call_original expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path(tmp_repo_path, "update"), ref_name, old_value, new_value) + .with(vars, hook_path(tmp_repo_path, "custom_hooks/update.d/hook"), ref_name, old_value, new_value) .and_call_original expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "post-receive"), changes) + .with(hook_path(tmp_repo_path, "custom_hooks/post-receive.d/hook"), changes) .and_call_original - stub_const("ROOT_PATH", tmp_root_path) gitlab_custom_hook.pre_receive(changes) gitlab_custom_hook.update(ref_name, old_value, new_value) gitlab_custom_hook.post_receive(changes) @@ -123,12 +138,11 @@ describe GitlabCustomHook do context "having ok repo but failing global hooks" do before do - create_hooks(tmp_repo_path, hook_ok) - create_hooks(tmp_root_path, hook_fail) + create_repo_hooks_d(tmp_repo_path, hook_ok) + create_global_hooks_d(tmp_repo_path, hook_fail) end it "returns false" do - stub_const("ROOT_PATH", tmp_root_path) expect(gitlab_custom_hook.pre_receive(changes)).to eq(false) expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(false) expect(gitlab_custom_hook.post_receive(changes)).to eq(false) @@ -136,42 +150,61 @@ describe GitlabCustomHook do it "executes the relevant hooks" do expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "pre-receive"), changes) + .with(hook_path(tmp_repo_path, "hooks/pre-receive.d/hook"), changes) .and_call_original expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_root_path, "pre-receive"), changes) + .with(hook_path(tmp_repo_path, "custom_hooks/pre-receive.d/hook"), changes) .and_call_original expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path(tmp_repo_path, "update"), ref_name, old_value, new_value) + .with(vars, hook_path(tmp_repo_path, "hooks/update.d/hook"), ref_name, old_value, new_value) .and_call_original expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path(tmp_root_path, "update"), ref_name, old_value, new_value) + .with(vars, hook_path(tmp_repo_path, "custom_hooks/update.d/hook"), ref_name, old_value, new_value) .and_call_original expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "post-receive"), changes) + .with(hook_path(tmp_repo_path, "hooks/post-receive.d/hook"), changes) .and_call_original expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_root_path, "post-receive"), changes) + .with(hook_path(tmp_repo_path, "custom_hooks/post-receive.d/hook"), changes) .and_call_original - stub_const("ROOT_PATH", tmp_root_path) gitlab_custom_hook.pre_receive(changes) gitlab_custom_hook.update(ref_name, old_value, new_value) gitlab_custom_hook.post_receive(changes) end end - def hook_path(path, name) - File.join(path, 'custom_hooks', name) + def hook_path(repo_path, path) + File.join(repo_path, path.split('/')) + end + + def create_hook(repo_path, path, which) + FileUtils.ln_sf(which, hook_path(repo_path, path)) + end + + def create_global_hooks(path, which) + # should not be tested, as the "global hooks" is gitlab-shell itself (gitlab-shell/hooks/<hook_name>) + raise "no method, this is gitlab-shell itself" + end + + # global hooks multiplexed + def create_global_hooks_d(path, which) + create_hook(path, 'hooks/pre-receive.d/hook', which) + create_hook(path, 'hooks/update.d/hook', which) + create_hook(path, 'hooks/post-receive.d/hook', which) end - def create_hook(path, name, which) - FileUtils.ln_sf(which, hook_path(path, name)) + # repo hooks + def create_repo_hooks(path, which) + create_hook(path, 'custom_hooks/pre-receive', which) + create_hook(path, 'custom_hooks/update', which) + create_hook(path, 'custom_hooks/post-receive', which) end - def create_hooks(path, which) - create_hook(path, 'pre-receive', which) - create_hook(path, 'update', which) - create_hook(path, 'post-receive', which) + # repo hooks multiplexed + def create_repo_hooks_d(path, which) + create_hook(path, 'custom_hooks/pre-receive.d/hook', which) + create_hook(path, 'custom_hooks/update.d/hook', which) + create_hook(path, 'custom_hooks/post-receive.d/hook', which) end end -- GitLab From 5b740fcf2978decca31a459184b16531d7517e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 16 Nov 2016 02:05:25 +0200 Subject: [PATCH 07/21] remove no longer needed gitlab_init --- hooks/post-receive | 1 - hooks/pre-receive | 1 - hooks/update | 1 - 3 files changed, 3 deletions(-) diff --git a/hooks/post-receive b/hooks/post-receive index 16a6fa9..7877306 100755 --- a/hooks/post-receive +++ b/hooks/post-receive @@ -7,7 +7,6 @@ refs = $stdin.read key_id = ENV.delete('GL_ID') repo_path = Dir.pwd -require_relative '../lib/gitlab_init' require_relative '../lib/gitlab_custom_hook' require_relative '../lib/gitlab_post_receive' diff --git a/hooks/pre-receive b/hooks/pre-receive index 97b9669..1b16fd0 100755 --- a/hooks/pre-receive +++ b/hooks/pre-receive @@ -8,7 +8,6 @@ key_id = ENV.delete('GL_ID') protocol = ENV.delete('GL_PROTOCOL') repo_path = Dir.pwd -require_relative '../lib/gitlab_init' require_relative '../lib/gitlab_custom_hook' require_relative '../lib/gitlab_reference_counter' require_relative '../lib/gitlab_access' diff --git a/hooks/update b/hooks/update index e569446..4c2fc08 100755 --- a/hooks/update +++ b/hooks/update @@ -9,7 +9,6 @@ new_value = ARGV[2] repo_path = Dir.pwd key_id = ENV.delete('GL_ID') -require_relative '../lib/gitlab_init' require_relative '../lib/gitlab_custom_hook' if GitlabCustomHook.new(repo_path, key_id).update(ref_name, old_value, new_value) -- GitLab From d87c4b9c0d3aed4a23d74f340ece2c4bff83101b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 16 Nov 2016 02:08:50 +0200 Subject: [PATCH 08/21] use String.end_with? instead of regexp --- lib/gitlab_custom_hook.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab_custom_hook.rb b/lib/gitlab_custom_hook.rb index 451d5b4..6265ec1 100644 --- a/lib/gitlab_custom_hook.rb +++ b/lib/gitlab_custom_hook.rb @@ -92,7 +92,7 @@ class GitlabCustomHook # the resulting list is sorted def match_hook_files(path) Dir["#{path}/*"].select do |f| - !f[/~$/] && File.executable?(f) + !f.end_with?('~') && File.executable?(f) end.sort end end -- GitLab From 872c66e977b3041e0c18543d2e00a255e8e89e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 16 Nov 2016 02:12:07 +0200 Subject: [PATCH 09/21] avoid Dir.exists? duplication by moving the check to match_hook_files --- lib/gitlab_custom_hook.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/gitlab_custom_hook.rb b/lib/gitlab_custom_hook.rb index 6265ec1..a48ad12 100644 --- a/lib/gitlab_custom_hook.rb +++ b/lib/gitlab_custom_hook.rb @@ -72,15 +72,11 @@ class GitlabCustomHook # <repository>.git/custom_hooks/<hook_name>.d/* hook_path = File.join(@repo_path, 'custom_hooks', "#{hook_name}.d") - if Dir.exist?(hook_path) - hook_files += match_hook_files(hook_path) - end + hook_files += match_hook_files(hook_path) # <repository>.git/hooks/<hook_name>.d/* hook_path = File.join(@repo_path, 'hooks', "#{hook_name}.d") - if Dir.exist?(hook_path) - hook_files += match_hook_files(hook_path) - end + hook_files += match_hook_files(hook_path) hook_files end @@ -91,6 +87,8 @@ class GitlabCustomHook # # the resulting list is sorted def match_hook_files(path) + return [] unless Dir.exist?(path) + Dir["#{path}/*"].select do |f| !f.end_with?('~') && File.executable?(f) end.sort -- GitLab From f8e64aa2baa7fa30be43ab6759233d4082be9f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 16 Nov 2016 02:13:10 +0200 Subject: [PATCH 10/21] remove unused create_global_hooks --- spec/gitlab_custom_hook_spec.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index 701218c..d91690f 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -182,11 +182,6 @@ describe GitlabCustomHook do FileUtils.ln_sf(which, hook_path(repo_path, path)) end - def create_global_hooks(path, which) - # should not be tested, as the "global hooks" is gitlab-shell itself (gitlab-shell/hooks/<hook_name>) - raise "no method, this is gitlab-shell itself" - end - # global hooks multiplexed def create_global_hooks_d(path, which) create_hook(path, 'hooks/pre-receive.d/hook', which) -- GitLab From 23b90272acc4bcd0c12e4127c0697ede620e503a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 16 Nov 2016 02:14:28 +0200 Subject: [PATCH 11/21] improve wording by using successful instead of ok --- spec/gitlab_custom_hook_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index d91690f..0718f16 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -82,7 +82,7 @@ describe GitlabCustomHook do end end - context "having only ok repo hooks" do + context "having only successful repo hooks" do before do create_repo_hooks(tmp_repo_path, hook_ok) end @@ -94,7 +94,7 @@ describe GitlabCustomHook do end end - context "having both ok repo and global hooks" do + context "having both successful repo and global hooks" do before do create_repo_hooks(tmp_repo_path, hook_ok) create_global_hooks_d(tmp_root_path, hook_ok) @@ -107,7 +107,7 @@ describe GitlabCustomHook do end end - context "having failing repo and ok global hooks" do + context "having failing repo and successful global hooks" do before do create_repo_hooks_d(tmp_repo_path, hook_fail) create_global_hooks_d(tmp_repo_path, hook_ok) @@ -136,7 +136,7 @@ describe GitlabCustomHook do end end - context "having ok repo but failing global hooks" do + context "having successful repo but failing global hooks" do before do create_repo_hooks_d(tmp_repo_path, hook_ok) create_global_hooks_d(tmp_repo_path, hook_fail) -- GitLab From 91ba63969a418583454b54879afb0f335e9e06c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 16 Nov 2016 21:04:34 +0200 Subject: [PATCH 12/21] changelog entry --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index e520a99..7cb6b19 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ +v4.1.0 + - Add support for global custom hooks and chanined hooks (Elan Ruusamäe, Dirk Hörner), !93, !89, #32 + v4.0.3 - Fetch repositories with `--prune` option by default + v4.0.2 - Fix gitlab_custom_hook dependencies -- GitLab From 17691041ae723145f78a081a16809d0afb8136f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 16 Nov 2016 23:12:55 +0200 Subject: [PATCH 13/21] move helpers to top --- spec/gitlab_custom_hook_spec.rb | 58 ++++++++++++++++----------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index 0718f16..69809b9 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -16,6 +16,35 @@ describe GitlabCustomHook do let(:gitlab_custom_hook) { GitlabCustomHook.new(tmp_repo_path, 'key_1') } + def hook_path(repo_path, path) + File.join(repo_path, path.split('/')) + end + + def create_hook(repo_path, path, which) + FileUtils.ln_sf(which, hook_path(repo_path, path)) + end + + # global hooks multiplexed + def create_global_hooks_d(path, which) + create_hook(path, 'hooks/pre-receive.d/hook', which) + create_hook(path, 'hooks/update.d/hook', which) + create_hook(path, 'hooks/post-receive.d/hook', which) + end + + # repo hooks + def create_repo_hooks(path, which) + create_hook(path, 'custom_hooks/pre-receive', which) + create_hook(path, 'custom_hooks/update', which) + create_hook(path, 'custom_hooks/post-receive', which) + end + + # repo hooks multiplexed + def create_repo_hooks_d(path, which) + create_hook(path, 'custom_hooks/pre-receive.d/hook', which) + create_hook(path, 'custom_hooks/update.d/hook', which) + create_hook(path, 'custom_hooks/post-receive.d/hook', which) + end + # setup paths # <repository>.git/hooks/ - symlink to gitlab-shell/hooks global dir # <repository>.git/hooks/<hook_name> - executed by git itself, this is gitlab-shell/hooks/<hook_name> @@ -173,33 +202,4 @@ describe GitlabCustomHook do gitlab_custom_hook.post_receive(changes) end end - - def hook_path(repo_path, path) - File.join(repo_path, path.split('/')) - end - - def create_hook(repo_path, path, which) - FileUtils.ln_sf(which, hook_path(repo_path, path)) - end - - # global hooks multiplexed - def create_global_hooks_d(path, which) - create_hook(path, 'hooks/pre-receive.d/hook', which) - create_hook(path, 'hooks/update.d/hook', which) - create_hook(path, 'hooks/post-receive.d/hook', which) - end - - # repo hooks - def create_repo_hooks(path, which) - create_hook(path, 'custom_hooks/pre-receive', which) - create_hook(path, 'custom_hooks/update', which) - create_hook(path, 'custom_hooks/post-receive', which) - end - - # repo hooks multiplexed - def create_repo_hooks_d(path, which) - create_hook(path, 'custom_hooks/pre-receive.d/hook', which) - create_hook(path, 'custom_hooks/update.d/hook', which) - create_hook(path, 'custom_hooks/post-receive.d/hook', which) - end end -- GitLab From 5043d13bac184ed1092a67afb33a1b108c5e03d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Wed, 16 Nov 2016 23:15:19 +0200 Subject: [PATCH 14/21] cleanup dirs in before to fixup aborted tests --- spec/gitlab_custom_hook_spec.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index 69809b9..f6b16bb 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -45,6 +45,13 @@ describe GitlabCustomHook do create_hook(path, 'custom_hooks/post-receive.d/hook', which) end + def cleanup_hook_setup + FileUtils.rm_rf(File.join(tmp_repo_path, 'custom_hooks')) + FileUtils.rm_rf(File.join(tmp_repo_path, 'hooks')) + FileUtils.rm_rf(File.join(tmp_repo_path, 'hooks.d')) + FileUtils.rm_rf(File.join(tmp_root_path, 'hooks')) + end + # setup paths # <repository>.git/hooks/ - symlink to gitlab-shell/hooks global dir # <repository>.git/hooks/<hook_name> - executed by git itself, this is gitlab-shell/hooks/<hook_name> @@ -56,6 +63,8 @@ describe GitlabCustomHook do # as global scripts are ran first, failing global skips repo hooks before do + cleanup_hook_setup + FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks')) FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'update.d')) FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'pre-receive.d')) @@ -69,10 +78,7 @@ describe GitlabCustomHook do end after do - FileUtils.rm_rf(File.join(tmp_repo_path, 'custom_hooks')) - FileUtils.rm_rf(File.join(tmp_repo_path, 'hooks')) - FileUtils.rm_rf(File.join(tmp_repo_path, 'hooks.d')) - FileUtils.rm_rf(File.join(tmp_root_path, 'hooks')) + cleanup_hook_setup end context 'with gl_id_test_hook' do -- GitLab From 8910d4b069cea1c5d1fa25f192ca20afc062ed9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Sun, 20 Nov 2016 15:43:00 +0200 Subject: [PATCH 15/21] fix gl_id_test_hook --- spec/gitlab_custom_hook_spec.rb | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index f6b16bb..e47fae0 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -7,6 +7,7 @@ describe GitlabCustomHook do let(:tmp_root_path) { File.join(ROOT_PATH, 'tmp') } let(:hook_ok) { File.join(ROOT_PATH, 'spec', 'support', 'hook_ok') } let(:hook_fail) { File.join(ROOT_PATH, 'spec', 'support', 'hook_fail') } + let(:hook_gl_id) { File.join(ROOT_PATH, 'spec', 'support', 'gl_id_test_hook') } let(:vars) { {"GL_ID" => "key_1"} } let(:old_value) { "old-value" } @@ -82,29 +83,26 @@ describe GitlabCustomHook do end context 'with gl_id_test_hook' do - let(:hook_path) { File.join(ROOT_PATH, 'spec/support/gl_id_test_hook') } + before do + create_repo_hooks(tmp_repo_path, hook_gl_id) + create_global_hooks_d(tmp_root_path, hook_gl_id) + end context 'pre_receive hook' do it 'passes GL_ID variable to hook' do - allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) - - expect(gitlab_custom_hook.pre_receive(changes)).to be_true + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) end end context 'post_receive hook' do it 'passes GL_ID variable to hook' do - allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) - - expect(gitlab_custom_hook.post_receive(changes)).to be_true + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) end end context 'update hook' do it 'passes GL_ID variable to hook' do - allow(gitlab_custom_hook).to receive(:hook_file).and_return(hook_path) - - expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to be_true + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) end end end -- GitLab From a04895942167e65dcc39bf2d9b6557b28f1e5573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Sun, 20 Nov 2016 15:53:01 +0200 Subject: [PATCH 16/21] spec/custom_hooks: cleanup helpers not to repeat repo path parameter --- spec/gitlab_custom_hook_spec.rb | 68 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index e47fae0..05ec38b 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -17,33 +17,33 @@ describe GitlabCustomHook do let(:gitlab_custom_hook) { GitlabCustomHook.new(tmp_repo_path, 'key_1') } - def hook_path(repo_path, path) - File.join(repo_path, path.split('/')) + def hook_path(path) + File.join(tmp_repo_path, path.split('/')) end - def create_hook(repo_path, path, which) - FileUtils.ln_sf(which, hook_path(repo_path, path)) + def create_hook(path, which) + FileUtils.ln_sf(which, hook_path(path)) end # global hooks multiplexed - def create_global_hooks_d(path, which) - create_hook(path, 'hooks/pre-receive.d/hook', which) - create_hook(path, 'hooks/update.d/hook', which) - create_hook(path, 'hooks/post-receive.d/hook', which) + def create_global_hooks_d(which) + create_hook('hooks/pre-receive.d/hook', which) + create_hook('hooks/update.d/hook', which) + create_hook('hooks/post-receive.d/hook', which) end # repo hooks - def create_repo_hooks(path, which) - create_hook(path, 'custom_hooks/pre-receive', which) - create_hook(path, 'custom_hooks/update', which) - create_hook(path, 'custom_hooks/post-receive', which) + def create_repo_hooks(which) + create_hook('custom_hooks/pre-receive', which) + create_hook('custom_hooks/update', which) + create_hook('custom_hooks/post-receive', which) end # repo hooks multiplexed - def create_repo_hooks_d(path, which) - create_hook(path, 'custom_hooks/pre-receive.d/hook', which) - create_hook(path, 'custom_hooks/update.d/hook', which) - create_hook(path, 'custom_hooks/post-receive.d/hook', which) + def create_repo_hooks_d(which) + create_hook('custom_hooks/pre-receive.d/hook', which) + create_hook('custom_hooks/update.d/hook', which) + create_hook('custom_hooks/post-receive.d/hook', which) end def cleanup_hook_setup @@ -84,8 +84,8 @@ describe GitlabCustomHook do context 'with gl_id_test_hook' do before do - create_repo_hooks(tmp_repo_path, hook_gl_id) - create_global_hooks_d(tmp_root_path, hook_gl_id) + create_repo_hooks(hook_gl_id) + create_global_hooks_d(hook_gl_id) end context 'pre_receive hook' do @@ -117,7 +117,7 @@ describe GitlabCustomHook do context "having only successful repo hooks" do before do - create_repo_hooks(tmp_repo_path, hook_ok) + create_repo_hooks(hook_ok) end it "returns true" do @@ -129,8 +129,8 @@ describe GitlabCustomHook do context "having both successful repo and global hooks" do before do - create_repo_hooks(tmp_repo_path, hook_ok) - create_global_hooks_d(tmp_root_path, hook_ok) + create_repo_hooks(hook_ok) + create_global_hooks_d(hook_ok) end it "returns true" do @@ -142,8 +142,8 @@ describe GitlabCustomHook do context "having failing repo and successful global hooks" do before do - create_repo_hooks_d(tmp_repo_path, hook_fail) - create_global_hooks_d(tmp_repo_path, hook_ok) + create_repo_hooks_d(hook_fail) + create_global_hooks_d(hook_ok) end it "returns false" do @@ -154,13 +154,13 @@ describe GitlabCustomHook do it "only executes the global hook" do expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "custom_hooks/pre-receive.d/hook"), changes) + .with(hook_path("custom_hooks/pre-receive.d/hook"), changes) .and_call_original expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path(tmp_repo_path, "custom_hooks/update.d/hook"), ref_name, old_value, new_value) + .with(vars, hook_path("custom_hooks/update.d/hook"), ref_name, old_value, new_value) .and_call_original expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "custom_hooks/post-receive.d/hook"), changes) + .with(hook_path("custom_hooks/post-receive.d/hook"), changes) .and_call_original gitlab_custom_hook.pre_receive(changes) @@ -171,8 +171,8 @@ describe GitlabCustomHook do context "having successful repo but failing global hooks" do before do - create_repo_hooks_d(tmp_repo_path, hook_ok) - create_global_hooks_d(tmp_repo_path, hook_fail) + create_repo_hooks_d(hook_ok) + create_global_hooks_d(hook_fail) end it "returns false" do @@ -183,22 +183,22 @@ describe GitlabCustomHook do it "executes the relevant hooks" do expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "hooks/pre-receive.d/hook"), changes) + .with(hook_path("hooks/pre-receive.d/hook"), changes) .and_call_original expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "custom_hooks/pre-receive.d/hook"), changes) + .with(hook_path("custom_hooks/pre-receive.d/hook"), changes) .and_call_original expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path(tmp_repo_path, "hooks/update.d/hook"), ref_name, old_value, new_value) + .with(vars, hook_path("hooks/update.d/hook"), ref_name, old_value, new_value) .and_call_original expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path(tmp_repo_path, "custom_hooks/update.d/hook"), ref_name, old_value, new_value) + .with(vars, hook_path("custom_hooks/update.d/hook"), ref_name, old_value, new_value) .and_call_original expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "hooks/post-receive.d/hook"), changes) + .with(hook_path("hooks/post-receive.d/hook"), changes) .and_call_original expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path(tmp_repo_path, "custom_hooks/post-receive.d/hook"), changes) + .with(hook_path("custom_hooks/post-receive.d/hook"), changes) .and_call_original gitlab_custom_hook.pre_receive(changes) -- GitLab From 24d6df6c882c4224d66271f81cc04c5a9ba3b3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Sun, 20 Nov 2016 16:30:45 +0200 Subject: [PATCH 17/21] spec/custom_hook: ensure "before" does complete cleanup this fixes problem that tests succeeded locally but failed in ci where parent dirs were missing --- spec/gitlab_custom_hook_spec.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index 05ec38b..faa4f2b 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -47,9 +47,7 @@ describe GitlabCustomHook do end def cleanup_hook_setup - FileUtils.rm_rf(File.join(tmp_repo_path, 'custom_hooks')) - FileUtils.rm_rf(File.join(tmp_repo_path, 'hooks')) - FileUtils.rm_rf(File.join(tmp_repo_path, 'hooks.d')) + FileUtils.rm_rf(File.join(tmp_repo_path)) FileUtils.rm_rf(File.join(tmp_root_path, 'hooks')) end @@ -66,16 +64,17 @@ describe GitlabCustomHook do before do cleanup_hook_setup + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks')) + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'update.d')) + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'pre-receive.d')) + FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'post-receive.d')) + FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks')) FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'update.d')) FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'pre-receive.d')) FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', 'post-receive.d')) FileUtils.symlink(File.join(tmp_root_path, 'hooks'), File.join(tmp_repo_path, 'hooks')) - FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks')) - FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'update.d')) - FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'pre-receive.d')) - FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', 'post-receive.d')) end after do -- GitLab From 37148a6c56ab252728cba9c11c5f25ed889211f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Fri, 25 Nov 2016 20:27:33 +0200 Subject: [PATCH 18/21] test gl_id_test_hook as global and as repo hook separately --- spec/gitlab_custom_hook_spec.rb | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index faa4f2b..5cc9e0b 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -81,9 +81,32 @@ describe GitlabCustomHook do cleanup_hook_setup end - context 'with gl_id_test_hook' do + context 'with gl_id_test_hook as repo hook' do before do create_repo_hooks(hook_gl_id) + end + + context 'pre_receive hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) + end + end + + context 'post_receive hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.post_receive(changes)).to eq(true) + end + end + + context 'update hook' do + it 'passes GL_ID variable to hook' do + expect(gitlab_custom_hook.update(ref_name, old_value, new_value)).to eq(true) + end + end + end + + context 'with gl_id_test_hook as global hook' do + before do create_global_hooks_d(hook_gl_id) end -- GitLab From f3512031fefe7a566d4a8a911cc024fb6bc1c99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Fri, 25 Nov 2016 20:56:24 +0200 Subject: [PATCH 19/21] DRY: add helpers for expect hook calls --- spec/gitlab_custom_hook_spec.rb | 66 ++++++++++++++++----------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index 5cc9e0b..cbf2d03 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -26,10 +26,10 @@ describe GitlabCustomHook do end # global hooks multiplexed - def create_global_hooks_d(which) - create_hook('hooks/pre-receive.d/hook', which) - create_hook('hooks/update.d/hook', which) - create_hook('hooks/post-receive.d/hook', which) + def create_global_hooks_d(which, hook_name = 'hook') + create_hook('hooks/pre-receive.d/' + hook_name, which) + create_hook('hooks/update.d/' + hook_name, which) + create_hook('hooks/post-receive.d/' + hook_name, which) end # repo hooks @@ -40,10 +40,10 @@ describe GitlabCustomHook do end # repo hooks multiplexed - def create_repo_hooks_d(which) - create_hook('custom_hooks/pre-receive.d/hook', which) - create_hook('custom_hooks/update.d/hook', which) - create_hook('custom_hooks/post-receive.d/hook', which) + def create_repo_hooks_d(which, hook_name = 'hook') + create_hook('custom_hooks/pre-receive.d/' + hook_name, which) + create_hook('custom_hooks/update.d/' + hook_name, which) + create_hook('custom_hooks/post-receive.d/' + hook_name, which) end def cleanup_hook_setup @@ -51,6 +51,20 @@ describe GitlabCustomHook do FileUtils.rm_rf(File.join(tmp_root_path, 'hooks')) end + def expect_call_receive_hook(path) + expect(gitlab_custom_hook) + .to receive(:call_receive_hook) + .with(hook_path(path), changes) + .and_call_original + end + + def expect_call_update_hook(path) + expect(gitlab_custom_hook) + .to receive(:system) + .with(vars, hook_path(path), ref_name, old_value, new_value) + .and_call_original + end + # setup paths # <repository>.git/hooks/ - symlink to gitlab-shell/hooks global dir # <repository>.git/hooks/<hook_name> - executed by git itself, this is gitlab-shell/hooks/<hook_name> @@ -175,15 +189,9 @@ describe GitlabCustomHook do end it "only executes the global hook" do - expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path("custom_hooks/pre-receive.d/hook"), changes) - .and_call_original - expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path("custom_hooks/update.d/hook"), ref_name, old_value, new_value) - .and_call_original - expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path("custom_hooks/post-receive.d/hook"), changes) - .and_call_original + expect_call_receive_hook("custom_hooks/pre-receive.d/hook") + expect_call_update_hook("custom_hooks/update.d/hook") + expect_call_receive_hook("custom_hooks/post-receive.d/hook") gitlab_custom_hook.pre_receive(changes) gitlab_custom_hook.update(ref_name, old_value, new_value) @@ -204,24 +212,12 @@ describe GitlabCustomHook do end it "executes the relevant hooks" do - expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path("hooks/pre-receive.d/hook"), changes) - .and_call_original - expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path("custom_hooks/pre-receive.d/hook"), changes) - .and_call_original - expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path("hooks/update.d/hook"), ref_name, old_value, new_value) - .and_call_original - expect(gitlab_custom_hook).to receive(:system) - .with(vars, hook_path("custom_hooks/update.d/hook"), ref_name, old_value, new_value) - .and_call_original - expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path("hooks/post-receive.d/hook"), changes) - .and_call_original - expect(gitlab_custom_hook).to receive(:call_receive_hook) - .with(hook_path("custom_hooks/post-receive.d/hook"), changes) - .and_call_original + expect_call_receive_hook("hooks/pre-receive.d/hook") + expect_call_receive_hook("custom_hooks/pre-receive.d/hook") + expect_call_update_hook("hooks/update.d/hook") + expect_call_update_hook("custom_hooks/update.d/hook") + expect_call_receive_hook("hooks/post-receive.d/hook") + expect_call_receive_hook("custom_hooks/post-receive.d/hook") gitlab_custom_hook.pre_receive(changes) gitlab_custom_hook.update(ref_name, old_value, new_value) -- GitLab From d9afbf47ea25834498e0dfe1f981e1fa576ba88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Fri, 25 Nov 2016 20:56:44 +0200 Subject: [PATCH 20/21] test expected hook order --- spec/gitlab_custom_hook_spec.rb | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb index cbf2d03..b5be8ec 100644 --- a/spec/gitlab_custom_hook_spec.rb +++ b/spec/gitlab_custom_hook_spec.rb @@ -224,4 +224,34 @@ describe GitlabCustomHook do gitlab_custom_hook.post_receive(changes) end end + + context "executing hooks in expected order" do + before do + create_repo_hooks_d(hook_ok, '01-test') + create_repo_hooks_d(hook_ok, '02-test') + create_global_hooks_d(hook_ok, '03-test') + create_global_hooks_d(hook_ok, '04-test') + end + + it "executes hooks in order" do + expect_call_receive_hook("custom_hooks/pre-receive.d/01-test").ordered + expect_call_receive_hook("custom_hooks/pre-receive.d/02-test").ordered + expect_call_receive_hook("hooks/pre-receive.d/03-test").ordered + expect_call_receive_hook("hooks/pre-receive.d/04-test").ordered + + expect_call_update_hook("custom_hooks/update.d/01-test").ordered + expect_call_update_hook("custom_hooks/update.d/02-test").ordered + expect_call_update_hook("hooks/update.d/03-test").ordered + expect_call_update_hook("hooks/update.d/04-test").ordered + + expect_call_receive_hook("custom_hooks/post-receive.d/01-test").ordered + expect_call_receive_hook("custom_hooks/post-receive.d/02-test").ordered + expect_call_receive_hook("hooks/post-receive.d/03-test").ordered + expect_call_receive_hook("hooks/post-receive.d/04-test").ordered + + gitlab_custom_hook.pre_receive(changes) + gitlab_custom_hook.update(ref_name, old_value, new_value) + gitlab_custom_hook.post_receive(changes) + end + end end -- GitLab From b77f6530b96c520ef8637ceba4ef2889a008d383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= <glen@delfi.ee> Date: Fri, 25 Nov 2016 21:03:16 +0200 Subject: [PATCH 21/21] changelog spelling --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 7cb6b19..0caca15 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,5 @@ v4.1.0 - - Add support for global custom hooks and chanined hooks (Elan Ruusamäe, Dirk Hörner), !93, !89, #32 + - Add support for global custom hooks and chained hook directories (Elan Ruusamäe, Dirk Hörner), !93, !89, #32 v4.0.3 - Fetch repositories with `--prune` option by default -- GitLab