Welcome to mirror list, hosted at ThFree Co, Russian Federation.

irker_worker.rb « integrations « workers « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 4c1f0df0fc78dbf280985e5b24c9a787619e4c6b (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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# frozen_string_literal: true

require 'json'
require 'socket'
require 'resolv'

module Integrations
  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::HTTP_V2::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
end