BigW Consortium Gitlab

hipchat_service.rb 7.74 KB
Newer Older
1
class HipchatService < Service
2 3
  MAX_COMMITS = 3

4
  prop_accessor :token, :room, :server, :notify, :color, :api_version
5
  boolean_accessor :notify_only_broken_builds
6 7
  validates :token, presence: true, if: :activated?

8 9 10 11 12 13
  def initialize_properties
    if properties.nil?
      self.properties = {}
      self.notify_only_broken_builds = true
    end
  end
14

15
  def title
16
    'HipChat'
17 18 19
  end

  def description
20
    'Private group chat and IM'
21 22 23 24 25 26 27 28
  end

  def to_param
    'hipchat'
  end

  def fields
    [
29 30
      { type: 'text', name: 'token',     placeholder: 'Room token' },
      { type: 'text', name: 'room',      placeholder: 'Room name or ID' },
31 32
      { type: 'checkbox', name: 'notify' },
      { type: 'select', name: 'color', choices: ['yellow', 'red', 'green', 'purple', 'gray', 'random'] },
33 34
      { type: 'text', name: 'api_version',
        placeholder: 'Leave blank for default (v2)' },
35
      { type: 'text', name: 'server',
36 37
        placeholder: 'Leave blank for default. https://hipchat.example.com' },
      { type: 'checkbox', name: 'notify_only_broken_builds' },
38 39 40
    ]
  end

41
  def supported_events
42
    %w(push issue merge_request note tag_push build)
43 44
  end

45
  def execute(data)
46
    return unless supported_events.include?(data[:object_kind])
47 48
    message = create_message(data)
    return unless message.present?
49
    gate[room].send('GitLab', message, message_options)
50 51
  end

52 53 54 55 56 57 58 59 60 61
  def test(data)
    begin
      result = execute(data)
    rescue StandardError => error
      return { success: false, result: error }
    end

    { success: true, result: result }
  end

62 63 64
  private

  def gate
65
    options = { api_version: api_version.present? ? api_version : 'v2' }
Drew Blessing committed
66
    options[:server_url] = server unless server.blank?
67
    @gate ||= HipChat::Client.new(token, options)
68 69
  end

70 71 72 73
  def message_options
    { notify: notify.present? && notify == '1', color: color || 'yellow' }
  end

74 75 76
  def create_message(data)
    object_kind = data[:object_kind]

77 78 79 80 81 82 83 84 85
    case object_kind
    when "push", "tag_push"
      create_push_message(data)
    when "issue"
      create_issue_message(data) unless is_update?(data)
    when "merge_request"
      create_merge_request_message(data) unless is_update?(data)
    when "note"
      create_note_message(data)
86 87
    when "build"
      create_build_message(data) if should_build_be_notified?(data)
88
    end
89 90 91
  end

  def create_push_message(push)
92 93
    ref_type = Gitlab::Git.tag_ref?(push[:ref]) ? 'tag' : 'branch'
    ref = Gitlab::Git.ref_name(push[:ref])
94

95 96 97 98 99
    before = push[:before]
    after = push[:after]

    message = ""
    message << "#{push[:user_name]} "
100
    if Gitlab::Git.blank_ref?(before)
101
      message << "pushed new #{ref_type} <a href=\""\
102
                 "#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>"\
103
                 " to #{project_link}\n"
104
    elsif Gitlab::Git.blank_ref?(after)
105
      message << "removed #{ref_type} <b>#{ref}</b> from <a href=\"#{project.web_url}\">#{project_name}</a> \n"
106
    else
107
      message << "pushed to #{ref_type} <a href=\""\
108
                  "#{project.web_url}/commits/#{CGI.escape(ref)}\">#{ref}</a> "
109 110
      message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> "
      message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)"
111 112 113 114 115 116 117

      push[:commits].take(MAX_COMMITS).each do |commit|
        message << "<br /> - #{commit[:message].lines.first} (<a href=\"#{commit[:url]}\">#{commit[:id][0..5]}</a>)"
      end

      if push[:commits].count > MAX_COMMITS
        message << "<br />... #{push[:commits].count - MAX_COMMITS} more commits"
118 119 120 121 122
      end
    end

    message
  end
123

124 125 126 127 128 129 130 131
  def format_body(body)
    if body
      body = body.truncate(200, separator: ' ', omission: '...')
    end

    "<pre>#{body}</pre>"
  end

132
  def create_issue_message(data)
133
    user_name = data[:user][:name]
