summaryrefslogtreecommitdiff
path: root/app/workers/irker_worker.rb
blob: c9658b3fe17c458fbee1da4548a7763c24fd9bee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
require 'json'
require 'socket'

class IrkerWorker
  include Sidekiq::Worker
  include DedicatedSidekiqQueue

  def perform(project_id, chans, colors, push_data, settings)
    project = Project.find(project_id)

    # Get config parameters
    return false unless init_perform settings, chans, colors

    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, project, repo_name, committer, branch

    # Next messages are for commits
    send_commits push_data, project, repo_name, committer, branch

    close_connection
    true
  end

  private

  def init_perform(set, chans, colors)
    @colors = colors
    @channels = chans
    start_connection set['server_host'], set['server_port']
  end

  def start_connection(irker_server, irker_port)
    begin
      @socket = TCPSocket.new irker_server, irker_port
    rescue Errno::ECONNREFUSED => e
      logger.fatal "Can't connect to Irker daemon: #{e}"
      return false
    end
    true
  end

  def sendtoirker(privmsg)
    to_send = { to: @channels, privmsg: privmsg }
    @socket.puts JSON.dump(to_send)
  end

  def close_connection
    @socket.close
  end

  def send_branch_updates(push_data, project, repo_name, committer, branch)
    if Gitlab::Git.blank_ref?(push_data['before'])
      send_new_branch project, repo_name, committer, branch
    elsif Gitlab::Git.blank_ref?(push_data['after'])
      send_del_branch repo_name, committer, branch
    end
  end

  def send_new_branch(project, repo_name, committer, branch)
    repo_path = project.path_with_namespace
    newbranch = "#{Gitlab.config.gitlab.url}/#{repo_path}/branches"
    newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors

    privmsg = "[#{repo_name}] #{committer} has created a new branch "
    privmsg += "#{branch}: #{newbranch}"
    sendtoirker privmsg
  end

  def send_del_branch(repo_name, committer, branch)
    privmsg = "[#{repo_name}] #{committer} has deleted the branch #{branch}"
    sendtoirker privmsg
  end

  def send_commits(push_data, project, repo_name, committer, branch)
    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, project
    end

    send_commits_count(push_data, project, repo_name, committer, branch)

    # One message per commit, limited by 3 messages (same limit as the
    # github irc hook)
    commits = push_data['commits'].first(3)
    commits.each do |hook_attrs|
      send_one_commit project, hook_attrs, repo_name, branch
    end
  end

  def before_on_new_branch(push_data, project)
    commit = commit_from_id project, 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(data, project, repo, committer, branch)
    url = compare_url data, project.path_with_namespace
    commits = colorize_commits data['total_commits_count']

    new_commits = 'new commit'
    new_commits += 's' if data['total_commits_count'] > 1

    sendtoirker "[#{repo}] #{committer} pushed #{commits} #{new_commits} " \
                "to #{branch}: #{url}"
  end

  def compare_url(data, repo_path)
    sha1 = Commit.truncate_sha(data['before'])
    sha2 = Commit.truncate_sha(data['after'])
    compare_url = "#{Gitlab.config.gitlab.url}/#{repo_path}/compare"
    compare_url += "/#{sha1}...#{sha2}"
    colorize_url compare_url
  end

  def send_one_commit(project, hook_attrs, repo_name, branch)
    commit = commit_from_id project, hook_attrs['id']
    sha = colorize_sha Commit.truncate_sha(hook_attrs['id'])
    author = hook_attrs['author']['name']
    files = colorize_nb_files(files_count commit)
    title = commit.title

    sendtoirker "#{repo_name}/#{branch} #{sha} #{author} (#{files}): #{title}"
  end

  def commit_from_id(project, id)
    project.commit(id)
  end

  def files_count(commit)
    diffs = commit.raw_diffs(deltas_only: true)

    files = "#{diffs.real_size} file"
    files += 's' if diffs.size > 1
    files
  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