require_relative 'gitlab_init' require_relative 'gitlab_net' require_relative 'gitlab_reference_counter' require 'json' require 'base64' require 'securerandom' class GitlabPostReceive include NamesHelper attr_reader :config, :repo_path, :changes, :jid def initialize(repo_path, actor, changes) @config = GitlabConfig.new @repo_path, @actor = repo_path.strip, actor @repo_name = extract_repo_name(@repo_path.dup) @changes = changes @jid = SecureRandom.hex(12) end def exec result = update_redis begin broadcast_message = api.broadcast_message if broadcast_message.has_key?("message") puts print_broadcast_message(broadcast_message["message"]) end merge_request_urls = api.merge_request_urls(@repo_name, @changes) print_merge_request_links(merge_request_urls) rescue GitlabNet::ApiUnreachableError nil end result && GitlabReferenceCounter.new(repo_path).decrease 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) if merge_request["new_merge_request"] message = "Create merge request for #{merge_request["branch_name"]}:" else message = "View merge request for #{merge_request["branch_name"]}:" end puts message puts((" " * 2) + merge_request["url"]) puts end def print_broadcast_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 # 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 # "". # The last result is always an empty string (0 chars and the end-of-line), # so drop that. # message.scan returns a nested array of capture groups, so flatten. lines = message.scan(/(.{,#{text_width}})(?:\s|$)/)[0...-1].flatten 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 def update_redis # Encode changes as base64 so we don't run into trouble with non-UTF-8 input. changes = Base64.encode64(@changes) queue = "#{config.redis_namespace}:queue:post_receive" msg = JSON.dump({ 'class' => 'PostReceive', 'args' => [@repo_path, @actor, changes], 'jid' => @jid, 'enqueued_at' => Time.now.to_f }) begin GitlabNet.new.redis_client.rpush(queue, msg) true rescue => e $stderr.puts "GitLab: An unexpected error occurred in writing to Redis: #{e}" false end end end