134 135 136 137 138 139 140 141 142

    obj_attr = data[:object_attributes]
    obj_attr = HashWithIndifferentAccess.new(obj_attr)
    title = obj_attr[:title]
    state = obj_attr[:state]
    issue_iid = obj_attr[:iid]
    issue_url = obj_attr[:url]
    description = obj_attr[:description]

143 144
    issue_link = "<a href=\"#{issue_url}\">issue ##{issue_iid}</a>"
    message = "#{user_name} #{state} #{issue_link} in #{project_link}: <b>#{title}</b>"
145 146

    if description
147 148
      description = format_body(description)
      message << description
149 150 151 152 153 154
    end

    message
  end

  def create_merge_request_message(data)
155
    user_name = data[:user][:name]
156 157 158 159 160 161 162 163 164

    obj_attr = data[:object_attributes]
    obj_attr = HashWithIndifferentAccess.new(obj_attr)
    merge_request_id = obj_attr[:iid]
    state = obj_attr[:state]
    description = obj_attr[:description]
    title = obj_attr[:title]

    merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}"
165
    merge_request_link = "<a href=\"#{merge_request_url}\">merge request !#{merge_request_id}</a>"
166
    message = "#{user_name} #{state} #{merge_request_link} in " \
167 168 169
      "#{project_link}: <b>#{title}</b>"

    if description
170 171 172 173 174 175 176 177 178 179 180 181 182
      description = format_body(description)
      message << description
    end

    message
  end

  def format_title(title)
    "<b>" + title.lines.first.chomp + "</b>"
  end

  def create_note_message(data)
    data = HashWithIndifferentAccess.new(data)
183
    user_name = data[:user][:name]
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

    obj_attr = HashWithIndifferentAccess.new(data[:object_attributes])
    note = obj_attr[:note]
    note_url = obj_attr[:url]
    noteable_type = obj_attr[:noteable_type]

    case noteable_type
    when "Commit"
      commit_attr = HashWithIndifferentAccess.new(data[:commit])
      subject_desc = commit_attr[:id]
      subject_desc = Commit.truncate_sha(subject_desc)
      subject_type = "commit"
      title = format_title(commit_attr[:message])
    when "Issue"
      subj_attr = HashWithIndifferentAccess.new(data[:issue])
      subject_id = subj_attr[:iid]
      subject_desc = "##{subject_id}"
      subject_type = "issue"
      title = format_title(subj_attr[:title])
    when "MergeRequest"
      subj_attr = HashWithIndifferentAccess.new(data[:merge_request])
      subject_id = subj_attr[:iid]
206
      subject_desc = "!#{subject_id}"
207 208 209 210 211 212 213 214 215 216 217
      subject_type = "merge request"
      title = format_title(subj_attr[:title])
    when "Snippet"
      subj_attr = HashWithIndifferentAccess.new(data[:snippet])
      subject_id = subj_attr[:id]
      subject_desc = "##{subject_id}"
      subject_type = "snippet"
      title = format_title(subj_attr[:title])
    end

    subject_html = "<a href=\"#{note_url}\">#{subject_type} #{subject_desc}</a>"
218
    message = "#{user_name} commented on #{subject_html} in #{project_link}: "
219 220 221 222 223
    message << title

    if note
      note = format_body(note)
      message << note
224 225 226 227 228
    end

    message
  end

229 230 231 232 233 234 235 236
  def create_build_message(data)
    ref_type = data[:tag] ? 'tag' : 'branch'
    ref = data[:ref]
    sha = data[:sha]
    user_name = data[:commit][:author_name]
    status = data[:commit][:status]
    duration = data[:commit][:duration]

237 238
    branch_link = "<a href=\"#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>"
    commit_link = "<a href=\"#{project_url}/commit/#{CGI.escape(sha)}/builds\">#{Commit.truncate_sha(sha)}</a>"
239 240 241 242

    "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
  end

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
  def project_name
    project.name_with_namespace.gsub(/\s/, '')
  end

  def project_url
    project.web_url
  end

  def project_link
    "<a href=\"#{project_url}\">#{project_name}</a>"
  end

  def is_update?(data)
    data[:object_attributes][:action] == 'update'
  end
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

  def humanized_status(status)
    case status
    when 'success'
      'passed'
    else
      status
    end
  end

  def should_build_be_notified?(data)
    case data[:commit][:status]
    when 'success'
      !notify_only_broken_builds?
    when 'failed'
      true
    else
      false
    end
  end
Dmitriy Zaporozhets committed
278
end