189 lines
5 KiB
Ruby
189 lines
5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'json'
|
|
require 'socket'
|
|
require 'resolv'
|
|
|
|
class IrkerWorker # rubocop:disable Scalability/IdempotentWorker
|
|
include ApplicationWorker
|
|
|
|
data_consistency :always
|
|
sidekiq_options retry: 3
|
|
feature_category :integrations
|
|
urgency :low
|
|
|
|
def perform(project_id, channels, colors, push_data, settings)
|
|
# Establish connection to irker server
|
|
return false unless start_connection(settings['server_host'],
|
|
settings['server_port'])
|
|
|
|
@project = Project.find(project_id)
|
|
@colors = colors
|
|
@channels = channels
|
|
|
|
@repo_path = @project.full_path
|
|
@repo_name = push_data['repository']['name']
|
|
@committer = push_data['user_name']
|
|
@branch = push_data['ref'].gsub(%r'refs/[^/]*/', '')
|
|
|
|
if @colors
|
|
@repo_name = "\x0304#{@repo_name}\x0f"
|
|
@branch = "\x0305#{@branch}\x0f"
|
|
end
|
|
|
|
# First messages are for branch creation/deletion
|
|
send_branch_updates(push_data)
|
|
|
|
# Next messages are for commits
|
|
send_commits(push_data)
|
|
|
|
close_connection
|
|
true
|
|
end
|
|
|
|
private
|
|
|
|
def start_connection(irker_server, irker_port)
|
|
ip_address = Resolv.getaddress(irker_server)
|
|
# handle IP6 addresses
|
|
domain = Resolv::IPv6::Regex.match?(ip_address) ? "[#{ip_address}]" : ip_address
|
|
|
|
begin
|
|
Gitlab::UrlBlocker.validate!(
|
|
"irc://#{domain}",
|
|
allow_localhost: allow_local_requests?,
|
|
allow_local_network: allow_local_requests?,
|
|
schemes: ['irc'])
|
|
@socket = TCPSocket.new ip_address, irker_port
|
|
rescue Errno::ECONNREFUSED, Gitlab::UrlBlocker::BlockedUrlError => e
|
|
logger.fatal "Can't connect to Irker daemon: #{e}"
|
|
return false
|
|
end
|
|
|
|
true
|
|
end
|
|
|
|
def allow_local_requests?
|
|
Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
|
|
end
|
|
|
|
def send_to_irker(privmsg)
|
|
to_send = { to: @channels, privmsg: privmsg }
|
|
|
|
@socket.puts Gitlab::Json.dump(to_send)
|
|
end
|
|
|
|
def close_connection
|
|
@socket.close
|
|
end
|
|
|
|
def send_branch_updates(push_data)
|
|
message =
|
|
if Gitlab::Git.blank_ref?(push_data['before'])
|
|
new_branch_message
|
|
elsif Gitlab::Git.blank_ref?(push_data['after'])
|
|
delete_branch_message
|
|
end
|
|
|
|
send_to_irker(message)
|
|
end
|
|
|
|
def new_branch_message
|
|
newbranch = "#{Gitlab.config.gitlab.url}/#{@repo_path}/-/branches"
|
|
newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors
|
|
|
|
"[#{@repo_name}] #{@committer} has created a new branch #{@branch}: #{newbranch}"
|
|
end
|
|
|
|
def delete_branch_message
|
|
"[#{@repo_name}] #{@committer} has deleted the branch #{@branch}"
|
|
end
|
|
|
|
def send_commits(push_data)
|
|
return if push_data['total_commits_count'] == 0
|
|
|
|
# Next message is for number of commit pushed, if any
|
|
if Gitlab::Git.blank_ref?(push_data['before'])
|
|
# Tweak on push_data["before"] in order to have a nice compare URL
|
|
push_data['before'] = before_on_new_branch(push_data)
|
|
end
|
|
|
|
send_commits_count(push_data)
|
|
|
|
# One message per commit, limited by 3 messages (same limit as the
|
|
# github irc hook)
|
|
commits = push_data['commits'].first(3)
|
|
commits.each do |commit_attrs|
|
|
send_one_commit(commit_attrs)
|
|
end
|
|
end
|
|
|
|
def before_on_new_branch(push_data)
|
|
commit = commit_from_id(push_data['commits'][0]['id'])
|
|
parents = commit.parents
|
|
|
|
# Return old value if there's no new one
|
|
return push_data['before'] if parents.empty?
|
|
|
|
# Or return the first parent-commit
|
|
parents[0].id
|
|
end
|
|
|
|
def send_commits_count(push_data)
|
|
url = compare_url(push_data['before'], push_data['after'])
|
|
commits = colorize_commits(push_data['total_commits_count'])
|
|
new_commits = 'new commit'.pluralize(push_data['total_commits_count'])
|
|
|
|
send_to_irker("[#{@repo_name}] #{@committer} pushed #{commits} #{new_commits} " \
|
|
"to #{@branch}: #{url}")
|
|
end
|
|
|
|
def compare_url(sha_before, sha_after)
|
|
sha1 = Commit.truncate_sha(sha_before)
|
|
sha2 = Commit.truncate_sha(sha_after)
|
|
compare_url = "#{Gitlab.config.gitlab.url}/#{@repo_path}/-/compare" \
|
|
"/#{sha1}...#{sha2}"
|
|
|
|
colorize_url(compare_url)
|
|
end
|
|
|
|
def send_one_commit(commit_attrs)
|
|
commit = commit_from_id(commit_attrs['id'])
|
|
sha = colorize_sha(Commit.truncate_sha(commit_attrs['id']))
|
|
author = commit_attrs['author']['name']
|
|
files = colorize_nb_files(files_count(commit))
|
|
title = commit.title
|
|
|
|
send_to_irker("#{@repo_name}/#{@branch} #{sha} #{author} (#{files}): #{title}")
|
|
end
|
|
|
|
def commit_from_id(id)
|
|
@project.commit(id)
|
|
end
|
|
|
|
def files_count(commit)
|
|
diff_size = commit.raw_deltas.size
|
|
|
|
"#{diff_size} file".pluralize(diff_size)
|
|
end
|
|
|
|
def colorize_sha(sha)
|
|
sha = "\x0314#{sha}\x0f" if @colors
|
|
sha
|
|
end
|
|
|
|
def colorize_nb_files(nb_files)
|
|
nb_files = "\x0312#{nb_files}\x0f" if @colors
|
|
nb_files
|
|
end
|
|
|
|
def colorize_url(url)
|
|
url = "\x0302\x1f#{url}\x0f" if @colors
|
|
url
|
|
end
|
|
|
|
def colorize_commits(commits)
|
|
commits = "\x02#{commits}\x0f" if @colors
|
|
commits
|
|
end
|
|
end
|