diff options
-rwxr-xr-x | hooks/post-receive | 24 | ||||
-rwxr-xr-x | hooks/pre-receive | 34 | ||||
-rwxr-xr-x | hooks/update | 20 | ||||
-rw-r--r-- | lib/gitlab_access.rb | 43 | ||||
-rw-r--r-- | lib/gitlab_custom_hook.rb | 98 | ||||
-rw-r--r-- | lib/gitlab_net.rb | 1 | ||||
-rw-r--r-- | lib/gitlab_post_receive.rb | 125 | ||||
-rw-r--r-- | spec/gitlab_access_spec.rb | 77 | ||||
-rw-r--r-- | spec/gitlab_custom_hook_spec.rb | 295 | ||||
-rw-r--r-- | spec/gitlab_post_receive_spec.rb | 284 |
10 files changed, 9 insertions, 992 deletions
diff --git a/hooks/post-receive b/hooks/post-receive index 2b6538f..73740da 100755 --- a/hooks/post-receive +++ b/hooks/post-receive @@ -1,22 +1,4 @@ -#!/usr/bin/env ruby +#!/bin/sh +echo "The gitlab-shell hooks have been migrated to Gitaly, see https://gitlab.com/gitlab-org/gitaly/issues/1226" +exit 1 -# This file was placed here by GitLab. It makes sure that your pushed commits -# will be processed properly. - -refs = $stdin.read -key_id = ENV.delete('GL_ID') -gl_repository = ENV['GL_REPOSITORY'] -repo_path = Dir.pwd - -require_relative '../lib/gitlab_custom_hook' -require_relative '../lib/hooks_utils' -require_relative '../lib/gitlab_post_receive' - -push_options = HooksUtils.get_push_options - -if GitlabPostReceive.new(gl_repository, repo_path, key_id, refs, push_options).exec && - GitlabCustomHook.new(repo_path, key_id).post_receive(refs) - exit 0 -else - exit 1 -end diff --git a/hooks/pre-receive b/hooks/pre-receive index 6ce5879..73740da 100755 --- a/hooks/pre-receive +++ b/hooks/pre-receive @@ -1,32 +1,4 @@ -#!/usr/bin/env ruby +#!/bin/sh +echo "The gitlab-shell hooks have been migrated to Gitaly, see https://gitlab.com/gitlab-org/gitaly/issues/1226" +exit 1 -# This file was placed here by GitLab. It makes sure that your pushed commits -# will be processed properly. - -refs = $stdin.read -key_id = ENV.delete('GL_ID') -protocol = ENV.delete('GL_PROTOCOL') -repo_path = Dir.pwd -gl_repository = ENV['GL_REPOSITORY'] - -def increase_reference_counter(gl_repository, repo_path) - result = GitlabNet.new.pre_receive(gl_repository) - - result && result['reference_counter_increased'] -end - -require_relative '../lib/gitlab_custom_hook' -require_relative '../lib/gitlab_access' -require_relative '../lib/gitlab_net' - -# It's important that on pre-receive `increase_reference_counter` gets executed -# last so that it only runs if everything else succeeded. On post-receive on the -# 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(gl_repository, repo_path, key_id, refs, protocol).exec && - GitlabCustomHook.new(repo_path, key_id).pre_receive(refs) && - increase_reference_counter(gl_repository, repo_path) - exit 0 -else - exit 1 -end diff --git a/hooks/update b/hooks/update index 4c2fc08..73740da 100755 --- a/hooks/update +++ b/hooks/update @@ -1,18 +1,4 @@ -#!/usr/bin/env ruby +#!/bin/sh +echo "The gitlab-shell hooks have been migrated to Gitaly, see https://gitlab.com/gitlab-org/gitaly/issues/1226" +exit 1 -# 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 -key_id = ENV.delete('GL_ID') - -require_relative '../lib/gitlab_custom_hook' - -if GitlabCustomHook.new(repo_path, key_id).update(ref_name, old_value, new_value) - exit 0 -else - exit 1 -end diff --git a/lib/gitlab_access.rb b/lib/gitlab_access.rb deleted file mode 100644 index 72abd14..0000000 --- a/lib/gitlab_access.rb +++ /dev/null @@ -1,43 +0,0 @@ -require_relative 'gitlab_init' -require_relative 'gitlab_net' -require_relative 'gitlab_access_status' -require_relative 'gitlab_metrics' -require_relative 'object_dirs_helper' -require 'json' - -class GitlabAccess - class AccessDeniedError < StandardError; end - - attr_reader :config, :gl_repository, :repo_path, :changes, :protocol - - def initialize(gl_repository, repo_path, actor, changes, protocol) - @config = GitlabConfig.new - @gl_repository = gl_repository - @repo_path = repo_path.strip - @actor = actor - @changes = changes.lines - @protocol = protocol - end - - def exec - status = GitlabMetrics.measure('check-access:git-receive-pack') do - api.check_access('git-receive-pack', @gl_repository, @repo_path, @actor, @changes, @protocol, env: ObjectDirsHelper.all_attributes.to_json) - end - - raise AccessDeniedError, status.message unless status.allowed? - - true - rescue GitlabNet::ApiUnreachableError - $stderr.puts "GitLab: Failed to authorize your Git request: internal API unreachable" - false - rescue AccessDeniedError => ex - $stderr.puts "GitLab: #{ex.message}" - false - end - - protected - - def api - GitlabNet.new - end -end diff --git a/lib/gitlab_custom_hook.rb b/lib/gitlab_custom_hook.rb deleted file mode 100644 index 67096df..0000000 --- a/lib/gitlab_custom_hook.rb +++ /dev/null @@ -1,98 +0,0 @@ -require 'open3' -require_relative 'gitlab_init' -require_relative 'gitlab_metrics' - -class GitlabCustomHook - attr_reader :vars, :config - - def initialize(repo_path, key_id) - @repo_path = repo_path - @vars = { 'GL_ID' => key_id } - @config = GitlabConfig.new - end - - def pre_receive(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) - 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) - 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 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. - stdin_reader, stdin_writer = IO.pipe - hook_pid = spawn(vars, hook, in: stdin_reader, err: :out) - stdin_reader.close - - # Submit changes to the hook via its stdin. - begin - IO.copy_stream(StringIO.new(changes), stdin_writer) - rescue Errno::EPIPE # rubocop:disable Lint/HandleExceptions - # It is not an error if the hook does not consume all of its input. - end - - # Close the pipe to let the hook know there is no further input. - stdin_writer.close - - Process.wait(hook_pid) - $?.success? - end - - # 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> - project_custom_hook_file = File.join(@repo_path, 'custom_hooks', hook_name) - hook_files.push(project_custom_hook_file) if File.executable?(project_custom_hook_file) - - # <repository>.git/custom_hooks/<hook_name>.d/* - project_custom_hooks_dir = File.join(@repo_path, 'custom_hooks', "#{hook_name}.d") - hook_files += match_hook_files(project_custom_hooks_dir) - - # <repository>.git/hooks/<hook_name>.d/* OR <custom_hook_dir>/<hook_name>.d/* - global_custom_hooks_parent = config.custom_hooks_dir(default: File.join(@repo_path, 'hooks')) - global_custom_hooks_dir = File.join(global_custom_hooks_parent, "#{hook_name}.d") - hook_files += match_hook_files(global_custom_hooks_dir) - - 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) - return [] unless Dir.exist?(path) - - Dir["#{path}/*"].select do |f| - !f.end_with?('~') && File.executable?(f) - end.sort - end -end diff --git a/lib/gitlab_net.rb b/lib/gitlab_net.rb index a84ba84..07fef22 100644 --- a/lib/gitlab_net.rb +++ b/lib/gitlab_net.rb @@ -3,7 +3,6 @@ require 'openssl' require 'json' require_relative 'gitlab_config' -require_relative 'gitlab_access' require_relative 'gitlab_lfs_authentication' require_relative 'http_helper' diff --git a/lib/gitlab_post_receive.rb b/lib/gitlab_post_receive.rb deleted file mode 100644 index 7c5bd19..0000000 --- a/lib/gitlab_post_receive.rb +++ /dev/null @@ -1,125 +0,0 @@ -require_relative 'gitlab_init' -require_relative 'gitlab_net' -require_relative 'gitlab_metrics' -require 'json' -require 'base64' -require 'securerandom' - -class GitlabPostReceive - attr_reader :config, :gl_repository, :repo_path, :changes, :jid - - def initialize(gl_repository, repo_path, actor, changes, push_options) - @config = GitlabConfig.new - @gl_repository = gl_repository - @repo_path = repo_path.strip - @actor = actor - @changes = changes - @push_options = push_options - @jid = SecureRandom.hex(12) - end - - def exec - response = GitlabMetrics.measure("post-receive") do - api.post_receive(gl_repository, @actor, changes, @push_options) - end - - return false unless response - print_formatted_alert_message(response['broadcast_message']) if response['broadcast_message'] - print_merge_request_links(response['merge_request_urls']) if response['merge_request_urls'] - puts response['redirected_message'] if response['redirected_message'] - puts response['project_created_message'] if response['project_created_message'] - print_warnings(response['warnings']) if response['warnings'] - - response['reference_counter_decreased'] - rescue GitlabNet::ApiUnreachableError - false - end - - protected - - def api - @api ||= GitlabNet.new - end - - def print_merge_request_links(merge_request_urls) - return if merge_request_urls.empty? - puts - merge_request_urls.each { |mr| print_merge_request_link(mr) } - end - - def print_merge_request_link(merge_request) - message = - if merge_request["new_merge_request"] - "To create a merge request for #{merge_request['branch_name']}, visit:" - else - "View merge request for #{merge_request['branch_name']}:" - end - - puts message - puts((" " * 2) + merge_request["url"]) - puts - end - - def print_warnings(warnings) - message = "WARNINGS:\n#{warnings}" - print_formatted_alert_message(message) - end - - def print_formatted_alert_message(message) - # A standard terminal window is (at least) 80 characters wide. - total_width = 80 - - # Git prefixes remote messages with "remote: ", so this width is subtracted - # from the width available to us. - total_width -= "remote: ".length # rubocop:disable Performance/FixedSize - - # Our centered text shouldn't start or end right at the edge of the window, - # so we add some horizontal padding: 2 chars on either side. - text_width = total_width - 2 * 2 - - # Automatically wrap message at text_width (= 68) characters: - # Splits the message up into the longest possible chunks matching - # "<between 0 and text_width characters><space or end-of-line>". - - msg_start_idx = 0 - lines = [] - while msg_start_idx < message.length - parsed_line = parse_broadcast_msg(message[msg_start_idx..-1], text_width) - msg_start_idx += parsed_line.length - lines.push(parsed_line.strip) - end - - puts - puts "=" * total_width - puts - - lines.each do |line| - line.strip! - - # Center the line by calculating the left padding measured in characters. - line_padding = [(total_width - line.length) / 2, 0].max - puts((" " * line_padding) + line) - end - - puts - puts "=" * total_width - end - - private - - def parse_broadcast_msg(msg, text_length) - msg ||= "" - # just return msg if shorter than or equal to text length - return msg if msg.length <= text_length - - # search for word break shorter than text length - truncate_to_space = msg.match(/\A(.{,#{text_length}})(?=\s|$)(\s*)/).to_s - - if truncate_to_space.empty? - # search for word break longer than text length - truncate_to_space = msg.match(/\A\S+/).to_s - end - - truncate_to_space - end -end diff --git a/spec/gitlab_access_spec.rb b/spec/gitlab_access_spec.rb deleted file mode 100644 index 6c1d348..0000000 --- a/spec/gitlab_access_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -require 'spec_helper' -require 'gitlab_access' - -describe GitlabAccess do - let(:repository_path) { "/home/git/repositories" } - let(:repo_name) { 'dzaporozhets/gitlab-ci' } - let(:repo_path) { File.join(repository_path, repo_name) + ".git" } - let(:api) do - double(GitlabNet).tap do |api| - allow(api).to receive(:check_access).and_return(GitAccessStatus.new(true, - '200', - 'ok', - gl_repository: 'project-1', - gl_project_path: 'group/subgroup/project', - gl_id: 'user-123', - gl_username: 'testuser', - git_config_options: ['receive.MaxInputSize=10000'], - gitaly: nil, - git_protocol: 'version=2')) - end - end - subject do - GitlabAccess.new(nil, repo_path, 'key-123', 'wow', 'ssh').tap do |access| - allow(access).to receive(:exec_cmd).and_return(:exec_called) - allow(access).to receive(:api).and_return(api) - end - end - - before do - allow_any_instance_of(GitlabConfig).to receive(:repos_path).and_return(repository_path) - end - - describe :initialize do - it { expect(subject.repo_path).to eq(repo_path) } - it { expect(subject.changes).to eq(['wow']) } - it { expect(subject.protocol).to eq('ssh') } - end - - describe "#exec" do - context "access is granted" do - it "returns true" do - expect(subject.exec).to be_truthy - end - end - - context "access is denied" do - before do - allow(api).to receive(:check_access).and_return(GitAccessStatus.new( - false, - '401', - 'denied', - gl_repository: nil, - gl_project_path: nil, - gl_id: nil, - gl_username: nil, - git_config_options: nil, - gitaly: nil, - git_protocol: nil - )) - end - - it "returns false" do - expect(subject.exec).to be_falsey - end - end - - context "API connection fails" do - before do - allow(api).to receive(:check_access).and_raise(GitlabNet::ApiUnreachableError) - end - - it "returns false" do - expect(subject.exec).to be_falsey - end - end - end -end diff --git a/spec/gitlab_custom_hook_spec.rb b/spec/gitlab_custom_hook_spec.rb deleted file mode 100644 index 540cd2b..0000000 --- a/spec/gitlab_custom_hook_spec.rb +++ /dev/null @@ -1,295 +0,0 @@ -# coding: utf-8 -require 'spec_helper' -require 'gitlab_custom_hook' - -describe GitlabCustomHook do - let(:original_root_path) { ROOT_PATH } - let(:tmp_repo_path) { File.join(original_root_path, 'tmp', 'repo.git') } - let(:tmp_root_path) { File.join(original_root_path, 'tmp') } - let(:global_custom_hooks_path) { global_hook_path('custom_global_hooks') } - let(:hook_ok) { File.join(original_root_path, 'spec', 'support', 'hook_ok') } - let(:hook_fail) { File.join(original_root_path, 'spec', 'support', 'hook_fail') } - let(:hook_gl_id) { File.join(original_root_path, 'spec', 'support', 'gl_id_test_hook') } - - 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" } - - let(:gitlab_custom_hook) { GitlabCustomHook.new(tmp_repo_path, 'key_1') } - - def hook_path(path) - File.join(tmp_repo_path, path.split('/')) - end - - def global_hook_path(path) - File.join(tmp_root_path, path.split('/')) - end - - def create_hook(path, which) - FileUtils.ln_sf(which, hook_path(path)) - end - - # global hooks multiplexed - 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 - 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(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 - FileUtils.rm_rf(File.join(tmp_repo_path)) - FileUtils.rm_rf(File.join(global_custom_hooks_path)) - FileUtils.rm_rf(File.join(tmp_root_path, 'hooks')) - FileUtils.rm_f(File.join(tmp_root_path, 'config.yml')) - 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> - # <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 - cleanup_hook_setup - - FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks')) - FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks')) - - ['pre-receive', 'update', 'post-receive'].each do |hook| - FileUtils.mkdir_p(File.join(tmp_repo_path, 'custom_hooks', "#{hook}.d")) - FileUtils.mkdir_p(File.join(tmp_root_path, 'hooks', "#{hook}.d")) - end - - FileUtils.symlink(File.join(tmp_root_path, 'hooks'), File.join(tmp_repo_path, 'hooks')) - FileUtils.symlink(File.join(ROOT_PATH, 'config.yml.example'), File.join(tmp_root_path, 'config.yml')) - - stub_const('ROOT_PATH', tmp_root_path) - end - - after do - cleanup_hook_setup - end - - 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 - - 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 "having no hooks" do - it "returns true" do - 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 successful repo hooks" do - before do - create_repo_hooks(hook_ok) - end - - it "returns true" do - 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 successful repo and global hooks" do - before do - create_repo_hooks(hook_ok) - create_global_hooks_d(hook_ok) - end - - it "returns true" do - 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 failing repo and successful global hooks" do - before do - create_repo_hooks_d(hook_fail) - create_global_hooks_d(hook_ok) - end - - it "returns false" do - 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 global hook" do - 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) - gitlab_custom_hook.post_receive(changes) - end - end - - context "having successful repo but failing global hooks" do - before do - create_repo_hooks_d(hook_ok) - create_global_hooks_d(hook_fail) - end - - it "returns false" do - 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_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_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 - - context "when the custom_hooks_dir config option is set" do - before do - allow(gitlab_custom_hook.config).to receive(:custom_hooks_dir).and_return(global_custom_hooks_path) - - FileUtils.mkdir_p(File.join(global_custom_hooks_path, "pre-receive.d")) - FileUtils.ln_sf(hook_ok, File.join(global_custom_hooks_path, "pre-receive.d", "hook")) - - create_global_hooks_d(hook_fail) - end - - it "finds hooks in that directory" do - expect(gitlab_custom_hook) - .to receive(:call_receive_hook) - .with(global_hook_path("custom_global_hooks/pre-receive.d/hook"), changes) - .and_call_original - - expect(gitlab_custom_hook.pre_receive(changes)).to eq(true) - end - - it "does not execute hooks in the default location" do - expect(gitlab_custom_hook) - .not_to receive(:call_receive_hook) - .with("hooks/pre-receive.d/hook", changes) - .and_call_original - - gitlab_custom_hook.pre_receive(changes) - end - end -end diff --git a/spec/gitlab_post_receive_spec.rb b/spec/gitlab_post_receive_spec.rb deleted file mode 100644 index d061830..0000000 --- a/spec/gitlab_post_receive_spec.rb +++ /dev/null @@ -1,284 +0,0 @@ -# coding: utf-8 -require 'spec_helper' -require 'gitlab_post_receive' - -describe GitlabPostReceive do - let(:repository_path) { "/home/git/repositories" } - let(:repo_name) { 'dzaporozhets/gitlab-ci' } - let(:actor) { 'key-123' } - let(:changes) { "123456 789012 refs/heads/tést\n654321 210987 refs/tags/tag" } - let(:wrongly_encoded_changes) { changes.encode("ISO-8859-1").force_encoding("UTF-8") } - let(:base64_changes) { Base64.encode64(wrongly_encoded_changes) } - let(:repo_path) { File.join(repository_path, repo_name) + ".git" } - let(:gl_repository) { "project-1" } - let(:push_options) { [] } - let(:gitlab_post_receive) { GitlabPostReceive.new(gl_repository, repo_path, actor, wrongly_encoded_changes, push_options) } - let(:broadcast_message) { "test " * 10 + "message " * 10 } - let(:enqueued_at) { Time.new(2016, 6, 23, 6, 59) } - let(:new_merge_request_urls) do - [{ - 'branch_name' => 'new_branch', - 'url' => 'http://localhost/dzaporozhets/gitlab-ci/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch', - 'new_merge_request' => true - }] - end - let(:existing_merge_request_urls) do - [{ - 'branch_name' => 'feature_branch', - 'url' => 'http://localhost/dzaporozhets/gitlab-ci/merge_requests/1', - 'new_merge_request' => false - }] - end - - before do - $logger = double('logger').as_null_object # Global vars are bad - allow_any_instance_of(GitlabConfig).to receive(:repos_path).and_return(repository_path) - end - - describe "#exec" do - let(:response) { { 'reference_counter_decreased' => true } } - - it 'calls the api to notify the execution of the hook' do - expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) - - expect(gitlab_post_receive.exec).to eq(true) - end - - context 'merge request urls and broadcast messages' do - let(:response) do - { - 'reference_counter_decreased' => true, - 'merge_request_urls' => new_merge_request_urls, - 'broadcast_message' => broadcast_message - } - end - - it 'prints the merge request urls and broadcast message' do - expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) - assert_broadcast_message_printed(gitlab_post_receive) - assert_new_mr_printed(gitlab_post_receive) - - expect(gitlab_post_receive.exec).to eq(true) - end - - context 'when contains long url string at end' do - let(:broadcast_message) { "test " * 10 + "message " * 10 + "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url" } - - it 'doesnt truncate url' do - expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) - assert_broadcast_message_printed_keep_long_url_end(gitlab_post_receive) - assert_new_mr_printed(gitlab_post_receive) - - expect(gitlab_post_receive.exec).to eq(true) - end - end - - context 'when contains long url string at start' do - let(:broadcast_message) { "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url " + "test " * 10 + "message " * 11} - - it 'doesnt truncate url' do - expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) - assert_broadcast_message_printed_keep_long_url_start(gitlab_post_receive) - assert_new_mr_printed(gitlab_post_receive) - - expect(gitlab_post_receive.exec).to eq(true) - end - end - - context 'when contains long url string in middle' do - let(:broadcast_message) { "test " * 11 + "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url " + "message " * 11} - - it 'doesnt truncate url' do - expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) - assert_broadcast_message_printed_keep_long_url_middle(gitlab_post_receive) - assert_new_mr_printed(gitlab_post_receive) - - expect(gitlab_post_receive.exec).to eq(true) - end - end - end - - context 'when warnings are present' do - let(:response) do - { - 'reference_counter_decreased' => true, - 'warnings' => 'My warning message' - } - end - - it 'treats the warning as a broadcast message' do - expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) - expect(gitlab_post_receive).to receive(:print_formatted_alert_message).with("WARNINGS:\nMy warning message") - expect(gitlab_post_receive.exec).to eq(true) - end - end - - context 'when redirected message available' do - let(:message) { "This is a redirected message" } - let(:response) do - { - 'reference_counter_decreased' => true, - 'redirected_message' => message - } - end - - it 'prints redirected message' do - expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) - assert_redirected_message_printed(gitlab_post_receive) - expect(gitlab_post_receive.exec).to eq(true) - end - - context 'when project created message is available' do - let(:message) { "This is a created project message" } - let(:response) do - { - 'reference_counter_decreased' => true, - 'project_created_message' => message - } - end - - it 'prints project created message' do - expect_any_instance_of(GitlabNet).to receive(:post_receive).and_return(response) - - assert_project_created_message_printed(gitlab_post_receive) - - expect(gitlab_post_receive.exec).to be true - end - end - end - end - - private - - def assert_new_mr_printed(gitlab_post_receive) - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "To create a merge request for new_branch, visit:" - ).ordered - expect(gitlab_post_receive).to receive(:puts).with( - " http://localhost/dzaporozhets/gitlab-ci/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" - ).ordered - expect(gitlab_post_receive).to receive(:puts).ordered - end - - def assert_existing_mr_printed(gitlab_post_receive) - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "View merge request for feature_branch:" - ).ordered - expect(gitlab_post_receive).to receive(:puts).with( - " http://localhost/dzaporozhets/gitlab-ci/merge_requests/1" - ).ordered - expect(gitlab_post_receive).to receive(:puts).ordered - end - - def assert_broadcast_message_printed(gitlab_post_receive) - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "========================================================================" - ).ordered - expect(gitlab_post_receive).to receive(:puts).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - " test test test test test test test test test test message message" - ).ordered - expect(gitlab_post_receive).to receive(:puts).with( - " message message message message message message message message" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "========================================================================" - ).ordered - end - - def assert_redirected_message_printed(gitlab_post_receive) - expect(gitlab_post_receive).to receive(:puts).with("This is a redirected message") - end - - def assert_project_created_message_printed(gitlab_post_receive) - expect(gitlab_post_receive).to receive(:puts).with("This is a created project message") - end - - def assert_broadcast_message_printed_keep_long_url_end(gitlab_post_receive) - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "========================================================================" - ).ordered - expect(gitlab_post_receive).to receive(:puts).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - " test test test test test test test test test test message message" - ).ordered - expect(gitlab_post_receive).to receive(:puts).with( - " message message message message message message message message" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "========================================================================" - ).ordered - end - - def assert_broadcast_message_printed_keep_long_url_start(gitlab_post_receive) - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "========================================================================" - ).ordered - expect(gitlab_post_receive).to receive(:puts).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - " test test test test test test test test test test message message" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - " message message message message message message message message" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - " message" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "========================================================================" - ).ordered - end - - def assert_broadcast_message_printed_keep_long_url_middle(gitlab_post_receive) - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "========================================================================" - ).ordered - expect(gitlab_post_receive).to receive(:puts).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - " test test test test test test test test test test test" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - "https://localhost:5000/test/a/really/long/url/that/is/in/the/broadcast/message/do-not-truncate-when-url" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - " message message message message message message message message" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).with( - " message message message" - ).ordered - - expect(gitlab_post_receive).to receive(:puts).ordered - expect(gitlab_post_receive).to receive(:puts).with( - "========================================================================" - ).ordered - end -end |